简体   繁体   English

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

[英]Unity C# 2d Breakout Clone, Null Reference Exception

Okay so before I begin, Yes I have looked online to find this answer. 好的,在开始之前,是的,我已经上网寻找了答案。 I've followed advice on multiple other questions, gone through the unity documentation, and done more than a few web searches and nothing I've found so far has solved the error. 我遵循了关于其他多个问题的建议,通过了统一文档,并进行了多次网络搜索,到目前为止,我发现没有任何东西可以解决该错误。 I'm sure someone will take one look at this and know immediately what's wrong, but as for me, I just can't find it. 我敢肯定有人会看一眼并立即知道出了什么问题,但是对于我来说,我就是找不到。

Now that that's out of the way Here's the problem. 既然这样,那就不成问题了。 I'm making a Breakout clone and I had everything done, everything working properly. 我正在制作Breakout克隆,我已完成所有工作,一切工作正常。 I've got one static class that takes care of the scoring and score related variables, so that other scripts can access them easily. 我有一个静态类,负责处理评分和与分数相关的变量,以便其他脚本可以轻松访问它们。 I wanted to practice some basic saving and loading with PlayerPrefs, so I added something for highscores. 我想使用PlayerPrefs进行一些基本的保存和加载,因此我为高分添加了一些内容。 It's pretty much independent of the other classes, but once I finished that, I started getting a Null Reference Exception in a script that has been done for hours, and was working fine. 它几乎独立于其他类,但是一旦完成,我就开始在已经完成了几个小时并且工作正常的脚本中获取Null Reference Exception。

I appreciate any help you might have, and any tips for preventing this kind of error the next time around. 感谢您提供的任何帮助,以及下次如何防止此类错误的提示。 Sorry It's such a long question. 抱歉,这个问题太长了。

Here's the full error: 这是完整的错误:

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)

And here are the three scripts listed in said error: 这是上述错误中列出的三个脚本:

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

}

The problem is that Scoring is not a MonoBehaviour so the Awake method never gets called. 问题是Scoring不是MonoBehaviour,因此Awake方法永远不会被调用。 You can try to initialize the fields in a static constructor 您可以尝试在静态构造函数中初始化字段

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

or make the Awake method public and call it from another MonoBehaviour. 或将Awake方法公开,并从另一个MonoBehaviour中调用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM