Unity记忆卡片谜题点击按钮触发空引用异常报错求助
Unity记忆卡片游戏NullReferenceException问题解决
问题根源分析
报错指向的UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject存在空引用风险,可能的原因包括:
- 场景中没有EventSystem对象(UI交互必须依赖它)
- 点击触发时
currentSelectedGameObject未被正确赋值 - 按钮的名字不是合法整数,导致
int.Parse失败
另外,依赖对象名获取索引的方式本身就不可靠,一旦按钮重命名就会触发错误,这是设计上的缺陷。
修复方案
1. 确保场景中有EventSystem
右键Hierarchy面板 -> UI -> EventSystem,创建默认的EventSystem对象(如果没有的话)。
2. 替换按钮点击的索引传递方式
不要通过EventSystem.current获取点击的按钮,而是在添加监听时直接传递按钮在列表中的索引,这是更可靠的实现方式:
修改AddListeners方法:
void AddListeners() { for (int i = 0; i < buttons.Count; i++) { int index = i; // 捕获当前循环索引,避免闭包陷阱 buttons[i].onClick.AddListener(() => PickButton(index)); } }
修改PickButton方法,直接接收索引参数:
void PickButton(int buttonIndex) { // 防止重复点击同一按钮 if ((_firstGuess && buttonIndex == _firstGuessIndex) || buttons[buttonIndex].image.sprite != startImage) { return; } if (!_firstGuess) { _firstGuess = true; _firstGuessIndex = buttonIndex; _firstGuessName = spritePuzzles[_firstGuessIndex].name; buttons[_firstGuessIndex].image.sprite = spritePuzzles[_firstGuessIndex]; } else if (!_secondGuess) { _secondGuess = true; _secondGuessIndex = buttonIndex; _secondGuessName = spritePuzzles[_secondGuessIndex].name; buttons[_secondGuessIndex].image.sprite = spritePuzzles[_secondGuessIndex]; _guessCount++; StartCoroutine(PuzzleMatch()); } }
3. 其他潜在问题修复
- 在
Start方法中调整执行顺序,先添加图片再打乱,避免逻辑错误:
void Start() { GetButtons(); AddImages(); // 先添加图片再打乱 RandomShuffle(spritePuzzles); AddListeners(); // 最后添加监听 _gameGuesses = spritePuzzles.Count / 2; }
- 给
door对象添加空引用检查,避免游戏结束时报错:
void IsGameFinished() { _correctGuesses++; if (_correctGuesses == _gameGuesses && door != null) { door.SetActive(false); } }
修改后的完整脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class MemoryPuzzleController : MonoBehaviour { public List<Button> buttons = new List<Button>(); public List<Sprite> spritePuzzles = new List<Sprite>(); public Sprite[] puzzles; public GameObject door; public Sprite startImage; public bool _firstGuess, _secondGuess; public int _guessCount; public int _correctGuesses; public int _gameGuesses; public int _firstGuessIndex, _secondGuessIndex; public string _firstGuessName, _secondGuessName; void Start() { GetButtons(); AddImages(); RandomShuffle(spritePuzzles); AddListeners(); _gameGuesses = spritePuzzles.Count / 2; } void GetButtons() { GameObject[] objects = GameObject.FindGameObjectsWithTag("PuzzleButton"); for(int i = 0; i < objects.Length; i++) { Button btn = objects[i].GetComponent<Button>(); if (btn != null) { buttons.Add(btn); btn.image.sprite = startImage; } } } void AddImages() { int looper = buttons.Count; if (looper == 0 || puzzles == null || puzzles.Length == 0) { Debug.LogError("按钮列表为空或谜题图片数组未赋值!"); return; } int index = 0; for (int i = 0; i < looper; i++) { if (index == looper / 2) { index = 0; } spritePuzzles.Add(puzzles[index]); index++; } } void AddListeners() { for (int i = 0; i < buttons.Count; i++) { int index = i; buttons[i].onClick.AddListener(() => PickButton(index)); } } void PickButton(int buttonIndex) { if ((_firstGuess && buttonIndex == _firstGuessIndex) || buttons[buttonIndex].image.sprite != startImage) { return; } if (!_firstGuess) { _firstGuess = true; _firstGuessIndex = buttonIndex; _firstGuessName = spritePuzzles[_firstGuessIndex].name; buttons[_firstGuessIndex].image.sprite = spritePuzzles[_firstGuessIndex]; } else if (!_secondGuess) { _secondGuess = true; _secondGuessIndex = buttonIndex; _secondGuessName = spritePuzzles[_secondGuessIndex].name; buttons[_secondGuessIndex].image.sprite = spritePuzzles[_secondGuessIndex]; _guessCount++; StartCoroutine(PuzzleMatch()); } } IEnumerator PuzzleMatch() { yield return new WaitForSeconds(.5f); if (_firstGuessName == _secondGuessName && _firstGuessIndex != _secondGuessIndex) { yield return new WaitForSeconds(.5f); buttons[_firstGuessIndex].interactable = false; buttons[_secondGuessIndex].interactable = false; buttons[_firstGuessIndex].image.color = new Color(0, 0, 0, 0); buttons[_secondGuessIndex].image.color = new Color(0, 0, 0, 0); IsGameFinished(); } else { yield return new WaitForSeconds(.5f); buttons[_firstGuessIndex].image.sprite = startImage; buttons[_secondGuessIndex].image.sprite = startImage; } yield return new WaitForSeconds(.5f); _firstGuess = _secondGuess = false; } void IsGameFinished() { _correctGuesses++; if (_correctGuesses == _gameGuesses && door != null) { door.SetActive(false); } } void RandomShuffle(List<Sprite> shuffleList) { for (int i = 0; i < shuffleList.Count; i++) { Sprite temp = shuffleList[i]; int randomIndex = Random.Range(0, shuffleList.Count); shuffleList[i] = shuffleList[randomIndex]; shuffleList[randomIndex] = temp; } } }
内容的提问来源于stack exchange,提问作者MyNameIsToday
相关产品推荐
相关产品推荐

