对象引用未设置为对象的实例 C# Unity 教程

Object reference not set to an instance of an object C# Unity tutorial

我正在使用 unity 提供的 2D rouge-like 教程创建游戏。除了运动之外,一切都按预期工作。游戏运行时出现单个error。

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

这是导致错误的代码行: healthText.text = "Health: " + health;

整个脚本的代码如下:

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 ();
            }
        }
    }
}

如果 healthText 变量被 link 编辑到 UI 文本对象,请检查检查器。如果出现此异常,则 link 不得设置 (None) 或以其他方式损坏 (Missing)。