using Godot; using System; public partial class ai_fighter : ship { [Export] public float AggroRange = 500f; [Export] public float FireCooldown = 2f; [Export] public int ScorePayout = 50; [Export] public float EngageDistance = 300f; //retreat logic private float previousDistance = 0f; private float stuckTime = 0f; private const float stuckThreshold = 0.5f; // how many seconds to count as “stuck” private const float distanceTolerance = 5f; // how little the distance must change private Node2D currentTarget; private float fireTimer = 0f; public override void _Ready() { SetShipStats(); SetupVisual(); Sprite.Texture = GD.Load(spritePath); LaserSpawn = GetNode("LaserSpawn"); } public override void _PhysicsProcess(double delta) { UpdateMovement(delta); GD.Print(Name, ": MainSpeed = ", MainSpeed, " Velocity = ", Velocity.Length()); } // SETUP private void SetupAI() { } // COMBAT private void FireWeapons() { } // TARGETING private Node2D FindClosestTarget() { Node2D closest = null; float closestDistance = Mathf.Inf; Node shipParent = null; if (faction == ShipFaction.FRIENDLY) { shipParent = GetTree().Root.GetNode("Game/Ships/Enemy"); } else if (faction == ShipFaction.ENEMY || faction == ShipFaction.ACE) { shipParent = GetTree().Root.GetNode("Game/Ships/Friendly"); } if (shipParent == null) { GD.Print("No shipParent found"); return null; } foreach (Node node in shipParent.GetChildren()) { if (node is ship target && target.Health > 0) { float dist = GlobalPosition.DistanceTo(target.GlobalPosition); if (dist < closestDistance) { closest = target; closestDistance = dist; } } } return closest; } private bool EnsureTarget() { if (currentTarget == null || !IsInstanceValid(currentTarget)) { currentTarget = FindClosestTarget(); return false; } return true; } private void UpdateDistanceTracking(float distance) { if (MathF.Abs(distance - previousDistance) < distanceTolerance) { stuckTime += (float)GetProcessDeltaTime(); } else { stuckTime = 0f; } previousDistance = distance; } private void HandleThrust(Vector2 direction, float angleDiff, float distance) { float retreatThreshold = EngageDistance * 0.75f; if (Mathf.Abs(angleDiff) < 1f && Velocity.Length() < MaxSpeed - MainSpeed) { if (distance > EngageDistance) { Velocity += -Transform.Y * MainSpeed; } else if (distance < retreatThreshold) { if (stuckTime > stuckThreshold) { Vector2 away = (GlobalPosition - currentTarget.GlobalPosition).Normalized(); Velocity += away * MainSpeed; } else { Velocity += Transform.X * StrafeSpeed; } } } } private void RotateToTarget(Vector2 direction, double delta) { float targetAngle = direction.Angle() + Mathf.Pi / 2; float angleDiff = Mathf.AngleDifference(Rotation, targetAngle); Rotation += Mathf.Clamp(angleDiff, -RotationSpeed * (float)delta, RotationSpeed * (float)delta); } private void UpdateMovement(double delta) { if (!EnsureTarget()) { return; } Vector2 direction = (currentTarget.GlobalPosition - GlobalPosition).Normalized(); float angleToTarget = direction.Angle() + MathF.PI / 2; float angleDiff = Mathf.AngleDifference(Rotation, angleToTarget); float distance = GlobalPosition.DistanceTo(currentTarget.GlobalPosition); UpdateDistanceTracking(distance); HandleThrust(direction, angleDiff, distance); RotateToTarget(direction, delta); Velocity = Velocity.MoveToward(Vector2.Zero, 2.5f); //2.5f FA value (on for AI) Velocity = Velocity.LimitLength(MaxSpeed); MoveAndSlide(); } /*private void UpdateMovement(double delta) { if (currentTarget == null || !IsInstanceValid(currentTarget)) { currentTarget = FindClosestTarget(); return; } Vector2 direction = (currentTarget.GlobalPosition - GlobalPosition).Normalized(); float distance = GlobalPosition.DistanceTo(currentTarget.GlobalPosition); float retreatThreshold = EngageDistance * 0.75f; //Velocity += direction * MainSpeed; float angleToTarget = direction.Angle() + Mathf.Pi / 2; float angleDiff = Mathf.AngleDifference(Rotation, angleToTarget); float currentDistance = GlobalPosition.DistanceTo(currentTarget.GlobalPosition); if (Mathf.Abs(currentDistance - previousDistance) < distanceTolerance) stuckTime += (float)delta; else stuckTime = 0f; previousDistance = currentDistance; //GD.Print("angleDiff: ", Mathf.RadToDeg(angleDiff)); //GD.Print("rotation: ", Mathf.RadToDeg(Rotation), " target: ", Mathf.RadToDeg(angleToTarget)); if (Mathf.Abs(angleDiff) < 1f && Velocity.Length() < MaxSpeed - MainSpeed) { if (distance > EngageDistance) { Velocity += -Transform.Y * MainSpeed; } else if (distance < retreatThreshold) { if (stuckTime > stuckThreshold){ Velocity += Transform.Y * MainSpeed; } else { Velocity += Transform.X * StrafeSpeed; } //Velocity += Transform.Y * MainSpeed; //Velocity += Transform.X * StrafeSpeed; } } Velocity = Velocity.MoveToward(Vector2.Zero, 2.5f); //GD.Print(MainSpeed); //GD.Print(Velocity); //Rotation = direction.Angle() + Mathf.Pi / 2; // Keeps ship pointing right way angleDiff = Mathf.AngleDifference(Rotation, direction.Angle() + Mathf.Pi / 2); Rotation += Mathf.Clamp(angleDiff, -RotationSpeed * (float)delta, RotationSpeed * (float)delta); Velocity.LimitLength(MaxSpeed); MoveAndSlide(); }*/ }