Unity C# 2d Breakout Clone,空引用异常

Unity C# 2d Breakout Clone, Null Reference Exception

好的,在我开始之前,是的,我在网上查找了这个答案。我听从了关于其他多个问题的建议,浏览了统一文档,并进行了多次网络搜索,但到目前为止我没有发现任何解决错误的方法。我敢肯定有人会看一眼就知道出了什么问题,但是对于我来说,我就是找不到它。

现在已经解决了这就是问题所在。我正在制作一个 Breakout 克隆,我已经完成了所有工作,一切正常。我有一个静态 class 负责处理评分和分数相关的变量,以便其他脚本可以轻松访问它们。我想用 PlayerPrefs 练习一些基本的保存和加载,所以我添加了一些高分。它几乎独立于其他 classes,但是当我完成它后,我开始在一个已经完成数小时并且工作正常的脚本中出现 Null Reference Exception。

感谢您提供的任何帮助,以及任何防止下次出现此类错误的提示。抱歉,问题太长了。

这是完整的错误:

NullReferenceException: Object reference not set to an instance of an object
MenuManager.ActivateLose () (at Assets/Scripts/MenuScripts/MenuManager.cs:31)
Scoring.CheckGameOver () (at Assets/Scripts/Scoring.cs:64)
Scoring.LifeLost () (at Assets/Scripts/Scoring.cs:51)
DeadZone.OnTriggerEnter2D (UnityEngine.Collider2D other) (at Assets/Scripts/DeadZone.cs:22)

下面是上述错误中列出的三个脚本:

using UnityEngine;
using System.Collections;

public class DeadZone : MonoBehaviour 
{

    public GameObject ballPrefab;
    public Transform paddleObj;

    GameObject ball;

    void Update () 
    {
        ball = GameObject.FindGameObjectWithTag("Ball");
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        //if the object that entered the trigger is the ball
        if(other.tag == "Ball")
        {
            Scoring.LifeLost();
            //destroy it, and instantiate a new one above where the paddle currently is
            Destroy(ball);
            paddleObj.transform.position = new Vector2(0, -2.5f);
            (Instantiate(ballPrefab, new Vector2(paddleObj.transform.position.x, paddleObj.transform.position.y + 0.3f), Quaternion.identity) as GameObject).transform.parent = paddleObj;
        }
    }
}

using UnityEngine;
using System.Collections;

public static class Scoring
{

    public static GameObject scoreValue;
    public static TextMesh scoreText;
    public static int score;

    static int multiplier = 0;
    static int consecutiveBreaks = 0;
    static int lives = 3;
    static int totalBricks;
    static int remainingBricks;

    public static GameObject menuManagerObj;
    public static MenuManager menuManager = new MenuManager();

    static void Awake()
    {
        scoreValue = GameObject.FindGameObjectWithTag("Scoring");
        scoreText = scoreValue.GetComponent<TextMesh>();
        menuManagerObj = GameObject.FindGameObjectWithTag("MenuManager");
        //menuManager = menuManagerObj.GetComponent<MenuManager>();
    }

    public static void BrickDestroyed()
    {
        if(scoreValue == null && scoreText == null)
        {
            scoreValue = GameObject.FindGameObjectWithTag("Scoring");
            scoreText = scoreValue.GetComponent<TextMesh>();
        }

        remainingBricks--;
        consecutiveBreaks++;
        multiplier = 1 + (consecutiveBreaks % 5);
        score += 10 * multiplier;
        CheckGameOver();
        scoreText.text = score + "";
    }

    public static void LifeLost()
    {
        consecutiveBreaks = 0;
        multiplier = 1;
        score -= 100;
        lives--;
        LivesDisplay.SetLives(lives);
        CheckGameOver();
        scoreText.text = score + "";
    }

    public static void SetBrickCount(int brickCount)
    {
        totalBricks = brickCount;
        remainingBricks = totalBricks;
    }

    public static void CheckGameOver()
    {
        //lose condition
        if(lives < 0) menuManager.ActivateLose();

        //win condition
        if(remainingBricks == 0) menuManager.ActivateWin();

    }

}

using UnityEngine;
using System.Collections;

public class MenuManager :  MonoBehaviour
{

    public GameObject winMenu;
    public GameObject loseMenu;
    public GameObject pauseMenu;
    public HighScoreManager highScores;

    bool isGamePaused = true;

    void Awake()
    {
        winMenu = GameObject.FindGameObjectWithTag("Win");
        loseMenu = GameObject.FindGameObjectWithTag("Lose");
        pauseMenu = GameObject.FindGameObjectWithTag("Pause");
    }

    public void ActivateWin()
    {
        Time.timeScale = 0f;
        winMenu.transform.position = new Vector3(0, 0, -1);
        highScores.CompareToHighScores(Scoring.score);
    }

    public void ActivateLose()
    {
        Time.timeScale = 0f;
        loseMenu.transform.position = new Vector3(0, 0, -1);
    }

    void ActivatePause()
    {
        if(isGamePaused)
        {
            Time.timeScale = 0f;
            pauseMenu.transform.position = new Vector3(0, 0, -1);
        }
        else
        {
            Time.timeScale = 1f;
            pauseMenu.transform.position = new Vector3(35, 0, -1);
        }
        isGamePaused = !isGamePaused;
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Escape))
        {
            ActivatePause();
        }
    }

}

问题是 Scoring 不是 MonoBehaviour,因此永远不会调用 Awake 方法。您可以尝试在静态构造函数中初始化字段

static Scoring()
{
    scoreValue = GameObject.FindGameObjectWithTag("Scoring");
    scoreText = scoreValue.GetComponent<TextMesh>();
    menuManagerObj = GameObject.FindGameObjectWithTag("MenuManager");
    //menuManager = menuManagerObj.GetComponent<MenuManager>();
}

或者创建 Awake 方法 public 并从另一个 MonoBehaviour 调用它。