Can't find tagged player, but can assign trough public variable

Hello! I’ve been working on a small 2D multiplayer game for a little while now. Recently I have been implementing some simple AI to chase the player(s). However, when I try to use GameObject.FindGameObjectWithTag, it throws a NullReferenceException: Object reference not set to an instance of an object error. I am using Mirror for networking instead of UNet because I had some issues with that. I am able to assign the Target variable by dragging the player object into it ingame, and it works perfectly fine then. I have also tried making other objects with the “AITarget” tag, and that also works! However, as soon as I declare that object as the player prefab in the Mirror NetworkManager, the AI can’t find the object anymore. GameObject.Find doesn’t work either.

AIController script:

using UnityEngine;
using Mirror;

public class AIController : NetworkBehaviour
{
    public int speed;
    public int turnSpeed;

    public Transform target;

    Rigidbody2D rb2D;

    void Awake()
    {
        rb2D = GetComponent<Rigidbody2D>();
        target = GameObject.FindGameObjectWithTag("AITarget").transform;
    }

    void FixedUpdate()
    {
        Move();
        Turn();
    }

    void Move()
    {
        rb2D.velocity = transform.up * speed * Time.fixedDeltaTime;
    }

    void Turn()
    {
        Vector2 direction = (Vector2)target.position - rb2D.position;
        direction.Normalize();

        float rotateAmount = Vector3.Cross(direction, transform.up).z;

        rb2D.angularVelocity = -rotateAmount * turnSpeed * Time.deltaTime;
    }
}

PlayerController script:

using UnityEngine;
using Mirror;

public class PlayerController : NetworkBehaviour
{
    public int speed;
    public int turnSpeed;

    public float fireRate;

    public GameObject bulletPrefab;
    public Transform firePoint;

    Rigidbody2D rb2D;

    float nextTimeToFire = 0f;

    void Awake()
    {
        rb2D = GetComponent<Rigidbody2D>();
    }

    void FixedUpdate()
    {
        if (!isLocalPlayer)
        {
            return;
        }

        Move();
        Turn();

        if (Input.GetMouseButton(0) && Time.time >= nextTimeToFire)
        {
            CmdFire();
            nextTimeToFire = Time.time + 1f / fireRate;
        }
    }

    void Move()
    {
        rb2D.velocity = transform.up * speed * Time.fixedDeltaTime;
    }

    void Turn()
    {
        Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);

        Vector2 direction = (Vector2)mousePos - rb2D.position;
        direction.Normalize();

        float rotateAmount = Vector3.Cross(direction, transform.up).z;

        rb2D.angularVelocity = -rotateAmount * turnSpeed * Time.deltaTime;
    }

    [Command]
    void CmdFire()
    {
        GameObject bullet = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);

        NetworkServer.Spawn(bullet);
    }

    public override void OnStartLocalPlayer()
    {
        GetComponent<SpriteRenderer>().color = Color.blue;
    }
}

Full error:

NullReferenceException: Object reference not set to an instance of an object
AIController.Awake () (at <b20ef9cf22714441922445df38f1b92e>:0)
UnityEngine.Object:Instantiate(GameObject, Vector3, Quaternion)
AISpawner:OnStartServer()
Mirror.NetworkIdentity:OnStartServer(Boolean) (at Assets/Mirror/Runtime/NetworkIdentity.cs:373)
Mirror.NetworkServer:SpawnObject(GameObject) (at Assets/Mirror/Runtime/NetworkServer.cs:937)
Mirror.NetworkServer:Spawn(GameObject) (at Assets/Mirror/Runtime/NetworkServer.cs:1035)
Mirror.NetworkServer:SpawnObjects() (at Assets/Mirror/Runtime/NetworkServer.cs:1228)
Mirror.NetworkManager:StartServer() (at Assets/Mirror/Runtime/NetworkManager.cs:261)
Mirror.NetworkManager:StartHost() (at Assets/Mirror/Runtime/NetworkManager.cs:318)
Mirror.NetworkManagerHUD:OnGUI() (at Assets/Mirror/Runtime/NetworkManagerHUD.cs:42)

Sorry if I left anything out and thanks in advance :]

couple things, do you actually have a tagged assigned in your editor on your player object (not in the script but the editor) called AITarget. if not it may be as simple as that.

the other thing is gameobject.find is a little slow when you continue to build up the game works fine but I constantly found myself having to rescript and rescript because I was throwing null references for goodness knows why.

it helped when i switched to static variables which is a little more readily available than gameobject.find or findwithtag.

basically you’ll declare your script as static at the very top and you’ll give it it’s own handle name so if you want the AI to track the player you would make whatever script contains your player prefab static and public. Here’s my example

//my player prefab is held in my game Manager
public class GameManager : NetworkBehaviour

 {
      //this is declaring my script as available to be communicated with, first name has to be same as the script and the second is just whatever you want to call it
      public static GameManager gManager;

      //your "Player script" controls your player but you're trying to get the AI to track the player so it can go 1 of 2 ways, this is gamemanager version and i'll give you an IE of doing it through the player script.
      public GameObject player;

      //always always have this method in any static script, it will make sure on reloads, restarts etc that there's always only one of it.
      private void Awake()
{
    
    if (gManager == null)
    {    
        gManager = this;
    }
    
    else if (gManager != this)
    {    
        Destroy(gameObject);
    }
}
 }

so now you can access the player gameobject from any other script. so in your AI script you can just declare what you’re looking for like you’re trying to in the start method but it would look like this
public class AIController : NetworkBehaviour

{
    target = newVector3 (GameManager.gManager.player.transfrom.position);
 }

this is the version i use in my game for a similar concept where i want a perfect mirror of my player and i do it in my player script which is my prefered method. you still set it up in the player script the same way i showed you for the game manager.

public class MirrorPlayer : MonoBehavior

 {
     transform.position = new Vector3(Player.ninja.transform.position.x * -1, Player.ninja.transform.position.y, Player.ninja.transform.position.z);
 }

Hey! I tried around with your method, but sadly I couldn’t get it to work. Or it did kinda work, but the AI didn’t move and thought the players position was 0,0,0. But I figured it out myself, finally!! It was actually pretty damn simple, all I did was add the target = GameObject.FindGameObjectWithTag("AITarget").transform; to LateUpdate() instead of Awake/Start. I’m guessing the AI was searching for the player moments before it spawned, but that doesn’t really answer why using Update() didn’t work either. Anyway thank you for the help, the next thing I’ll be doing is store the players in an array to pick from :slight_smile: