How would i use a prefab gameobject clone as a player target for a navmesh agent in unity version 2022.3f

36 views Asked by At

I need a solution to my problem. i need a way for my navmesh_agent. to detect and follow a prefab clone instead of a gameobject already inside of the scene. to give some intel i am trying to add multiplayer to my zombie game, and as you may know to use multiplayer in unity you will need to spawn a new player each time incase of player joining.

ive tried, creating a prefab of the player, and deleting the one in the scene having the nav mesh straight up, follow the prefab starting runtime, and dragging the prefab into the scene. Unfortunately i am not able to think of another solution.

using UnityEngine;
using UnityEngine.AI;

public class ZomWalkerAI : MonoBehaviour
{
    public GameObject Zom1DW;
    public GameObject Zom1I;
    public GameObject Zom1NB;
    public Transform Playerpos;
    public bool TouchingPlayer = false;
    UnityEngine.AI.NavMeshAgent agent;
    public bool inRange = false;
    // Start is called before the first frame update
    void Start()
    {
       agent = GetComponent<UnityEngine.AI.NavMeshAgent>();
       Zom1DW.SetActive(false);
       Zom1NB.SetActive(false);
       Zom1I.SetActive(false);

    }
    void Update()
    {
        if (TouchingPlayer == true)
        {
            Zom1I.SetActive(false);
            Zom1NB.SetActive(true);
            Zom1DW.SetActive(false);
            
        }

        if (inRange == false)
        {
            Zom1I.SetActive(true);
            Zom1NB.SetActive(false);
            Zom1DW.SetActive(false);
        }
        if (inRange == true)
        {
            if(TouchingPlayer == false)
            {
                Zom1DW.SetActive(true);
                Zom1I.SetActive(false);
                Zom1NB.SetActive(false);
                agent.destination = Playerpos.position; 
            }

        }
    }
    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {
            inRange = true;  
        }
    }  
    void OnTriggerExit(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {
            inRange = false;  
            Zom1DW.SetActive(false);
1

There are 1 answers

5
Patrick Moling On

There are a lot of solutions you could implement, basing on my experience, working with Transform's Tags is way easier than anything else.

What I would do is create a Player tag and assign it to the Player prefab that you mentioned. (I just saw you did it so you are already good to go for the next step)

Then, I would create a script that handles the tracking of the players, it is way more efficient than having it on every single zombie.

GameObject[] playerArray;

private void Start() {
   InvokeRepeating(nameof(GetPlayers),0,1); //not optimized but not expensive, easy way of updating the players reference
}

private void GetPlayers() { //You must call this function when a player joins or exits the lobby
   playerArray = GameObject.FindGameObjectsWithTag("Player");
}

public GameObject FindClosestPlayerTo(Transform zombie) {
   GameObject closestPlayer = null;
   float distance = Mathf.Infinity; 
   foreach (GameObject player in playerArray) {
      if (player == null) continue; //maybe a player quits?
      Vector3 difference = player.transform.position - zombie.position; 
      float currentDistance = difference.sqrMagnitude; 
      if (currentDistance < distance) {
         closestPlayer = player;
         distance = currentDistance; 
      } 
    } 
    return closestPlayer; 
}

With this done, from you zombie script you could do:

 private void FindTarget() { //You should call this every second using InvokeRepeating just like before 
    GameObject closestPlayer = referenceToScript.FindClosestPlayerTo(transform); 
    if (closestPlayer != null)
       referenceAgent.SetDestination(closestPlayer.transform.position);
 }

And there you go, easy zombie system setup.