0

I'm making a game right now where the enemies become alerted to the player and chase them indefinetely until the player stand on a "safe plate" in game. When the player stands here the enemies should then return to their original position.

The issue is that whenever the player stands on the plate I get a null reference exception error and I can see the original guard position has been reset to 0,0,0 in the console. I'm assuming the reason for the null reference exception is because the world origin isn't on the nav mesh I'm using, although I could easily be wrong about that. I just can't seem to figure out why the vector3 value has changed at all since the guardPosition variable is initiated on Start and never touched again.

I've included both my enemyAi class (script attached to enemy) and my class associated with stepping on plates. If there's anything more needed to include let me know. If anyone has any ideas, help would be appreciated. Cheers.

Screenshot on console after stepping on plate

public class EnemyAI : MonoBehaviour
{
    
    DeathHandler dh;

    [SerializeField] Transform target;
    [SerializeField] float chaseRange = 5f;
    [SerializeField] float killRange = 2f;

    [SerializeField] GameObject explosionEffect;

    NavMeshAgent navMeshAgent;
    float distanceToTarget = Mathf.Infinity;
    bool isDead = false;
    bool isAlert = false;

    Vector3 guardPosition;

    void Start()
    {
        GameObject gob;
        gob = GameObject.Find("Player");
        dh = gob.GetComponent<DeathHandler>();

        guardPosition = transform.position;

        navMeshAgent = GetComponent<NavMeshAgent>();
    }

    void Update()
    {
        distanceToTarget = Vector3.Distance(target.position, transform.position);

        print(guardPosition + " guard position during update");

        //alert a dude
        if (distanceToTarget <= chaseRange && !isDead)
        {
            isAlert = true;
        }

        //chase a dude
        if (isAlert == true)
        {
            ChasePlayer();
            print(isAlert);
        }
    }

    public void ChasePlayer()
    {
        navMeshAgent.SetDestination(target.position);

        //explode a dude
        if (distanceToTarget <= killRange)
        {
            Explode();
            dh.KillPlayer();
        }
    }

    public void SetAlertStatus(bool status)
    {
        isAlert = status;
    }

    public void ReturnToPost()
    {
        //isAlert = false;
        print(guardPosition + " guard position after stepping on plate");
        navMeshAgent.SetDestination(guardPosition);
    }    

    void Explode()
    {
        Instantiate(explosionEffect, transform.position, transform.rotation);

        isDead = true;
        Destroy(gameObject);
    }

    void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, chaseRange);
    }
}
public class SafeSpots : MonoBehaviour
{
    
EnemyAI enemyAi;

    

    void Start()
    {
        GameObject gob;
        gob = GameObject.FindGameObjectWithTag("Enemy");
        enemyAi = gob.GetComponent<EnemyAI>();
    }

    public void OnTriggerStay(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {
            

            enemyAi.SetAlertStatus(false);
            enemyAi.ReturnToPost();
        }
    }
}
S.Cardno
  • 5
  • 4
  • are you sure you are retrieving `navMeshAgent` in the start? Maybe that is what is null and is what is causing the exception – rustyBucketBay Dec 15 '20 at 15:33
  • As far as I know, it's being retrieved. The enemy will chase the player about on the navMesh fine. It's just when the player steps on the plate it breaks. – S.Cardno Dec 15 '20 at 15:37
  • code doesn't produce described behaviour - no line prints "guard position during update". Anyway, it's possible that the `EnemyAI.guardPosition` being read to print the "guard position during update" log is of a different instance of `EnemyAI` than the one `FindGameObjectWithTag("Enemy")` finds. Question mentions many enemies. Have you considered using [`FindGameObjectsWithTag`](https://docs.unity3d.com/ScriptReference/GameObject.FindGameObjectsWithTag.html) then iterating through them all? – Ruzihm Dec 15 '20 at 16:07
  • Ah sorry, I changed the print statements after pasting the code to make the screenshot more readable. I've edited the code now to where they appear. As for your suggestion, I do have multiple enemies but for the purposes of testing, I disabled the EnemyAi script on all but 1. – S.Cardno Dec 15 '20 at 16:36
  • Yes, and so when you look for game objects with tag in `SafeSpots.Start`, it seems to be getting one which has its `EnemyAI` script disabled. And since it is disabled, its `EnemyAI.Start` does not run, and so its `guardPosition = transform.position;` is never called on that instance. That means when you call `GetComponent()` on it, it is getting a disabled instance of `EnemyAI` that has never set its `guardPosition` field. It is a different instance of `EnemyAI` than the one whose `Update` is running and printing "guard position during update" – Ruzihm Dec 15 '20 at 16:43

1 Answers1

0

You are getting a disabled instance of EnemyAI. Instead, use FindGameObjectsWithTag then iterate through all of them and add their EnemyAI to a list which you can iterate through when necessary. By the way, it's better to use CompareTag when possible to reduce garbage:

public class SafeSpots : MonoBehaviour
{
    
    List<EnemyAI> enemyAis;

    void Start()
    {
        GameObject[] enemies= GameObject.FindGameObjectsWithTag("Enemy");
        enemyAis = new List<EnemyAI>();
       
        foreach (GameObject enemy in enemies)
        {
            enemyAis.Add(enemy.GetComponent<EnemyAI>());
        }
    }

    public void OnTriggerStay(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            foreach(EnemyAI enemyAi in enemyAis)
            {
                enemyAi.SetAlertStatus(false);
                enemyAi.ReturnToPost();
            }
        }
    }
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • Yes okay, this is what it was! I had been focussing on the wrong area this whole time. I've made those changes and now I'm getting the expected behavior. Thank you so much, it's been driving me mad. I'll remember that `CompareTag` in the future too, thanks! – S.Cardno Dec 15 '20 at 17:19