extends Area2D const DAMAGE_POPUP_SCENE := preload("res://scenes/game/damage_popup.tscn") const IMPACT_EFFECT_SCENE := preload("res://scenes/game/impact_effect.tscn") var direction := Vector2.UP var projectile_speed := 300.0 var damage := 8.0 var max_range := 1000.0 var _distance_travelled := 0.0 var _impact_handled := false func _ready() -> void: body_entered.connect(_on_body_entered) func configure(start_position: Vector2, travel_direction: Vector2, projectile_damage: float) -> void: global_position = start_position direction = travel_direction.normalized() damage = projectile_damage rotation = direction.angle() func _physics_process(delta: float) -> void: var step := projectile_speed * delta var next_position := global_position + direction * step var query := PhysicsRayQueryParameters2D.create(global_position, next_position, collision_mask, [get_rid()]) var hit := get_world_2d().direct_space_state.intersect_ray(query) var exclusions: Array[RID] = [get_rid()] hit = preload("res://scripts/game/shield_intersections.gd").intercept(hit,global_position,next_position,collision_mask,exclusions,get_tree()) if not hit.is_empty(): global_position = hit["position"] _hit_target(hit.get("collider")) return global_position = next_position _distance_travelled += step if _distance_travelled >= max_range: queue_free() func _draw() -> void: draw_circle(Vector2.ZERO, 6.0, Color(1.0, 0.24, 0.32, 0.98)) draw_circle(Vector2.ZERO, 3.0, Color(1.0, 0.82, 0.7, 1.0)) func _on_body_entered(body: Node2D) -> void: _hit_target(body) func _hit_target(target: Variant) -> void: if _impact_handled: return _impact_handled = true var effect := IMPACT_EFFECT_SCENE.instantiate() as Node2D effect.global_position = global_position get_parent().add_child(effect) effect.call("configure", false, Color(1.0, 0.32, 0.38)) effect.call("configure_contact",DamageTypes.Type.ENERGY,direction) if target is Node and target.has_method("take_damage") and not target.is_in_group("asteroids"): preload("res://scripts/game/combat_vfx.gd").mark_hit(target,global_position,direction) if target is CharacterBody2D: target.call("take_damage", damage, false, DamageTypes.Type.ENERGY) else: target.call("take_damage", damage) queue_free()