Unity关卡选择按钮索引异常:点击始终返回最后索引
解决Unity关卡选择按钮索引错误的问题
你遇到的是闭包捕获变量的常见陷阱:在foreach循环中,委托捕获的是index变量的引用而非当前迭代的数值。循环结束后index的值已经等于imageTextures的总长度,所以所有按钮点击都会输出这个最终值。
下面是几种解决方法和更优实现方案:
方法一:循环内创建局部变量捕获当前值
在foreach循环内部,用局部变量保存当前迭代的索引和纹理,让委托捕获这些局部值,避免引用同一个外部变量:
void Start() { int index = 0; foreach (Texture2D texture in imageTextures) { // 用局部变量保存当前迭代的索引和纹理 int currentIndex = index; Texture2D currentTexture = texture; Image image = Instantiate(levelSelectPrefab, levelSelectPanel); Button button = image.GetComponent<Button>(); button.onClick.AddListener(delegate { StartGame(currentTexture, currentIndex); }); index++; } } public void StartGame(Texture2D jigsawTexture, int index) { Debug.Log("chosen puzzle index: " + index); }
方法二:改用for循环替代foreach
C# 5.0及以上版本中,for循环的迭代变量会在每次循环时重新创建,委托会捕获当前迭代的数值而非引用,直接使用即可:
void Start() { for (int index = 0; index < imageTextures.Length; index++) { Texture2D texture = imageTextures[index]; Image image = Instantiate(levelSelectPrefab, levelSelectPanel); Button button = image.GetComponent<Button>(); button.onClick.AddListener(delegate { StartGame(texture, index); }); } } public void StartGame(Texture2D jigsawTexture, int index) { Debug.Log("chosen puzzle index: " + index); }
更优实现:UI与数据绑定
创建独立的关卡项脚本,将索引、纹理等数据直接挂载到UI对象上,逻辑更清晰且便于后期扩展:
- 新建
LevelItem脚本:
using UnityEngine; using UnityEngine.UI; public class LevelItem : MonoBehaviour { public int levelIndex; public Texture2D levelTexture; private Button _levelButton; private void Awake() { _levelButton = GetComponent<Button>(); _levelButton.onClick.AddListener(OnLevelClicked); } private void OnLevelClicked() { // 可直接调用游戏逻辑方法,或通过单例/事件通知 // 示例:假设存在GameManager单例 GameManager.Instance.StartGame(levelTexture, levelIndex); } }
- 修改Start方法:
void Start() { for (int index = 0; index < imageTextures.Length; index++) { Image image = Instantiate(levelSelectPrefab, levelSelectPanel); LevelItem levelItem = image.GetComponent<LevelItem>(); if (levelItem != null) { levelItem.levelIndex = index; levelItem.levelTexture = imageTextures[index]; } } } // GameManager中的示例方法 public void StartGame(Texture2D jigsawTexture, int index) { Debug.Log("chosen puzzle index: " + index); }
这种方式将UI元素与对应的数据、逻辑绑定,后续添加关卡锁定、星级展示等功能时,只需在LevelItem中扩展即可,维护性更强。
内容的提问来源于stack exchange,提问作者thumbtackthief
相关产品推荐
相关产品推荐

