You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:07:26