I’m making my very first game on my own (I’m about 1 month into Unity and 3 weeks into C#) and I’m getting the good ol’ NullReferenceException error. I’ve dug through forum posts (there are…so so many,) but I’m not finding a post referencing this error in regards to referencing different scripts. Or maybe I’m not sure what terminology to use to find them…
Right now I’m working step-by-step, slowly. I’m currently just trying to get my Restart button and Game Over text to show up when the player is destroyed. The NullReferenceException error points to line 7 of PlayerController.cs
Snippet from PlayerController.cs
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Asteroid"))
{
Debug.Log("Player has collided with asteroid!");
Destroy(gameObject);
gameManagerScript.GameOver();
}
}
Snippet from GameManagerScript.cs
public void GameOver()
{
gameOverText.gameObject.SetActive(true);
restartButton.gameObject.SetActive(true);
isGameActive = false;
}
If I remove “gameManagerScript.GameOver();” from the OnCollisionEnter then the error doesn’t come up. Both of the game objects referenced have objects set in the component, so I’m unsure why I’m getting this error… I’m sure the answer is embarrassingly simple, but I can’t seem to find it. I would assume it’s the text and button objects that are triggering this error, but I’m not sure why.
“I’ve dug through forum posts…”
https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/
You didnt post the stack trace of the error. So i cant tell if its the error is thrown because the gameManagerScript is null or something in GameOver() is null. You need to double check if these are realy set. You can also check all uses of the gameManagerScript with shift+F12. Finally you can attach the debugger and go line by line.
1 Like
Sorry… Here’s the error:
NullReferenceException: Object reference not set to an instance of an object
PlayerController.OnCollisionEnter (UnityEngine.Collision collision) (at Assets/Scripts/PlayerController.cs:73)
Line 73 in this error is line 7 in my post.
I’ve double (and triple) checked the objects are set.
I didn’t know about shift+F12! Thanks, that’s very handy. It only lists the one reference, though… I’ve never used a debugger before, so I’ll look into that.
Finally, here’s my full scripts if that’s any more helpful:
PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public GameObject laserPrefab;
private float speed = 15.0f;
private float zBoundary = 12.0f;
private float xBoundary = 24.0f;
private Rigidbody playerRB;
private float cooldown;
private float spawnInterval = 1.0f;
private GameManagerScript gameManagerScript;
// Start is called before the first frame update
void Start()
{
playerRB = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
MovePlayer();
ConstrainPlayer();
ShootLaser();
}
// Moves the player based on arrow key input
void MovePlayer()
{
// Reference point for inputs
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
// Uses force to move the player by a specific speed and key input
transform.Translate(Vector3.right * Time.deltaTime * speed * horizontalInput);
transform.Translate(Vector3.up * Time.deltaTime * speed * verticalInput);
}
// Prevent the player from leaving the screen
void ConstrainPlayer()
{
if (transform.position.z < -zBoundary)
{
transform.position = new Vector3(transform.position.x, transform.position.y, -zBoundary);
}
if (transform.position.z > zBoundary)
{
transform.position = new Vector3(transform.position.x, transform.position.y, zBoundary);
}
if (transform.position.x < -xBoundary)
{
transform.position = new Vector3(-xBoundary, transform.position.y, transform.position.z);
}
if (transform.position.x > xBoundary)
{
transform.position = new Vector3(xBoundary, transform.position.y, transform.position.z);
}
}
// Player is destroyed on collision with asteroid
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Asteroid"))
{
Debug.Log("Player has collided with asteroid!");
Destroy(gameObject);
gameManagerScript.GameOver();
}
}
// Powerup is destroyed on collision with player
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Powerup"))
{
Destroy(other.gameObject);
}
}
// Lasers are fired from Player on a delay
private void ShootLaser()
{
// Decrease cooldown on each frame
cooldown -= Time.deltaTime;
// On spacebar press, send laser
if (Input.GetKeyDown(KeyCode.Space) && cooldown <= 0)
{
Instantiate(laserPrefab, transform.position, laserPrefab.transform.rotation);
cooldown = spawnInterval;
}
}
}
GameManagerScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GameManagerScript : MonoBehaviour
{
public GameObject titleScreen;
public bool isGameActive;
public TextMeshProUGUI gameOverText;
public Button restartButton;
//
private void Update()
{
}
//
public void StartGame()
{
isGameActive = true;
titleScreen.SetActive(true);
}
public void GameOver()
{
gameOverText.gameObject.SetActive(true);
restartButton.gameObject.SetActive(true);
isGameActive = false;
}
}
How are you setting the gamemanager script reference?
Because this: private GameManagerScript gameManagerScript;
is not setting the reference to the script component. And as that is private you can’t be setting it through the Inspector as it would need to either be public or a serialized field for it to show up. So to set the reference you would need to be doing something like you do to get the rigidbody - although if the other script is on a different game object then you would probably have to do a find.
1 Like
Omg… As I thought, embarrassingly simple. Thank you so much, I hadn’t set it at Start. I added “gameManagerScript = GameObject.Find(“Game Manager”).GetComponent();” and it works perfectly.
Thank you again, so much.
Just for the future: When the top of the stacktrace points to a line inside the OnCollisionEnter method, then the exception has been thrown in that method. Not in a method that you call from this method. If the exception would have been thrown inside your GameOver method, that would have been the top entry in the stacktrace. So the error literally tells you the exact line that causes the error. The only reference in this line
gameManagerScript.GameOver();
is your “gameManagerScript” variable. So it has to be null. Then the next question you should ask yourself: why is it null. Or to reverse the logic: Why should it have a value at all. And if you’re looking for reasons why it may or may not have a value, it should become clear quickly. Just look for any places you assign a value to this variable. Of course public / serialized variables may get their value through an inspector assignment. However even if you did that, there could be other code overwriting that value.
We had once a question where the user had a public variable and assigned the other script in the inspector. However he also had an assignment in Awake where he used GetComponent to initialize the variable. Since the actual script he assigned was not on the same gameobject, GetComponent returned null since there was no such component on this object. So he explicitly replaced the reference he had correctly assigned in the inspector with null in code.
You should always keep in mind what you’re actually doing. Assigning a value 3 times or 10 times does not make the assignment “better” ;). You should pick one method to assign references. If you want to use a fallback solution, that’s fine, however be clear and aware about which method has priority. Usually when the variable is public you want to assign the object in the inspector. You could add code that checks in Awake or start if the variable is null and only then use GetComponent. So if something is assigned in the inspector, you would use that. If nothing was assigned it would use GetComponent. Of course that does not guarantee that you have a reference afterwards as shown in the example above. However depending on the kind of script / component such a fallback could be handy in some cases.
1 Like
@Bunny83 thanks so much for the long explanation. Some of this is over my head for now, but I’ll look back to this post as I learn more. I’m new enough that I forget setting a variable isn’t the same as setting a reference (I think I’ve got the terminology correct there.) Though after this post, I don’t think I’ll have any trouble remembering that in the future 