class_name EnemyRangedWeaponComponent extends Node # Same shape as VesselWeaponComponent, mirrored for an enemy: fires an # EnemyProjectile at the nearest player ship's CURRENT position, not led, # so a moving ship can dodge it. var capability_id: String = "ranged_weapon" @export var fire_range: float = 700.0 @export var fire_cooldown: float = 2.2 @export var projectile_speed: float = 260.0 @export var damage: int = 1 var fire_timer: float = 0.0 var projectile_scene: PackedScene = preload("res://EnemyProjectile.tscn") func tick(delta: float) -> void: fire_timer -= delta if fire_timer > 0.0: return var enemy: Node2D = get_parent() var target: Node2D = _nearest_ship_in_range(enemy) if target == null: fire_timer = 0.25 return var projectile: Area2D = projectile_scene.instantiate() # global_position: the projectile is reparented to root, a different # node than the enemy's own (possibly nested) parent, so local # position would be wrong the moment an enemy isn't a direct root # child - exactly the case #44 introduced (planet-surface hosting). projectile.position = enemy.global_position projectile.damage = damage projectile.speed = projectile_speed enemy.get_tree().root.add_child(projectile) projectile.launch(target.global_position - enemy.global_position) fire_timer = fire_cooldown func _nearest_ship_in_range(enemy: Node2D) -> Node2D: var fleet: Node2D = get_tree().get_first_node_in_group("player_fleet") if fleet == null: return null var nearest: Node2D = null var best_distance: float = fire_range for ship in fleet.ships: if not is_instance_valid(ship): continue var distance: float = enemy.global_position.distance_to(ship.global_position) if distance <= best_distance: best_distance = distance nearest = ship return nearest