UnityGameProjectsCode / RelianceGame / AI Control / Enemy Scripts / EnemyDefendState.cs
EnemyDefendState.cs
Raw
using EnemyAIMachineTools;
using System.Collections;
using UnityEngine;
using UnityEngine.AI;

public class EnemyDefendState : EnemyState
{
    private static EnemyDefendState _instance; //only declared once

    private EnemyDefendState() //set instance to itself
    {
        if (_instance != null)
        {
            return;
        }

        _instance = this;
    }

    public static EnemyDefendState instance //creates the instance of the first state if it does not exist
    {
        get
        {
            if (_instance == null)
            {
                new EnemyDefendState();
            }

            return _instance;
        }
    }

    public override IEnumerator InState(EnemyAIMachine owner)
    {
        Vector3 point = MoveWaypoint(owner);
        float waitTime = 3f;
        float elapsedTime = 0f;

        while (owner.botMachine.currentState == EnemyDefendState.instance)
        {
            if (!owner.disabled)
            {
                if (Vector3.Angle(owner.transform.forward, point - owner.transform.position) < 15)
                {
                    owner.thisAgent.SetDestination(point); //set the bots destination to the generated point

                    if (Vector3.Distance(owner.gameObject.transform.position, point) <= 15) //if the bot gets within 5 units of a destination, stop and wait
                    {
                        owner.thisAgent.SetDestination(owner.gameObject.transform.position); //set destination to itself

                        elapsedTime += Time.deltaTime; //track time

                        if (elapsedTime >= waitTime) //if the elapsed time goes over the wait time, generate a new waypoint
                        {
                            elapsedTime = 0f;
                            point = MoveWaypoint(owner);
                        }
                    }
                }
                else
                    RotateBody(owner, point);

                if (owner.canSeeEnemy && owner.enemyObject != null) //if an enemy is found, go to the chase state
                {
                    owner.botMachine.ChangeState(EnemyChaseState.instance); //need a special chase and attack state so that the bot will return to defending
                    yield break;
                }
                else
                {
                    owner.canSeeEnemy = false;
                }
            }
            else
            {
                owner.thisAgent.SetDestination(owner.transform.position);
            }
            yield return null;
        }
    }

    public Vector3 MoveWaypoint(EnemyAIMachine _owner) //generate a position within the search radius
    {
        RaycastHit hit;
        NavMeshHit NH;

        Vector3 point = _owner.objective.transform.position + Random.insideUnitSphere * _owner.searchRadius; //create a point on the navmesh
        NavMesh.SamplePosition(point, out NH, _owner.searchRadius, NavMesh.AllAreas); //create a position to give to the NH var

        if (Physics.Raycast(_owner.lineOrigin.transform.position, NH.position - _owner.transform.position, out hit, Vector3.Distance(_owner.lineOrigin.transform.position, point))) //draw a ray from this bot to the point at the same length as the distance from the bot to the point
        {
            //if the ray hits any object, get a new point and redo the raycast until the cast is false
            do
            {
                point = _owner.objective.transform.position + Random.insideUnitSphere * _owner.searchRadius;
                NavMesh.SamplePosition(point, out NH, _owner.searchRadius, NavMesh.AllAreas);
            }
            while (Physics.Raycast(_owner.lineOrigin.transform.position, NH.position - _owner.transform.position, out hit, Vector3.Distance(_owner.lineOrigin.transform.position, point)));
        }

        //show rays from the bots position to the point
        Debug.DrawLine(_owner.gameObject.transform.position, NH.position, Color.cyan, 5);
        Debug.DrawRay(_owner.lineOrigin.transform.position, NH.position - _owner.transform.position, Color.magenta, 5);

        return NH.position;
    }

    private void RotateBody(EnemyAIMachine _owner, Vector3 navPoint) //called to have the bot rotate to face the waypoint before navigating to it
    {
        //declare variables that will be used to determine how to move the bot
        Quaternion targetRot = Quaternion.LookRotation(navPoint - _owner.transform.position);

        //rotate the bot over time to face the enemy
        _owner.transform.rotation = Quaternion.RotateTowards(_owner.transform.rotation, targetRot, Time.deltaTime * _owner.bodyRotateSpeed);

        //set the bots y euler angle so that it only moves on that transform
        _owner.transform.localEulerAngles = new Vector3(0, _owner.transform.localEulerAngles.y, 0);
    }

}