extends Area2D var direction := Vector2.UP var projectile_speed := 600.0 var damage := 1.0 var max_range := 800.0 var weapon_kind := ItemDefinition.WeaponKind.PLASMA var _distance_travelled := 0.0 var _already_hit: Dictionary = {} func _ready() -> void: body_entered.connect(_on_body_entered) area_entered.connect(_on_area_entered) rotation = direction.angle() func configure( start_position: Vector2, travel_direction: Vector2, kind: int, speed: float, projectile_damage: float, projectile_range: float ) -> void: global_position = start_position direction = travel_direction.normalized() weapon_kind = kind projectile_speed = speed damage = projectile_damage max_range = projectile_range func _physics_process(delta: float) -> void: var step := projectile_speed * delta var previous_position := global_position var next_position := previous_position + direction * step var query := PhysicsRayQueryParameters2D.create( previous_position, next_position, collision_mask, [get_rid()] ) var result := get_world_2d().direct_space_state.intersect_ray(query) if not result.is_empty(): global_position = result["position"] _hit_target(result.get("collider")) return global_position = next_position _distance_travelled += step if _distance_travelled >= max_range: queue_free() func _draw() -> void: match weapon_kind: ItemDefinition.WeaponKind.PLASMA: draw_circle(Vector2.ZERO, 6.0, Color(0.3, 0.85, 1.0, 0.95)) draw_circle(Vector2.ZERO, 3.0, Color(0.85, 0.98, 1.0, 1.0)) ItemDefinition.WeaponKind.MACHINE_GUN: draw_rect(Rect2(-7.0, -2.0, 14.0, 4.0), Color(1.0, 0.82, 0.38, 1.0)) ItemDefinition.WeaponKind.MISSILE: draw_colored_polygon(PackedVector2Array([ Vector2(10, 0), Vector2(-7, -4), Vector2(-4, 0), Vector2(-7, 4), ]), Color(1.0, 0.42, 0.2, 1.0)) func _on_body_entered(body: Node2D) -> void: _hit_target(body) func _on_area_entered(area: Area2D) -> void: _hit_target(area) func _hit_target(target: Node) -> void: if weapon_kind == ItemDefinition.WeaponKind.MISSILE: _explode_at_target(target) else: _apply_damage_once(target) queue_free() func _explode_at_target(impact_target: Node) -> void: _apply_damage_once(impact_target) var explosion_shape := CircleShape2D.new() explosion_shape.radius = 120.0 var query := PhysicsShapeQueryParameters2D.new() query.shape = explosion_shape query.transform = Transform2D(0.0, global_position) query.collision_mask = 4 # Enemy physics layer 3. for result in get_world_2d().direct_space_state.intersect_shape(query, 32): _apply_damage_once(result.get("collider")) func _apply_damage_once(target: Variant) -> void: if not (target is Node): return var instance_id: int = target.get_instance_id() if _already_hit.has(instance_id): return _already_hit[instance_id] = true if target.has_method("take_damage"): target.call("take_damage", damage)