AI will no longer target and attack player
Can anyone please help me fix my AI. Here's my script.
using System.Collections.Generic;
using System.Numerics;
using Controller;
using UnityEngine;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
public class EnemyController : SpaceshipController
{
protected AIShipState State;
protected Transform CurrentTarget;
protected Vector2 RoamingTarget;
protected CustomPlanet planetTarget;
Rigidbody2D rb;
public float ShipDetectionRadius = 400f;
public float PlanetDetectionRadius = 800f;
public LayerMask ShipLayers;
public LayerMask PlanetLayers;
public float targetOffset = 5f;
bool attemptingToCallSOS;
Vector2? temporaryPoint;
Vector2 desiredDirection;
Vector2 desiredVelocity;
public LayerMask CollisionCheckMask;
public float DetectionLength;
public float PointArrivalDistance;
public int NumberOfRays;
public float DetectionAngle;
public float ShootingDistance;
bool conqueredPlanet;
public float RoamSearchInterval;
private float roamSearchTimer;
public float MinimumRoamDistance;
public bool WillTargetPlanets;
public bool WillConquerNeutralPlanets;
public bool WillConquerOwnedPlanets;
public bool WillDestroyBuildings;
public bool AggressiveAgainstEnemies;
public bool WillRetreatWhenLosing;
public bool WillDefendOthers;
//public AIBehaviourWithPlanets BehaviourWithPlanets;
//public AIBehaviourWithSpaceships BehaviourWithSpaceships;
protected override void CustomStart()
{
CurrentTarget = null;
State = AIShipState.LookingForTarget;
rb = GetComponent<Rigidbody2D>();
Respawning.AddListener(OnRespawning);
PlanetConquered.AddListener(OnPlanetConquered);
}
private void OnPlanetConquered(string planetName)
{
conqueredPlanet = true;
}
private void OnRespawning()
{
State = AIShipState.LookingForTarget;
}
protected override void CustomUpdate()
{
if (State == AIShipState.LookingForTarget)
{
LookForTarget(true);
}
else if (State == AIShipState.Roaming && RoamSearchInterval > 0)
{
if (roamSearchTimer < RoamSearchInterval)
{
roamSearchTimer += Time.deltaTime;
}
else
{
roamSearchTimer = 0f;
LookForTarget(false);
}
}
if (attemptingToCallSOS)
{
attemptingToCallSOS = false;
//StopAccelerating();
CallSOSBeacon();
}
CheckAbility();
RandomCommunication();
}
public virtual void CheckAbility()
{
}
protected override void UpdatePlayerHit()
{
// @TODO check this area
uiDamage.SpawnNumber();
}
public override void CheckInput_Rotation()
{
switch (State)
{
case AIShipState.Roaming:
if (ChaseTarget(RoamingTarget, PointArrivalDistance, false))
{
State = AIShipState.LookingForTarget;
}
break;
case AIShipState.GoingToConquer:
var arrivalDistance = (myCollider.radius * planetTarget.ColliderRadius) * 2;
if (ChaseTarget(CurrentTarget.position, arrivalDistance, true))
{
if (planetTarget.CurrentBuildings > 0)
{
State = AIShipState.DestroyingBuildings;
}
else if ((planetTarget.Owner == Faction.Neutral && (WillConquerNeutralPlanets || HomePlanet == null)) || (planetTarget.Owner != Faction.Neutral && WillConquerOwnedPlanets))
{
State = AIShipState.AttemptingToLand;
}
else
{
State = AIShipState.LookingForTarget;
}
}
break;
case AIShipState.AttemptingToLand:
if (conqueringPlanet)
{
State = AIShipState.Conquering;
}
else
{
// var remainingDist = (Vector2)CurrentTarget.position - rb.position;
var landingDist = (myCollider.radius * planetTarget.ColliderRadius) * 2;
var remainDist = Vector2.Distance(CurrentTarget.position, transform.position);
// Debug.Log($"remain:{remainDist} land:{landingDist} {Vector2.Distance(CurrentTarget.position, rb.position)}", gameObject);
if (remainDist > landingDist)
{
State = AIShipState.GoingToConquer;
}
else
{
var targetDir = (CurrentTarget.position - transform.position);
var velocityDir = rb.velocity.normalized;
var newDir = CheckCollision(velocityDir, true);
if (newDir.HasValue)
{
temporaryPoint = rb.position + newDir.Value * (DetectionLength / 2);
desiredDirection = newDir.Value;
var angle = Vector2.SignedAngle(rb.velocity.normalized, desiredDirection);
if (angle < 90f && angle > -90f)
{
SetTargetDirection(desiredDirection.Rotate(angle));
}
else
{
SetTargetDirection(desiredDirection);
}
}
else
{
var temp = CheckCollision(targetDir, true);
desiredVelocity = targetDir.normalized * safeLandingSpeed;
desiredDirection = -targetDir.normalized;
var targetAngle = Vector2.SignedAngle(rb.velocity.normalized, targetDir.normalized);
var desiredDirectionAngle = Vector2.SignedAngle(rb.velocity.normalized, desiredDirection);
if (targetAngle < 90f && targetAngle > -90f)
{
SetTargetDirection(desiredDirection.Rotate(-targetAngle));
}
else
{
SetTargetDirection(desiredDirection);
}
}
}
}
break;
case AIShipState.Conquering:
if (!conqueringPlanet)
{
if (conqueredPlanet)
{
if (fuelPercentage < 0.5f || health / Stats.MaxHealth < 0.5f)
{
State = AIShipState.Refueling;
}
else
{
State = AIShipState.LookingForTarget;
}
conqueredPlanet = false;
}
else
{
State = AIShipState.AttemptingToLand;
}
}
break;
case AIShipState.GoingToRefuel:
break;
case AIShipState.Refueling:
if (fuel == Stats.MaxFuel && health == Stats.MaxHealth)
{
State = AIShipState.LookingForTarget;
}
if (!hasLanded)
{
State = AIShipState.LookingForTarget;
}
break;
case AIShipState.ChasingEnemyShip:
if (CurrentTarget == null)
{
State = AIShipState.LookingForTarget;
}
else
{
var targetDistance = (CurrentTarget.position - transform.position).magnitude;
if (targetDistance < ShipDetectionRadius)
{
// arrival distance 0 because we don't care about this and want it to always be false since it will just rotate around it
ChaseTarget(CurrentTarget.position, 0f, false, ShootingDistance / 2);
}
else
{
CurrentTarget = null;
State = AIShipState.LookingForTarget;
}
}
break;
case AIShipState.AvoidingCollision:
// Not required since the update to the new movement plan
break;
case AIShipState.DestroyingBuildings:
if (planetTarget.CurrentBuildings > 0)
{
ChaseTarget(CurrentTarget.position, 0f, false, ShootingDistance / 2);
}
else
{
if ((planetTarget.Owner == Faction.Neutral && (WillConquerNeutralPlanets || HomePlanet == null)) || (planetTarget.Owner != Faction.Neutral && WillConquerOwnedPlanets))
{
State = AIShipState.AttemptingToLand;
}
else
{
State = AIShipState.LookingForTarget;
}
}
break;
default:
break;
}
}
private Collider2D[] nearByShips = new Collider2D[2];
Transform CheckForNearbyEnemyShip()
{
//@TODO check change with OverlapNonAlloc
var detectedShips = Physics2D.OverlapCircleAll(transform.position, ShipDetectionRadius, ShipLayers);
// var totalFound = Physics2D.OverlapCircleNonAlloc(transform.position, ShipDetectionRadius, nearByShips, ShipLayers);
// if (totalFound == 0) return null;
foreach (var item in detectedShips)
{
if (item != null && item.gameObject.Equals(gameObject))
{
if (AggressiveAgainstEnemies)
{
if (IsEnemy(item.gameObject))
{
return item.transform;
}
}
else if (WillDefendOthers)
{
var ship = item.GetComponent<SpaceshipController>();
if (ship != null && ship.IsPrimaryAttacker)
{
return ship.Attacker;
}
}
}
}
return null;
}
CustomPlanet CheckForNearbyPlanet()
{
var detectedPlanets = Physics2D.OverlapCircleAll(transform.position, PlanetDetectionRadius, PlanetLayers);
var neutralPlanets = new List<CustomPlanet>();
var ownedPlanets = new List<CustomPlanet>();
foreach (var item in detectedPlanets)
{
var planet = item.GetComponent<CustomPlanet>();
if (planet != null && planet.Owner != Faction /* && planet.planetData.type == "Earth"*/)
{
if (HomePlanet == null && !planet.planetData.type.Equals("Earth"))
{
continue;
}
if (planet.Owner == Faction.Neutral)
{
neutralPlanets.Add(planet);
}
else
{
ownedPlanets.Add(planet);
}
}
}
if ((WillConquerNeutralPlanets || HomePlanet == null) && neutralPlanets.Count > 0)
{
return neutralPlanets[0];
}
if ((WillConquerOwnedPlanets || WillDestroyBuildings) && ownedPlanets.Count > 0)
{
return ownedPlanets[0];
}
return null;
}
bool FindEnemyShip()
{
var enemyShip = CheckForNearbyEnemyShip();
if (enemyShip != null)
{
CurrentTarget = enemyShip;
State = AIShipState.ChasingEnemyShip;
return true;
}
return false;
}
bool FindPlanetToConquer()
{
var planet = CheckForNearbyPlanet();
if (planet != null)
{
CurrentTarget = planet.transform;
planetTarget = planet;
State = AIShipState.GoingToConquer;
return true;
}
return false;
}
void SetNewRoamTarget()
{
var minX = 0f;
var maxX = 0f;
var minY = 0f;
var maxY = 0f;
var bounds = GameManager.Instance.GalaxyBounds;
minX = bounds.min.x - (transform.position.x - MinimumRoamDistance);
maxX = bounds.max.x - (transform.position.x + MinimumRoamDistance);
minY = bounds.min.y - (transform.position.y - MinimumRoamDistance);
maxY = bounds.max.y - (transform.position.y + MinimumRoamDistance);
var validPoint = false;
var point = Vector2.zero;
do
{
point.x = Random.Range(minX, maxX);
point.y = Random.Range(minY, maxY);
validPoint = !(Physics2D.OverlapCircle(point, myCollider.radius));
} while (!validPoint);
RoamingTarget = point;
State = AIShipState.Roaming;
}
protected virtual void LookForTarget(bool getNewRoamPosition)
{
if (AggressiveAgainstEnemies || WillDefendOthers)
{
var enemyShip = CheckForNearbyEnemyShip();
if (enemyShip != null)
{
// check if current enemy seeking Player
if (enemyShip.GetComponent<SpaceshipController>().Faction.Equals(Faction.Player))
{
AnnounceAudio.Play("Hostile ship attacking player", transform.position);
}
CurrentTarget = enemyShip;
State = AIShipState.ChasingEnemyShip;
return;
}
}
if (WillTargetPlanets || HomePlanet == null)
{
var planet = CheckForNearbyPlanet();
if (planet != null)
{
CurrentTarget = planet.transform;
planetTarget = planet;
State = AIShipState.GoingToConquer;
return;
}
}
//for (int i = 1; i <= 7; i++)
//{
//}
if (getNewRoamPosition)
{
var minX = 0f;
var maxX = 0f;
var minY = 0f;
var maxY = 0f;
var bounds = GameManager.Instance.GalaxyBounds;
minX = bounds.min.x; // - (transform.position.x - MinimumRoamDistance);
maxX = bounds.max.x; // - (transform.position.x + MinimumRoamDistance);
minY = bounds.min.y; // - (transform.position.y - MinimumRoamDistance);
maxY = bounds.max.y; // - (transform.position.y + MinimumRoamDistance);
var validPoint = false;
var point = Vector2.zero;
do
{
point.x = Random.Range(minX, maxX);
point.y = Random.Range(minY, maxY);
var distance = point - (Vector2) transform.position;
if (distance.magnitude >= MinimumRoamDistance)
{
validPoint = !(Physics2D.OverlapCircle(point, myCollider.radius));
}
else
{
validPoint = false;
}
} while (!validPoint);
RoamingTarget = point;
State = AIShipState.Roaming;
}
}
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, ShipDetectionRadius);
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(transform.position, PlanetDetectionRadius);
if (myCollider != null && planetTarget != null)
{
Gizmos.color = Color.green;
var arrivalDistance = (myCollider.radius * planetTarget.ColliderRadius) * 2;
Gizmos.DrawWireSphere(transform.position, arrivalDistance);
}
if (State == AIShipState.Roaming)
{
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, RoamingTarget);
}
}
private float nextCheck = 0f;
Vector2? CheckCollision(Vector2 direction, bool ignoreCurrentTarget)
{
if (nextCheck < Time.time) return null;
var halfAngle = DetectionAngle / 2;
var angleStep = DetectionAngle / (NumberOfRays - 1);
var currentAngle = -halfAngle;
for (int i = 0; i < NumberOfRays; i++)
{
var dir = direction.Rotate(
currentAngle
);
var hit = Physics2D.Raycast(transform.position, dir, DetectionLength, CollisionCheckMask);
if (hit)
{
if (ignoreCurrentTarget)
{
if (CurrentTarget.gameObject.Equals(hit.collider.gameObject))
{
if (currentAngle == 0f)
{
return (direction).Rotate(angleStep / 2);
}
else
{
return (direction).Rotate(-currentAngle);
}
}
}
else
{
if (currentAngle == 0f)
{
return (direction).Rotate(angleStep / 2);
}
else
{
return (direction).Rotate(-currentAngle);
}
}
}
currentAngle += angleStep;
}
nextCheck = Time.time + 0.02f;
return null;
}
/// <summary>
/// Checks the path for direction and collisions then sets the rotation accordingly. Returns true if it has reached <paramref name="arrivalDistance"/>.
/// </summary>
/// <param name="arrivalDistance">The offset distance from target at which point it counts as arrived.</param>
/// <param name="ignoreCurrentTarget">Whether to ignore collision detection with the target or not.</param>
/// <param name="evasionOffset">A value to override the length by which to offet the evasion direction. Used DetectionLength by default.</param>
/// <returns>Is it within <paramref name="arrivalDistance"/></returns>
bool ChaseTarget(Vector2 target, float arrivalDistance, bool ignoreCurrentTarget, float? evasionOffset = null)
{
if (!evasionOffset.HasValue)
{
evasionOffset = DetectionLength;
}
bool reachedArrivalDistance = false;
var velMag = rb.velocity.magnitude;
var targetRemainingDistance = target - (Vector2) transform.position;
var targetDirection = targetRemainingDistance.normalized;
if (temporaryPoint.HasValue)
{
var remainingDistance = temporaryPoint.Value - (Vector2) transform.position;
if (remainingDistance.magnitude < PointArrivalDistance)
{
var newDir = CheckCollision(targetDirection, ignoreCurrentTarget);
if (newDir.HasValue)
{
temporaryPoint = rb.position + newDir.Value * evasionOffset;
desiredDirection = newDir.Value;
}
else
{
temporaryPoint = null;
desiredDirection = targetDirection;
}
}
else
{
var newDir = CheckCollision(desiredDirection, ignoreCurrentTarget);
if (newDir.HasValue)
{
temporaryPoint = rb.position + newDir.Value * evasionOffset;
desiredDirection = newDir.Value;
}
else
{
desiredDirection = (temporaryPoint.Value - rb.position).normalized;
}
}
}
else
{
var remainingDistance = target - (Vector2) transform.position;
if (remainingDistance.magnitude > arrivalDistance)
{
var castDir = targetDirection;
var newDir = CheckCollision(castDir, ignoreCurrentTarget);
if (newDir.HasValue)
{
temporaryPoint = rb.position + newDir.Value * evasionOffset;
desiredDirection = newDir.Value;
}
else
{
desiredDirection = castDir;
}
}
else
{
reachedArrivalDistance = true;
}
}
var angle = Vector2.SignedAngle(rb.velocity.normalized, desiredDirection);
if (angle < 90f && angle > -90f)
{
SetTargetDirection(desiredDirection.Rotate(angle));
}
else
{
SetTargetDirection(desiredDirection);
}
return reachedArrivalDistance;
}
public override void CheckInput_Acceleration()
{
var dot = Vector2.Dot(rb.velocity.normalized, desiredDirection);
if (State == AIShipState.Roaming)
{
if (rb.velocity.magnitude < Stats.MaxSpeed || dot < 0.99f)
{
StartAccelerating();
}
else
{
StopAccelerating();
}
}
else if (State == AIShipState.GoingToConquer)
{
var dist = (CurrentTarget.position - transform.position).magnitude;
var dotModifier = 0f;
var maxDotModifier = 0.3f;
var speedModifier = 1f;
var maxSpeedModifier = 0.5f;
if (dist < PlanetDetectionRadius)
{
var diff = PlanetDetectionRadius - dist;
dotModifier = diff / PlanetDetectionRadius * maxDotModifier;
speedModifier -= diff / PlanetDetectionRadius * maxSpeedModifier;
}
if (rb.velocity.magnitude < Stats.MaxSpeed * speedModifier || dot < 0.99f - dotModifier)
{
StartAccelerating();
}
else
{
StopAccelerating();
}
}
else if (State == AIShipState.ChasingEnemyShip)
{
if (rb.velocity.magnitude < Stats.MaxSpeed || dot < 0.99f)
{
StartAccelerating();
}
else
{
StopAccelerating();
}
}
else if (State == AIShipState.AttemptingToLand)
{
var dot2 = Vector2.Dot(rb.velocity.normalized, desiredVelocity.normalized);
var dist = (CurrentTarget.position - transform.position).magnitude;
var dotModifier = 0f;
var maxDotModifier = 0.3f;
if (dist < PlanetDetectionRadius)
{
var diff = PlanetDetectionRadius - dist;
dotModifier = diff / PlanetDetectionRadius * maxDotModifier;
}
if ((rb.velocity.magnitude > safeLandingSpeed - 1f && dot < -0.9f + dotModifier) || (dot2 < 0.9f))
{
StartAccelerating();
}
else
{
StopAccelerating();
}
}
else if (State == AIShipState.Conquering || State == AIShipState.Refueling)
{
StopAccelerating();
}
else if (dot < 1f)
{
StartAccelerating();
}
else
{
StopAccelerating();
}
}
public override void CheckInput_Shooting()
{
if (
(State == AIShipState.ChasingEnemyShip && CurrentTarget != null)
||
(State == AIShipState.DestroyingBuildings && planetTarget != null && planetTarget.CurrentBuildings > 0)
)
{
Vector3 forward = transform.up;
Vector3 toOther = CurrentTarget.position - transform.position;
var dot = Vector3.Dot(forward, toOther.normalized);
var distance = toOther.magnitude;
if (dot > .995f && distance < ShootingDistance)
{
//Debug.Log("Start Shoot");
StartShooting();
}
else
{
//Debug.Log("Stop Shoot");
StopShooting();
}
}
else
{
StopShooting();
}
}
private float timer = 0f;
void RandomCommunication()
{
timer += Time.deltaTime;
if (timer < AnnounceAudio.master.RandomCommunicationWait)
return;
timer = 0f; // reset timer
if (Faction.Equals(Faction.TheBandOfBarbell))
{
AnnounceAudio.Play("The Band Of Barbell Random Chat", transform.position);
}
else if (Faction.Equals(Faction.SpeedDemons))
{
AnnounceAudio.Play("Speed Demons Random Chat", transform.position);
}
}
protected override void UpdateHealthDisplay()
{
}
protected override void UpdateFuelDisplay()
{
}
protected override void SetCanCallSOS(bool canCall)
{
attemptingToCallSOS = canCall;
}
}
Comment
Your answer
Follow this Question
Related Questions
How to make enemy follow/find a certain object that is not the player? 0 Answers
Error CS0118 `EnemyAI.myTransform' is a `field' but a `type' was expected 1 Answer
My enemies' health wont go down 0 Answers
Enemy AI: Stop distance 0 Answers
Enemies fly through fast to players (through wall) and fly again 0 Answers