class_name LaserBeam extends Node2D ## 直线激光束:从所在位置垂直向上延伸,被第一个命中的敌人截断, ## 对其造成持续伤害(dps)。视觉为核心线 + 外发光双层 Line2D。 var dps := 10.0 var width := 5.0 var color := Color(0.55, 0.9, 1.0) var active := false var _core: Line2D var _glow: Line2D var _acc := 0.0 var _t := 0.0 func _ready() -> void: z_index = 5 _glow = Line2D.new() _glow.width = width * 2.8 _glow.default_color = Color(color, 0.28) _glow.points = [Vector2.ZERO, Vector2(0.0, -10.0)] add_child(_glow) _core = Line2D.new() _core.width = width _core.default_color = color _core.points = [Vector2.ZERO, Vector2(0.0, -10.0)] add_child(_core) visible = false ## 从自身祖先中解析所属游戏的敌容器(避免多实例时全局组查找拿错容器) func _get_enemies_container() -> Node2D: var node := get_parent() while node != null: var candidate := node.get_node_or_null("Enemies") if candidate != null: return candidate as Node2D node = node.get_parent() return null func _process(delta: float) -> void: if not active: if visible: visible = false return visible = true _t += delta var muzzle := global_position var hit_y := -40.0 var target: EnemyBase = null var container := _get_enemies_container() if container != null: for enemy in container.get_children(): if enemy is EnemyBase and not (enemy as EnemyBase).dead: var e := enemy as EnemyBase if absf(e.global_position.x - muzzle.x) < e.hit_radius + width * 0.5: # 光束向上:命中敌人底缘;若炮口已进入敌人范围则从炮口起算 var hy := minf(muzzle.y, e.global_position.y + e.hit_radius) if hy >= hit_y: hit_y = hy target = e var length := maxf(muzzle.y - hit_y, 0.0) var pulse := 1.0 + 0.1 * sin(_t * 42.0) _core.width = width * pulse _glow.width = width * 2.8 * pulse _core.points = [Vector2.ZERO, Vector2(0.0, -length)] _glow.points = [Vector2.ZERO, Vector2(0.0, -length)] if target != null and is_instance_valid(target): _acc += dps * delta if _acc >= 1.0: var whole := int(_acc) _acc -= float(whole) target.apply_damage(whole)