- Home /
The question is answered, right answer was accepted
Another NullReferenceException error.
What should be happening is "Game Over" appearing upon player death, but when the script is called, it tells me theres no reference to an object. But i have it set in the inspector as a text element. And none of the scripts return a bug, so everything is "correct." This is the error I'm getting exactly. I'll reference what the trouble lines are with comments.
NullReferenceException: Object reference not set to an instance of an object playerHealth.Death () (at Assets/Scripts/playerHealth.cs:86) playerHealth.TakeDamage (Int32 amount) (at Assets/Scripts/playerHealth.cs:77) AsteroidDmgMed.OnTriggerEnter2D (UnityEngine.Collider2D other) (at Assets/Scripts/AsteroidDmgMed.cs:23)
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GameController : MonoBehaviour
{
public Vector3 spawnValue;
public GameObject[] hazard;
public int hazardCount;
public float spawnWait;
public float waveWait;
public float startWait;
int randHazard;
public Text gameOverText;
public Text restartText;
private bool gameOver;
private bool restart;
void Start ()
{
gameOver = false;
restart = false;
restartText.text = "";
gameOverText.text = "";
StartCoroutine (SpawnWaves ());
}
void Update ()
{
if (restart) {
if (Input.GetKeyDown (KeyCode.R)) {
UnityEngine.SceneManagement.SceneManager.LoadScene ("Main");
}
}
}
IEnumerator SpawnWaves ()
{
yield return new WaitForSeconds (startWait);
while (true) {
for (int i = 0; i < hazardCount; i++) {
randHazard = Random.Range (0, 3);
Vector3 spawnPositionXpos = new Vector3 (spawnValue.x, Random.Range (-spawnValue.y, spawnValue.y), spawnValue.z);
Vector3 spawnPositionXneg = new Vector3 (-spawnValue.x, Random.Range (-spawnValue.y, spawnValue.y), spawnValue.z);
Vector3 spawnPositionYpos = new Vector3 (Random.Range (-spawnValue.x, spawnValue.x), spawnValue.y, spawnValue.z);
Vector3 spawnPositionYneg = new Vector3 (Random.Range (-spawnValue.x, spawnValue.x), -spawnValue.y, spawnValue.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate (hazard [randHazard], spawnPositionXpos, spawnRotation);
Instantiate (hazard [randHazard], spawnPositionXneg, spawnRotation);
Instantiate (hazard [randHazard], spawnPositionYpos, spawnRotation);
Instantiate (hazard [randHazard], spawnPositionYneg, spawnRotation);
yield return new WaitForSeconds (spawnWait);
}
yield return new WaitForSeconds (waveWait);
if (gameOver) {
restartText.text = "Press 'R' to Restart";
restart = true;
break;
}
}
}
public void GameOver ()
{
gameOverText.text = "Game Over";
gameOver = true;
}
}
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class playerHealth : MonoBehaviour
{
public int startingHealth = 100;
public int currentHealth;
public Slider healthSlider;
public Image damageImage;
public Image healImage;
public float DmgflashSpeed = 5f;
public float HealflashSpeed = 5f;
public Color DmgColor = new Color(1f, 0f, 0f, 0.1f);
public Color HealColor = new Color (0f, 1f, 0f, 0.1f);
playercontroller playerMovement;
GameController controller;
bool isDead;
bool damaged;
bool healed;
void Awake ()
{
controller = GetComponent <GameController> ();
playerMovement = GetComponent <playercontroller> ();
currentHealth = startingHealth;
}
void Update ()
{
if(damaged)
{
damageImage.color = DmgColor;
}
else
{
damageImage.color = Color.Lerp (damageImage.color, Color.clear, DmgflashSpeed * Time.deltaTime);
}
damaged = false;
if (healed) {
healImage.color = HealColor;
}
else {
healImage.color = Color.Lerp (healImage.color, Color.clear, HealflashSpeed * Time.deltaTime);
}
healed = false;
}
public void HealDamage (int amount)
{
if (currentHealth == 100) {
healed = false;
}
if (currentHealth < 100) {
healed = true;
currentHealth += amount;
healthSlider.value = currentHealth;
}
}
public void TakeDamage (int amount)
{
damaged = true;
currentHealth -= amount;
healthSlider.value = currentHealth;
if(currentHealth <= 0 && !isDead)
{
Death (); //Line 77
}
}
public void Death ()
{
isDead = true;
playerMovement.enabled = false;
controller.GameOver (); //Line 86
}
}
using UnityEngine;
using System.Collections;
public class AsteroidDmgMed : MonoBehaviour {
public int asteroidMedDmg = 10;
GameObject player;
playerHealth PlayerHealth;
void Awake ()
{
player = GameObject.FindGameObjectWithTag ("Player");
PlayerHealth = player.GetComponent <playerHealth> ();
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject == player)
{
PlayerHealth.TakeDamage (asteroidMedDmg); //Line 23
}
}
}
Do you know how to use breakpoints to debug? If you are using Visual Studio click the "attach to Unity" button. Once you do that, add a breakpoint by clicking to the right of the line number on that line 86 of the playerHealth script (you will see a red dot next to the line number once you have placed the breakpoint). Play the game, and when it hits that point you will see Unity stop and control be passed to Visual Studio. I am suspecting that the controller in that line of "controller.GameOver is null.
Debugging in general is great to know and can help you out in many instances when your code does not appear to be working right, but does compile (as yours would if the controller was null). Here is a tutorial with more information concerning debugging.
https://unity3d.com/learn/tutorials/topics/scripting/debugging-unity-games-visual-studio
Lastly, just a nitpick, but usually classes are pascal case, so your playerHealth class should be PlayerHealth.
I'll give that a shot.
And I can understand your nitpick, haha. $$anonymous$$y code is rather ugly. I'll sort it once everything is working properly.
Are your playerHealth and GameController scripts attached to the same object?
They are not. GameController is attached to an empty game object called GameController. playerHealth is attached to the player model.
Answer by Hanoble · Sep 06, 2016 at 09:54 PM
That will not worksince your playerHealth and controller scripts are on different objects. In your playerHealth script in the Awake() method, this line here attempts to get the controller component from the object it is on:
controller = GetComponent <GameController> ();
Since there is no controller on that object, it is null, which is why when you call controller.GameOver(), you get a null reference.
Put the controller on the same object as the playerHealth and it would work. Alternatively, and a method more commonly used, is to create a tag for the controller. If you called that tag Controller, you could then get the reference to the object in that Awake() method by using this code:
controller = GameObject.FindWithTag("Controller").GetComponent<GameController>();
So, am I able to just copy the code, past it under the player game object and delete the original?
also, controller = GameObject.FindWithTag ("GameController"); gives me this error "Cannot implicitly convert type UnityEngine.GameObject' to
GameController'"
Hanoble, my friend, you have solved my problem. $$anonymous$$any Thanks.
Yeah sorry about that, you need to get the controller like this.
controller = GameObject.FindWithTag("Controller").GetComponent<GameController>();
To better explain, that first example gives only the GameObject because that method of "FindWithTag(string)" returns a gameobject. Once you get the gameobject, you can then use a get component as you would normally.
A lot of this stuff is pretty important when it comes to Unity and scripting in general, have you visited the tutorial videos yet? They are a really good place to start and cover topics from nearly all sides of the Unity engine. I would HIGHLY recommend taking a look at those.
I've pored over almost all of the tutorial videos so many times. I couldn't find a solution to my problem. But this is going in my notebook so i don't forget it.
Answer by metalted · Sep 06, 2016 at 07:33 PM
If you have attached a Text Component in the inspector, don't forget to get that component of your object with:
gameOverText = GetComponent<Text>();
This will make sure you are writing to the right text component. What I'm thinking is that you are writing text to non-existing (null) text component, what will give you a "null reference exception" error.
On the Player Health script, switch the positions of the controller reference and the player reference. I had a similar issue and it seemed switching around somethings worked. I can give a little reason(from my understanding) as to why this occurs. We all know that scripts are read from top down and the updates are read again every frame, well if you put the controller before the player, the reference becomes null at Death() because it didn't read the player first. It has to know who the player is first in order to call the function, then it can call Controller. This may sound redundant and counterproductive but that just seems to be how it works.
Scripts are not read from top down, within a method in most cases they are, but universally no. Anytime you did something and it "just worked", there is usually a more technical reason as to why it worked. You could put an Awake() function at the bottom of your script and it will run before the Start(), Update(), etc.
His controller is null because he is attempting to get the GameController component on the same object his playerHealth script is attached to, but the GameController is on another script entirely. It is null because it is, well, null. There is no GameController on that object.
Doing that returns a bug. I have the text as a public Text and i just dragged the text component in to the inspector. I did it with a timer and a score display, and those both work fine.
Edit: also, unfortunately changing the order of some of the lines didn't change anything.
Follow this Question
Related Questions
Null Reference exception bug? 0 Answers
GUI NullReferenceException 2 Answers
NullReferenceException in for-loop 0 Answers
NullReferenceException 1 Answer