Problem with newly instantiated object and accessing a script attached to it

Hi!

In my game I create a clone of the player object and then add a new script called “PlayerMovement_Script” to it which contains a movement logic and also the player’s lives, like below:

Instantiate Player Script:

    private void Start()
    {
        var clone = Instantiate(player, transform.position, Quaternion.identity);
        clone.AddComponent<PlayerMovement_Script>();
        clone.tag = "Player";
    }

That script which is added to the clone has a variable called “playerLife”, a float of value 3. The frustration comes from trying to access that “playerLife” variable inside the clone from another script so I can change the UI and show the number of lives. This is where the error is coming from:
Update UI Script:

private float lifeVariable;

private void Start()
{
   var playerClone = GameObject.FindGameObjectWithTag("Player");
   lifeVariable = playerClone.GetComponent<PlayerMovement_Script>().playerLife;
   DoThingsAndStuff()
}

The error I’m getting is:
"nullreferenceexception object reference not set to an instance of an object"

I don’t have another object by tag “Player”, I made sure of that. The clone exists, I can move it, I also tried accessing it with GameObject.Find("Player(Clone)" but it also didn’t work, so I’m just currently frustrated trying to find what am I missing here.

Any ideas? I got the game running by declaring “playerLife” as a static float, but I honestly want to try and found out what am I doing wrong first. Thank you.

If both of those are in the scene at start, it is a 50/50 chance which script runs first.

Instead, it’s always better to explicitly connect them.

In this trivial case of player and UI, here would be my approach.

  • first I would not use the tags at all right now (you can go back and add it later)
  • in your player Start() do everything you are doing now, but also keep a reference to the added component:
var movement = clone.AddComponent<PlayerMovement_Script>();

Now you need to pass that to the UI screen script. The easiest way is probably with a FindObjectOfType<YourUISystem>() call. That will give you a reference to the UI script.

Now that you have that reference make a public function in the UI script that you call, something like “InitializeWithPlayer();” and it accepts the movement variable above.

You would call that function after you have cloned your player and added the movement script.

Remove anything to do with finding the player from the UI screen.

Also make sure the UI screen doesn’t try to do anything in Update() until it has a valid player movement reference, to avoid null references.

This way you guarantee that the UI screen is quiescent until it hears from the spawned player, and you are therefore immune to script order. I do NOT recommend tweaking script execution order. That is a path to many tears.

Taking this one step higher, often you have a playing scene manager script that sets up the scene according to what you need: it spawns the player, tells the UI (and anyone else) about the player, loads the enemies, etc.

1 Like

I thought about the possibility of the start() being executed concomitantly, but when looking objectively for the Instantiate problem, I believe I didn’t find anyone with a similar problem. I’ll try your solution, by the way, thank you very much!

1 Like

Ok, so I created a Coroutine that holds for 3 seconds before activating a bool which then allows for my script to get the “playerLife” reference.

I did the following just to be sure he is getting the right object:

public void Start()
    {
        StartCoroutine(WaitForExecution());
    }

    private void Update()
    {
        if (hasFinishedRunning)
        {
            var player = GameObject.FindGameObjectWithTag("Player_Object");
            Debug.Log("has found player");
            var newBool = player.GetComponent<PlayerInst_Script>().hasFinishedInst;
            if (hasFinishedInst)
            {
                DoStuff();
            }

    {
        IENumerator WaitForExecution()
    {
           yield return new WaitForSeconds(3);
    }
    }

I’m getting the “has found player” so I know for sure that my clone exists (also I can see him existing), but I’m still getting the same error, though this time is on the
var newBool = player.GetComponent<PlayerInst_Script>().hasFinishedInst;
Line. Any Ideas?

Well…No, you actually don’t know your clone exist when the debug runs. Your debug line is just a string and doesn’t actually reference the player variable at all, so for all you know, the value is null when this script runs.

Also, your coroutine doesn’t really seem to do anything? Did you just not post all the code? That might be what it is.

Anyways, if you’re getting null on that line either player is null or the GetComponent call doesn’t see the script you are trying to get on the player gameObject, thus it is null. Either way, when you do a debug to check if player is null or not, you should add the player to it to see if it is null or not. Or just do an if check and see if it’s equal to null and if so, you can do a debug to let you know or try to find the object again.

And to clarify, running this code in Update is not very performant since it runs every frame.