Search Unity

Question Enemy not following instantiated player, navmeshagent AI

Discussion in 'Scripting' started by zxzera, Aug 4, 2020.

  1. zxzera

    zxzera

    Joined:
    Jul 5, 2020
    Posts:
    4
    Enemy not following player, navmeshagent AI
    Hello, I am having a bit of a problem. It's not huge I guess as I could just put the player into the scene and everything works fine. However, I would like the player to be able to spawn in.

    The problem I am having is if I instantiate the player the enemies won't follow the player, even after dropping the prefab into the game object. If I drop the player into the scene and then put the player into the game object it works fine though.

    Any help is greatly appreciated.

    This is my code to grab the gameobject to folow.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3.  
    4. public class PlayerManager : MonoBehaviour
    5. {
    6.  
    7.      #region Singleton
    8.  
    9.      public static PlayerManager instance;
    10.  
    11.      private void Awake()
    12.      {
    13.          instance = this;
    14.      }
    15.  
    16.      #endregion
    17.  
    18.      public GameObject player;
    19. }
    this is the code of the enemyai

    Code (CSharp):
    1.  using UnityEngine;
    2. using UnityEngine.AI;
    3. public class EnemyAI : MonoBehaviour
    4. {
    5.      public float lookRadius = 5f;
    6.      Transform target;
    7.      NavMeshAgent agent;
    8.      private void Start()
    9.      {
    10.          target = PlayerManager.instance.player.transform;
    11.          agent = GetComponent<NavMeshAgent>();      
    12.      }
    13.      private void Update()
    14.      {
    15.          float distance = Vector3.Distance(target.position, transform.position);
    16.          if (distance <= lookRadius)
    17.          {
    18.              agent.SetDestination(target.position);
    19.          }
    20.      }
    and this is the code of the instantiate

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class SpawnPlayer : MonoBehaviour
    5. {
    6.      [SerializeField]
    7.      private Transform _playerSpawnPos;
    8.      // Start is called before the first frame update
    9.      void Start()
    10.      {
    11.          StartCoroutine(Spawn());
    12.      }
    13.      // Update is called once per frame
    14.      void Update()
    15.      {
    16.        
    17.      }
    18.      IEnumerator Spawn()
    19.      {
    20.          yield return new WaitForSeconds(1.0f);
    21.          PlayerSpawn();
    22.      }
    23.      void PlayerSpawn()
    24.      {
    25.          Instantiate(_playerSpawnPos, new Vector3(-20f, 4.3f, 9.4f), Quaternion.identity);
    26.      }
    27. }
     
    Last edited: Aug 4, 2020
  2. omnidream

    omnidream

    Joined:
    Jul 1, 2020
    Posts:
    2
    Hi!
    I´v run into similar problems a few times and a good way to solve this is to tag your player with the "Player"-tag. Then use mainChar = GameObject.FindWithTag("Player") to make a permanent reference to the Player object no matter if it is instantiated or not.

    Just remember that FindWithTag is a slower method so you could consider to just reset player stats (like health and stuff) and then transform the player to a spawn point.

    Hope this helps!
     
  3. Zer0Cool

    Zer0Cool

    Joined:
    Oct 24, 2014
    Posts:
    203
    Change your EnemyAI class so you can pass the reference to the player later:
    Code (CSharp):
    1.  using UnityEngine;
    2. using UnityEngine.AI;
    3. public class EnemyAI : MonoBehaviour
    4. {
    5.      public float lookRadius = 5f;
    6.      Transform target;
    7.      NavMeshAgent agent;
    8.  
    9.      private void Start()
    10.      {
    11.          target = PlayerManager.instance.player.transform;
    12.          agent = GetComponent<NavMeshAgent>();
    13.      }
    14.  
    15.     public void SetTarget(Transform target)
    16.     {
    17.         this.target = target;
    18.     }
    19.  
    20.      private void Update()
    21.      {
    22.          float distance = Vector3.Distance(target.position, transform.position);
    23.          if (distance <= lookRadius)
    24.          {
    25.              agent.SetDestination(target.position);
    26.          }
    27.      }
    Then pass the target to all your enemies if the player spawns (in your SpawnPlayer class):
    Code (CSharp):
    1.  void PlayerSpawn()
    2. {
    3.    Transform player = Instantiate(_playerSpawnPos, new Vector3(-20f, 4.3f, 9.4f), Quaternion.identity);
    4.    EnemyAI[] foundEnemyAIs = FindObjectsOfType<EnemyAI>();
    5.    foreach(EnemyAI enemy in foundEnemyAIs)
    6.    {
    7.      enemy.SetTarget(player);
    8.    }
    9. }
    PS:
    Dont call SetTarget too often (and not every frame) see my code here:
    https://forum.unity.com/threads/enemy-ai-doesnt-work.952664/
     
    Last edited: Aug 17, 2020
  4. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646
    Depending on the Size of the Game and Device, i would not recommend to use "FindObjectsOfType" nor "FindObjectsWithTag" runtime since its pretty slow and expensive