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

Unity中for循环生成带按钮苹果时点击弹窗索引越界问题及解决

Unity 循环生成带按钮苹果时回调索引越界问题解决

问题场景

需要在运行时从列表生成20个附带按钮的苹果,点击按钮弹出对应苹果的信息。但使用for循环实现后,点击按钮会触发ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.错误,弹窗无法正常显示对应信息。

原实现代码

public class AppleInventory : MonoBehaviour
{
   [SerializeField] private ApplesScript applPrefab;
   [SerializeField] private Transform applParent;
   
    public ApplesScript CreateApples()
    {
        var appl = Instantiate(applPrefab, applParent);

        for (int i = 0; i < apples.Count; i++)
        {
            appl = Instantiate(applPrefab, applParent);
            appl.InitAppleVisualization(apples[i].GetAppleSprite());
            appl.AssignAppleButtonCallback(() => CreateApplePopUpInfo(i));
            appl.transform.position = new Vector2(apples[i].x, apples[i].y);
        }

        return appl;
    }
}

问题验证

移除for循环,指定固定索引值(如i=7)时,代码可正常生成苹果并显示对应弹窗信息,确认问题出在for循环与回调的结合逻辑上。测试代码如下:

public ApplesScript CreateApples()
{
   int i = 7;

   var appl = Instantiate(applPrefab, applParent);
   appl.InitAppleVisualization(apples[i].GetAppleSprite());
   appl.AssignAppleButtonCallback(() => CreateApplePopUpInfo(i));
   appl.transform.position = new Vector2(apples[i].x, apples[i].y);

   return appl;
}

问题原因

这是C#闭包的变量捕获特性导致的:循环中的i是同一个变量,所有回调都会捕获这个变量的引用。当循环结束后,i的值会变成apples.Count(超出列表索引范围),此时点击按钮触发回调,就会出现索引越界异常。

解决方法

方法一:拆分循环与创建逻辑

将for循环单独抽取到一个方法中,每次循环调用生成单个苹果的方法并传入当前索引。由于方法参数是值类型,每次调用会创建i的副本,回调捕获的是这个独立的副本,避免了索引值被后续循环修改。修改后的代码如下:

public void StarterOfApplesCreation()
{
   for (int i = 0; i < apples.Count; i++)
   {
       CreateApples(i);
   }
}

public void CreateApples(int i)
{
   var appl = Instantiate(applPrefab, applParent);
   appl.InitAppleVisualization(apples[i].GetAppleSprite());
   appl.AssignAppleButtonCallback(() => CreateApplePopUpInfo(i));
   appl.transform.position = new Vector2(apples[i].x, apples[i].y);
}

方法二:循环内创建局部变量保存索引

在循环内部创建局部变量保存当前索引,让回调捕获这个独立的变量副本,同样可以解决问题:

public ApplesScript CreateApples()
{
    var appl = Instantiate(applPrefab, applParent);

    for (int i = 0; i < apples.Count; i++)
    {
        int currentIndex = i; // 创建局部变量保存当前索引
        appl = Instantiate(applPrefab, applParent);
        appl.InitAppleVisualization(apples[currentIndex].GetAppleSprite());
        appl.AssignAppleButtonCallback(() => CreateApplePopUpInfo(currentIndex));
        appl.transform.position = new Vector2(apples[currentIndex].x, apples[currentIndex].y);
    }

    return appl;
}

内容的提问来源于stack exchange,提问作者Alesf28

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:40:34