Is there any way to assign player to Camera after the game started in unity?

Viewed 323

Okay, so I create an endless runner game that has character selection. The goal is, when the scene starts (with no player in the hierarchy), the game manager will instantiate the player based on the selected player. But, the CameraController, have the error "Object reference not set to an instance of an object", it cannot find the instantiate player object

Here is how I instantiate my player:

void Start()
{
    int selectedCharacter = PlayerPrefs.GetInt("selectedChar");
    GameObject prefab = characterPrefabs[selectedCharacter];
    GameObject clone = Instantiate(prefab, playerStartPoint, Quaternion.identity);
    player = FindObjectOfType<PlayerScript>();
    platformStartPoint = platformGenerator.position;
    scoreManager = FindObjectOfType<ScoreManager>();
    Reset();
}

And this is my camera script:

public class CameraController : MonoBehaviour{
public PlayerScript player;
private Vector3 lastPlayerPosition;
private float distToMove;
// Start is called before the first frame update
void Start()
{
    player = FindObjectOfType<PlayerScript>();
    lastPlayerPosition = player.transform.position;
}

// Update is called once per frame
void Update()
{
    distToMove = player.transform.position.x - lastPlayerPosition.x;
    transform.position = new Vector3(transform.position.x + distToMove, transform.position.y, transform.position.z);
    lastPlayerPosition = player.transform.position;
}
}

The camera should be move along with the character, do you have any idea how to fix this? Thank you

2 Answers

I'm assuming your Camera tries to search for the player before they get instantiated based on what you mentioned. There are several different approaches to fixing this.

Method 1

Have the script that instantiates the player grab the camera and assign the player instance.

Example

// Call this after instantiating a player instance
FindObjectOfType<CameraController>().AssignTarget(player);
// Add this to CameraController.cs
public void AssignTarget(PlayerScript player)
{
    this.player = player;
    lastPlayerPosition = player.transform.position;
}

Method 2

Add an event field somewhere that informs when player has been instantiated and subscribe to it using your camera.

Example

using System;
using UnityEngine;

public class PlayerScript : MonoBehaviour
{
    public static event Action<PlayerScript> InstanceStarted;

    private void Start()
    {
        InstanceStarted?.Invoke(this);
    }
}

using UnityEngine;

public class CameraController : MonoBehaviour
{
    private Player player;

    private void Start()
    {
        player = FindObjectOfType<PlayerScript>();
        if (player == null)
            PlayerScript.InstanceStarted += OnPlayerInstanceStarted;
    }

    private void OnPlayerInstanceStarted(PlayerScript instance)
    {
        PlayerScript.InstanceStarted -= OnPlayerInstanceStarted;
        player = instance;
    }
}

Method 3

Add DefaultExecutionOrder attribute to your scripts and change the execution order to ensure that the player gets instantiated before the Camera starts to look for one.

Example

[DefaultExecutionOrder(100)]
public class TestScript : MonoBehaviour {}

Method 4

Have a Coroutine that periodically checks whether an instance of a player is available before allowing the Camera to do anything.

Example

using System.Collections;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    private PlayerScript player;

    private void Start()
    {
        StartCoroutine(StartOncePlayerIsFound());
    }

    private IEnumerator StartOncePlayerIsFound()
    {
        player = FindObjectOfType<PlayerScript>();
        while (player == null)
        {
            // Feel free to yield "WaitForEndOfFrame" or "null"
            // if you wish to search for player every frame

            yield return new WaitForSeconds(0.1f);
            player = FindObjectOfType<PlayerScript>();
        }

        // ...
    }
}

Try this one

transform.position = new Vector3(player.transform.position.x, transform.position.y, transform.position.z);
Related