starfighter/MB_FYP/script/ai_fighter.cs
2025-04-18 02:07:51 +01:00

242 lines
6.7 KiB
C#

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<Texture2D>(spritePath);
LaserSpawn = GetNode<Node2D>("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();
}*/
}