using Godot; namespace AceFieldNewHorizon.Scripts.Entities; public partial class Bullet : Area2D { [Export] public float Speed = 400.0f; [Export] public int Damage = 10; [Export] public float MaxDistance = 1000.0f; private Vector2 _direction = Vector2.Right; private Vector2 _startPosition; private float _distanceTraveled = 0f; private bool _hasHit = false; private uint _ignoreCollisionLayer = 0; // Layer to ignore (will be set by turret) public void Initialize(Vector2 direction, Vector2 position, float rotation, uint ignoreLayer = 0) { _direction = direction.Normalized(); Position = position; Rotation = rotation; _startPosition = position; _ignoreCollisionLayer = ignoreLayer; // Connect the area entered signal BodyEntered += OnBodyEntered; AreaEntered += OnAreaEntered; } public override void _PhysicsProcess(double delta) { if (_hasHit) return; // Move the bullet var movement = _direction * Speed * (float)delta; Position += movement; _distanceTraveled += movement.Length(); // Check if bullet has traveled max distance if (_distanceTraveled >= MaxDistance) { QueueFree(); return; } } private void OnBodyEntered(Node2D body) { HandleCollision(body); } private void OnAreaEntered(Area2D area) { HandleCollision(area); } private void HandleCollision(Node2D node) { if (_hasHit) return; // Skip collision if it's on the ignore layer if (node is PhysicsBody2D physicsBody && (physicsBody.CollisionLayer & _ignoreCollisionLayer) != 0) { return; } _hasHit = true; // If we hit an enemy, deal damage if (node is Enemy enemy) { // Get the global position where the bullet hit var hitPosition = GlobalPosition; enemy.TakeDamage(Damage, hitPosition); } // Optional: Add hit effect here // CreateHitEffect(); // Remove the bullet QueueFree(); } private void CreateHitEffect() { // You can add a hit effect here if desired // For example, a small explosion or impact sprite } public override void _ExitTree() { // Clean up signal connections BodyEntered -= OnBodyEntered; AreaEntered -= OnAreaEntered; } }