0

I am working on creating a game using the 2D rouge-like tutorial provided by unity. Everything works as expected thus far apart from movement. When the game runs a single error appears.

"NullReferenceException: object reference not set to an instance of an object completed.player.start () (at Assets/Completed/Scripts/Player.cs:39) "

This is the line of code causing the error: healthText.text = "Health: " + health;

The code for the entire script is below:

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
using UnityEngine.UI;   //Allows us to use UI.

namespace Completed
    {
    //Player inherits from MovingObject, our base class for objects that can move, Enemy also inherits from this.
    public class Player : MovingObject
    {
        public float restartLevelDelay = 1f;        //Delay time in seconds to restart level.
        public int pointsPerGoodFood = 10;          //Number of points to add to player health points when picking up a GoodFood object.
        public int pointsPerOkayFood = 20;          //Number of points to add to player health points when picking up a OkayFood object.
        public int wallDamage = 1;                  //How much damage a player does to a wall when attacking it.
        public Text healthText;                     //UI Text to display current player health total.
        public AudioClip moveSound1;                //1 of 2 Audio clips to play when player moves.
        public AudioClip moveSound2;                //2 of 2 Audio clips to play when player moves.
        public AudioClip eatSound1;                 //1 of 4 Audio clips to play when player collects a GoodFood object.
        public AudioClip eatSound2;                 //2 of 4 Audio clips to play when player collects a GoodFood object.
        public AudioClip eatSound3;                 //3 of 4 Audio clips to play when player collects a OkayFood object.
        public AudioClip eatSound4;                 //4 of 4 Audio clips to play when player collects a OkayFood object.
        public AudioClip gameOverSound;             //Audio clip to play when player dies.

        private Animator animator;                  //Used to store a reference to the Player's animator component.
        private int health;                         //Used to store player health points total during level.

        //Start overrides the Start function of MovingObject
        protected override void Start ()
        {
            //Get a component reference to the Player's animator component
            animator = GetComponent<Animator>();

            //Get the current health point total stored in GameManager.instance between levels.
            health = GameManager.instance.playerHealthPoints;

            //Set the foodText to reflect the current player health total.
            healthText.text = "Health: " + health;

            //Call the Start function of the MovingObject base class.
            base.Start ();
        }


        //This function is called when the behaviour becomes disabled or inactive.
        private void OnDisable ()
        {
            //When Player object is disabled, store the current local health total in the GameManager so it can be re-loaded in next level.
            GameManager.instance.playerHealthPoints = health;
        }


        private void Update ()
        {
            //If it's not the player's turn, exit the function.
            if(!GameManager.instance.playersTurn) return;

            int horizontal = 0;     //Used to store the horizontal move direction.
            int vertical = 0;       //Used to store the vertical move direction.

            //Check if we are running either in the Unity editor or in a standalone build.
            #if UNITY_STANDALONE || UNITY_WEBPLAYER

            //Get input from the input manager, round it to an integer and store in horizontal to set x axis move direction
            horizontal = (int) (Input.GetAxisRaw ("Horizontal"));

            //Get input from the input manager, round it to an integer and store in vertical to set y axis move direction
            vertical = (int) (Input.GetAxisRaw ("Vertical"));

            //Check if moving horizontally, if so set vertical to zero.
            if(horizontal != 0)
            {
                vertical = 0;
            }

            //Check if we have a non-zero value for horizontal or vertical
            if (horizontal != 0 || vertical != 0)
            {
                //Call AttemptMove passing in the generic parameter Wall, since that is what Player may interact with if they encounter one (by attacking it)
                //Pass in horizontal and vertical as parameters to specify the direction to move Player in.
                AttemptMove<Wall> (horizontal, vertical);
            }
        }

        //AttemptMove overrides the AttemptMove function in the base class MovingObject
        //AttemptMove takes a generic parameter T which for Player will be of the type Wall, it also takes integers for x and y direction to move in.
        protected override void AttemptMove <T> (int xDir, int yDir)
        {
            //Every time player moves, subtract from health points total.
            health--;

            //Update health text display to reflect current score.
            healthText.text = "Health: " + health;

            //Call the AttemptMove method of the base class, passing in the component T (in this case Wall) and x and y direction to move.
            base.AttemptMove <T> (xDir, yDir);

            //Hit allows us to reference the result of the Linecast done in Move.
            RaycastHit2D hit;

            //If Move returns true, meaning Player was able to move into an empty space.
            if (Move (xDir, yDir, out hit)) 
            {
                //Call RandomizeSfx of SoundManager to play the move sound, passing in two audio clips to choose from.
                SoundManager.instance.RandomizeSfx (moveSound1, moveSound2);
            }

            //Since the player has moved and lost health points, check if the game has ended.
            CheckIfGameOver ();

            //Set the playersTurn boolean of GameManager to false now that players turn is over.
            GameManager.instance.playersTurn = false;
        }


        //OnCantMove overrides the abstract function OnCantMove in MovingObject.
        //It takes a generic parameter T which in the case of Player is a Wall which the player can attack and destroy.
        protected override void OnCantMove <T> (T component)
        {
            //Set hitWall to equal the component passed in as a parameter.
            Wall hitWall = component as Wall;

            //Call the DamageWall function of the Wall we are hitting.
            hitWall.DamageWall (wallDamage);

            //Set the attack trigger of the player's animation controller in order to play the player's attack animation.
            animator.SetTrigger ("playerAttack");
        }


        //OnTriggerEnter2D is sent when another object enters a trigger collider attached to this object (2D physics only).
        private void OnTriggerEnter2D (Collider2D other)
        {
            //Check if the tag of the trigger collided with is Exit.
            if(other.tag == "Exit")
            {
                //Invoke the Restart function to start the next level with a delay of restartLevelDelay (default 1 second).
                Invoke ("Restart", restartLevelDelay);

                //Disable the player object since level is over.
                enabled = false;
            }

            //Check if the tag of the trigger collided with is GoodFood.
            else if(other.tag == "GoodFood")
            {
                //Add pointsPerGoodFood to the players current health total.
                health += pointsPerGoodFood;

                //Update healthText to represent current total and notify player that they gained points
                healthText.text = "+" + pointsPerGoodFood + " Health: " + health;

                //Call the RandomizeSfx function of SoundManager and pass in two eating sounds to choose between to play the eating sound effect.
                SoundManager.instance.RandomizeSfx (eatSound1, eatSound2);

                //Disable the GoodFood object the player collided with.
                other.gameObject.SetActive (false);
            }

            //Check if the tag of the trigger collided with is OkayFood.
            else if(other.tag == "OkayFood")
            {
                //Add pointsPerOkayFood to players health points total
                health += pointsPerOkayFood;

                //Update healthText to represent current total and notify player that they gained points
                healthText.text = "+" + pointsPerOkayFood + " Health: " + health;

                //Call the RandomizeSfx function of SoundManager and pass in two eating sounds to choose between to play the eating sound effect.
                SoundManager.instance.RandomizeSfx (eatSound3, eatSound4);

                //Disable the OkayFood object the player collided with.
                other.gameObject.SetActive (false);
            }
        }


        //Restart reloads the scene when called.
        private void Restart ()
        {
            //Load the last scene loaded, in this case Main, the only scene in the game.
            SceneManager.LoadScene(0);
        }


        //LoseHealth is called when an enemy attacks the player.
        //It takes a parameter loss which specifies how many points to lose.
        public void LoseHealth (int loss)
        {
            //Set the trigger for the player animator to transition to the playerHit animation.
            animator.SetTrigger ("playerHit");

            //Subtract lost health points from the players total.
            health -= loss;

            //Update the health display with the new total.
            healthText.text = "-"+ loss + " Health: " + health;

            //Check to see if game has ended.
            CheckIfGameOver ();
        }


        //CheckIfGameOver checks if the player is out of health points and if so, ends the game.
        private void CheckIfGameOver ()
        {
            //Check if health point total is less than or equal to zero.
            if (health <= 0) 
            {
                //Call the PlaySingle function of SoundManager and pass it the gameOverSound as the audio clip to play.
                SoundManager.instance.PlaySingle (gameOverSound);

                //Stop the background music.
                SoundManager.instance.musicSource.Stop();

                //Call the GameOver function of GameManager.
                GameManager.instance.GameOver ();
            }
        }
    }
}
Farhad Khan
  • 104
  • 2
  • 14
  • 1
    Have you assigned a `Text` component to the `public Text healthText` in the inspector? – I.B Mar 28 '17 at 21:22
  • @CNuts I have not, should it appear underneath the Player script in the inspector? at the moment things such as PointsPerGoodFood and Eat Sound 1 appear there but nothing for the healthText – Farhad Khan Mar 28 '17 at 21:35
  • Yes it should be there. Are you sure you saved your script with everything new you added. – I.B Mar 28 '17 at 21:38
  • @CNuts Thank you very much, I did as you said and the movement now works albeit incorrectly perhaps due to another error i have made elsewhere. – Farhad Khan Mar 28 '17 at 21:51
  • I'm happy it worked :) if you can't figure out that other error you could ask another question with it. – I.B Mar 28 '17 at 21:53
  • @CNuts I will do :) thanks again for your help and quick responses. – Farhad Khan Mar 28 '17 at 21:55
  • Per the marked duplicate, you have to make sure your fields are being initialized correctly, by their configuration in the inspector. See also the marked duplicate's marked duplicate for more extensive advice on how to debug, diagnose, and fix `NullReferenceException`. – Peter Duniho Mar 28 '17 at 22:25

1 Answers1

2

Check in the inspector if the healthText variable is linked to a UI text object. The link must be not set (None) or otherwise broken (Missing) if you are getting this exception.

Bizhan
  • 16,157
  • 9
  • 63
  • 101