UnityGameProjectsCode / RelianceGame / AI Control / Friendly Scripts / AIMachine.cs
AIMachine.cs
Raw
using AIMachineTools;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AI;

public class AIMachine : MonoBehaviour
{
    [HideInInspector]
    public DisplayLog logD;
    [HideInInspector]
    public GameManager gameManager;
    [HideInInspector]
    public BotStats botStats;
    [HideInInspector]
    public Health enemyHealth;
    [HideInInspector]
    public NavMeshAgent thisAgent;
    [HideInInspector]
    public BotStateMachine botMachine;
    [HideInInspector]
    public LineRenderer laserLine;
    [HideInInspector]
    public AudioSource audioS;
    [HideInInspector]
    public Animator animator;
    [HideInInspector]
    public SoundManager soundMgr;

    public string displayName;
    public int followDistance;
    public int healDistance;
    public int baseSearchRadius; //base radius without changes
    private int modifiedSearchRadius; //change from base radius via bot stats
    private int currentSearchRadius; //actual radius in use
    public int sentryRadiusIncrease; //amount radius is increased when in sentry state
    public int baseReinforcementRadius;
    public int attackDistance;
    public int retreatRadius;
    private int reinforcementRadius;
    public int hitChance;
    public int critChance;
    public int heavyHitChance;
    public int heavyHitModifier;
    public float fireRate;
    public float healRate;
    public float markerDistance;
    public float moveToDistance;
    public int turretRotateSpeed;
    public int barrelMoveSpeed;
    public int bodyRotateSpeed;
    public Transform lineOrigin;
    public Transform barrelEnd;
    public Transform turretPos;
    public Transform barrelPos;
    public Vector3 contactPoint;
    public Vector3 targetWaypoint;
    public Vector3 startingPos;
    public Vector3 agentVelocity;
    public GameObject marker;
    public GameObject grenadePrefab;
    public GameObject areaHealPrefab;
    public GameObject enemyObject;
    public GameObject barrelHitTarget;
    public GameObject playerObject;
    public GameObject followTarget;
    public GameObject markerCopy;
    public GameObject impactObject;
    public bool canSeeEnemy;
    public bool onTarget = false;
    public bool supportBuff = false;
    public bool removingEnemy = false;
    public bool disabled = false;
    public ParticleSystem laserParticles;
    public Light barrelLight;
    public List<GameObject> friendlyBots;
    public List<GameObject> additionalEnemies;
    public List<GameObject> nearbyFriendlies;
    public List<GameObject> objectives;
    public List<Material> lasers = new List<Material>();

    private float timeToScan = 0;

    public int ModifiedSearchRadius { get => modifiedSearchRadius; set => modifiedSearchRadius = value; }
    public int ReinforcementRadius { get => reinforcementRadius; set => reinforcementRadius = value; }

    void Start()
    {
        foreach (GameObject bot in GameObject.FindGameObjectsWithTag("Target"))
        {
            if (bot.GetComponent<Health>() && bot.GetComponent<AIMachine>())
                friendlyBots.Add(bot);
        }
        friendlyBots.Remove(this.gameObject);
        friendlyBots.Remove(GameObject.Find("PlayerSphere"));

        foreach (GameObject obj in GameObject.FindGameObjectsWithTag("Cap Area"))
        {
            objectives.Add(obj);
        }

        foreach (GameObject obj in GameObject.FindGameObjectsWithTag("Terminal"))
        {
            objectives.Add(obj);
        }

        botMachine = GetComponent<BotStateMachine>();
        thisAgent = GetComponent<NavMeshAgent>();
        botStats = GetComponent<BotStats>();
        gameManager = GameObject.Find("Persistent Object").GetComponent<GameManager>();
        soundMgr = GameObject.Find("Persistent Object").GetComponent<SoundManager>();
        logD = GameObject.Find("RunningUI/Text Log/Log Panel/Content").GetComponent<DisplayLog>();
        playerObject = GameObject.Find("PlayerSphere");
        laserLine = GetComponent<LineRenderer>();
        laserLine.enabled = false;
        audioS = GetComponent<AudioSource>();
        startingPos = transform.position;
        barrelLight = barrelEnd.gameObject.GetComponent<Light>();
        animator = GetComponent<Animator>();
        barrelLight.enabled = false;

        if (gameObject.name.Contains("Blue"))
            displayName = "Blue Bot";
        if (gameObject.name.Contains("Green"))
            displayName = "Green Bot";
        if (gameObject.name.Contains("Orange"))
            displayName = "Orange Bot";
    }

    void Update()
    {
        if (botMachine.baseStateName.Contains("Sentry") && currentSearchRadius == modifiedSearchRadius)
            currentSearchRadius = modifiedSearchRadius + sentryRadiusIncrease;

        else if (!botMachine.baseStateName.Contains("Sentry") && currentSearchRadius != modifiedSearchRadius)
            currentSearchRadius = modifiedSearchRadius;


        if (enemyObject != null)
            if (enemyObject.activeSelf == false)
            {
                enemyObject = null;
                Debug.Log(displayName + ": Enemy object is not active, removing.");
            }

        agentVelocity = thisAgent.velocity;

        timeToScan += Time.deltaTime;

        if (timeToScan >= 1.0f)
        {
            DrawSearchRays();

            DrawBarrelRay();

            timeToScan = 0.0f;
        }

        KeyCommands();
    }

    private void KeyCommands()
    {
        if (Input.GetButtonDown("AI Idle Mode"))
        {
            botMachine.ChangeState(IdleState.instance);
        }

        if (Input.GetButtonDown("AI Follow Mode"))
        {
            followTarget = playerObject;
            botMachine.ChangeState(FollowState.instance);
        }

        if (Input.GetButtonDown("AI Search Mode"))
        {
            botMachine.ChangeState(SearchState.instance);
        }

        if (Input.GetButtonDown("AI Sentry Mode"))
        {
            botMachine.ChangeState(SentryState.instance);
        }

        if (Input.GetButtonDown("AI Move To Command"))
        {
            botMachine.ChangeState(MoveToState.instance);
        }
    }

    private void DrawSearchRays()
    {
        Quaternion startingAngle = Quaternion.AngleAxis(-60, Vector3.up);
        Quaternion stepAngle = Quaternion.AngleAxis(5, Vector3.up);

        RaycastHit hit;
        var angle = transform.rotation * startingAngle;
        var direction = angle * Vector3.forward;

        for (var i = 0; i < 72; i++)
        {
            if (Physics.Raycast(lineOrigin.transform.position, direction, out hit, currentSearchRadius))
            {
                if (hit.collider.gameObject.CompareTag("Enemy"))
                {
                    Debug.DrawRay(lineOrigin.transform.position, direction * hit.distance, Color.red);
                    canSeeEnemy = true;
                    additionalEnemies.Add(hit.collider.gameObject);
                    additionalEnemies = additionalEnemies.Distinct().ToList();

                    SetTarget();

                    break;
                }
                else if (hit.collider.gameObject.CompareTag("EnemyStructure"))
                {
                    Debug.DrawRay(lineOrigin.transform.position, direction * hit.distance, Color.green);
                    canSeeEnemy = true;
                    additionalEnemies.Add(hit.collider.gameObject);
                    additionalEnemies = additionalEnemies.Distinct().ToList();

                    SetTarget();

                    break;
                }
                else if (hit.collider.gameObject.CompareTag("Target"))
                {
                    Debug.DrawRay(lineOrigin.transform.position, direction * hit.distance, Color.blue);
                    nearbyFriendlies.Add(hit.collider.gameObject);
                    nearbyFriendlies = nearbyFriendlies.Distinct().ToList();
                }
                else
                {
                    Debug.DrawRay(lineOrigin.transform.position, direction * hit.distance, Color.yellow);
                    canSeeEnemy = false;
                }
            }
            else
            {
                Debug.DrawRay(lineOrigin.transform.position, direction * currentSearchRadius, Color.white);
                canSeeEnemy = false;
            }

            direction = stepAngle * direction;
        }

        for (int i = 0; i < additionalEnemies.Count; i++)
        {
            if (Vector3.Distance(transform.position, additionalEnemies[i].transform.position) > currentSearchRadius || additionalEnemies[i].activeSelf == false)
                additionalEnemies.RemoveAt(i);
        }

        for (int i = 0; i < nearbyFriendlies.Count; i++)
        {
            if (Vector3.Distance(transform.position, nearbyFriendlies[i].transform.position) > currentSearchRadius || nearbyFriendlies[i].activeSelf == false)
                nearbyFriendlies.RemoveAt(i);
        }
    }

    public void DrawBarrelRay()
    {
        RaycastHit hit;

        if (Physics.Raycast(barrelEnd.transform.position, barrelEnd.forward, out hit, attackDistance + 10f))
        {
            if (hit.collider.gameObject.CompareTag("Enemy"))
            {
                Debug.DrawRay(barrelEnd.transform.position, barrelEnd.forward * hit.distance, Color.red);
                barrelHitTarget = hit.collider.gameObject;
                contactPoint = hit.point;
                onTarget = true;
            }
            else if (hit.collider.gameObject.CompareTag("Target"))
            {
                Debug.DrawRay(barrelEnd.transform.position, barrelEnd.forward * hit.distance, Color.blue);
                barrelHitTarget = hit.collider.gameObject;
                contactPoint = hit.point;
                onTarget = true;
            }
            else if (hit.collider.gameObject.CompareTag("EnemyStructure"))
            {
                Debug.DrawRay(barrelEnd.transform.position, barrelEnd.forward * hit.distance, Color.green);
                barrelHitTarget = hit.collider.gameObject;
                contactPoint = hit.point;
                onTarget = true;
            }
            else
            {
                Debug.DrawRay(barrelEnd.transform.position, barrelEnd.forward * hit.distance, Color.yellow);
                barrelHitTarget = null;
                onTarget = false;
            }
        }
        else
        {
            Debug.DrawRay(barrelEnd.transform.position, barrelEnd.forward * attackDistance);
            barrelHitTarget = null;
            onTarget = false;
        }
    }

    public void SetTarget()
    {
        float minDistance = float.MaxValue;
        GameObject targetBot = null;

        if (additionalEnemies.Count > 0)
        {
            for (int i = 0; i < additionalEnemies.Count; i++)
            {
                if (additionalEnemies[i].activeSelf == false)
                    additionalEnemies.Remove(additionalEnemies[i]);
            }

            if (additionalEnemies.Count == 1)
            {
                enemyObject = additionalEnemies[0];
                enemyHealth = enemyObject.GetComponent<Health>();
            }
            else if (additionalEnemies.Count > 1) //if there is more than 1 enemy
            {
                for (int i = 0; i < additionalEnemies.Count; i++)
                {
                    float thisDistance = Vector3.Distance(transform.position, additionalEnemies[i].transform.position);

                    if (thisDistance < minDistance)
                    {
                        minDistance = thisDistance;
                        targetBot = additionalEnemies[i];
                    }
                }

                enemyObject = targetBot;
                enemyHealth = enemyObject.GetComponent<Health>();
            }
        }
    }

    public void MarkLocation()
    {
        RaycastHit hit;

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out hit))
        {
            markerCopy = Instantiate(marker, hit.point, Quaternion.identity);
            marker.transform.position = hit.point;
        }
    }

    public void RemoveMarker()
    {
        if (markerCopy != null)
            Destroy(markerCopy);
    }

    public void CreateImpactParticles()
    {
        Instantiate(impactObject, contactPoint, Quaternion.identity, gameObject.transform.parent);
    }
}