class_name Boss extends EnemyBase ## 关底 Boss:四发重型轰炸机。 ## 进场悬停后左右巡逻;弹幕双模式交替(瞄准连发 / 扇形散布), ## 半血进入狂暴阶段(弹速、频率、弹幕密度提升)。 ## 死亡时爆炸链 + 震屏 + 清除全场敌弹。 const TEX := preload("res://assets/svg/boss_plane.svg") const CENTER_X := 270.0 const ENTER_Y := 150.0 const ENTER_SPEED := 100.0 const PATROL_AMP := 145.0 const MUZZLE := Vector2(0.0, 55.0) var difficulty := 1.0 var max_hp := 120 var _t := 0.0 var _entered := false var _pattern_index := 0 var _pattern_timer := 1.4 var _burst_left := 0 var _burst_tick := 0.0 func setup(p_difficulty: float) -> void: difficulty = p_difficulty hp = int(60.0 + 60.0 * difficulty) max_hp = hp score_value = 5000 drops_powerup = true hit_radius = 62.0 position = Vector2(CENTER_X, -120.0) func _ready() -> void: collision_layer = 4 collision_mask = 0 var sprite := Sprite2D.new() sprite.texture = TEX add_child(sprite) var shape := CollisionShape2D.new() var rect := RectangleShape2D.new() rect.size = Vector2(190.0, 84.0) shape.shape = rect add_child(shape) func _process(delta: float) -> void: if dead: return if not _entered: position.y += ENTER_SPEED * delta if position.y >= ENTER_Y: position.y = ENTER_Y _entered = true return _t += delta * (1.25 if _in_phase2() else 1.0) position.x = CENTER_X + sin(_t * 0.55) * PATROL_AMP position.y = ENTER_Y + sin(_t * 1.6) * 16.0 if _burst_left > 0: _burst_tick -= delta if _burst_tick <= 0.0: _burst_tick = 0.14 _burst_left -= 1 _fire_bullet(_aim_direction() * _bullet_speed(), MUZZLE) else: _pattern_timer -= delta if _pattern_timer <= 0.0: _fire_pattern() func _in_phase2() -> bool: return hp <= max_hp / 2.0 func _bullet_speed() -> float: return (235.0 + 40.0 * difficulty) * (1.12 if _in_phase2() else 1.0) func _fire_pattern() -> void: var phase2 := _in_phase2() if _pattern_index % 2 == 0: # 瞄准连发 _burst_left = 5 if phase2 else 3 _burst_tick = 0.0 _pattern_timer = 1.5 if phase2 else 2.0 else: # 扇形散布 var count := 8 if phase2 else 5 var spread := 50.0 if phase2 else 36.0 var speed := _bullet_speed() for i in count: var angle := deg_to_rad(-spread + spread * 2.0 * float(i) / float(count - 1)) _fire_bullet(Vector2.DOWN.rotated(angle) * speed, MUZZLE) _pattern_timer = 1.7 if phase2 else 2.2 _pattern_index += 1 func _die() -> void: _spawn_drop(Powerup.Kind.POWER) var game := get_tree().get_first_node_in_group("game") as Game if game != null and is_instance_valid(game): game.add_score(score_value) game.add_bomb() game.clear_enemy_bullets() game.shake(9.0) for i in 8: var offset := Vector2(randf_range(-92.0, 92.0), randf_range(-56.0, 56.0)) if game != null and is_instance_valid(game): game.spawn_explosion(global_position + offset, randf_range(1.3, 2.0)) await get_tree().create_timer(0.12).timeout if game != null and is_instance_valid(game): game.spawn_explosion(global_position, 3.0) await get_tree().create_timer(0.3).timeout queue_free()