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