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

Unity销毁Button后EventSystem访问已销毁对象引发异常求助

问题解决:销毁Button后EventSystem持续访问已销毁对象的优雅方案

问题核心是:点击按钮销毁时,光标可能仍停留在按钮上,EventSystem的pointerEnter等指针状态引用了已销毁对象,后续每帧处理指针移动时尝试访问其transform导致空引用错误,阻塞其他UI交互。

以下是几种无需延迟销毁的优雅解决方案:


方案1:手动清理EventSystem的指针引用

直接找到当前InputSystemUIInputModule,重置指向待销毁按钮的所有指针状态,从根源切断EventSystem对已销毁对象的引用:

public void makeProgram(int i, Button button)
{
    // 清理EventSystem中关联当前按钮的指针数据
    var inputModule = EventSystem.current.currentInputModule as InputSystemUIInputModule;
    if (inputModule != null)
    {
        foreach (var pointer in inputModule.pointers)
        {
            var eventData = inputModule.GetExtendedPointerEventData(pointer.id);
            if (eventData.pointerEnter == button.gameObject)
            {
                eventData.pointerEnter = null;
                eventData.pointerPress = null;
                eventData.lastPointerPress = null;
            }
        }
    }

    // 原有创建逻辑
    GameObject obj = Instantiate(ProgramObject, programHolder);
    var programComp = obj.GetComponent<Program>();
    programs.Add(programComp);
    programComp.gameManager = this;
    obj.GetComponent<RectTransform>().localPosition = button.transform.localPosition;
    
    Destroy(button.gameObject);
}

方案2:先禁用按钮再销毁

通过禁用按钮的交互性和激活状态,让EventSystem自动忽略该对象,避免后续指针事件关联:

public void makeProgram(int i, Button button)
{
    // 先禁用按钮,让EventSystem不再将其视为可交互目标
    button.interactable = false;
    button.gameObject.SetActive(false);

    // 原有创建逻辑
    GameObject obj = Instantiate(ProgramObject, programHolder);
    var programComp = obj.GetComponent<Program>();
    programs.Add(programComp);
    programComp.gameManager = this;
    obj.GetComponent<RectTransform>().localPosition = button.transform.localPosition;
    
    // 可立即销毁,无需延迟
    Destroy(button.gameObject);
}

方案3:清空当前选中对象(针对按钮被选中的场景)

如果按钮处于EventSystem的选中状态,强制清空选中对象,避免残留引用:

public void makeProgram(int i, Button button)
{
    // 若当前按钮是选中状态,清空选择
    if (EventSystem.current.currentSelectedGameObject == button.gameObject)
    {
        EventSystem.current.SetSelectedGameObject(null);
    }

    // 原有创建逻辑
    GameObject obj = Instantiate(ProgramObject, programHolder);
    var programComp = obj.GetComponent<Program>();
    programs.Add(programComp);
    programComp.gameManager = this;
    obj.GetComponent<RectTransform>().localPosition = button.transform.localPosition;
    
    Destroy(button.gameObject);
}

推荐实践

优先结合方案1+方案2,既手动清理指针引用,又通过禁用按钮让EventSystem主动放弃关联,能彻底避免空引用问题,且无需依赖延迟销毁的妥协方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:47:18