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

Unity ARFoundation多图像跟踪Canvas仅显示一次问题求助

问题分析与修复方案

核心问题

  1. 延迟调用冲突:Invoke的0.5秒延迟会导致状态判断滞后,比如图像刚被跟踪就丢失时,可能先后触发EnableMe和DisableMe,最终Canvas状态不符合预期。
  2. 无效的trackedImage重置:DisableMe中重置的trackedImage是foreach循环内的局部变量,而非类的成员变量,对后续跟踪判断完全没有影响。
  3. 缺少跟踪状态记录:没有记录当前正在跟踪的图像标识,无法区分新跟踪事件和重复触发,导致Canvas无法反复显示。

修复代码

首先在类中添加成员变量,用于记录跟踪状态和管理延迟操作:

// 记录当前正在跟踪的椅子图像名称
private string currentTrackedChairName;
// 管理延迟调用的协程,避免状态冲突
private Coroutine enableCoroutine;
private Coroutine disableCoroutine;

然后修改核心逻辑方法,替换Invoke为可控性更强的协程,并增加状态判断:

private void UpdateTrackedImages(IEnumerable<ARTrackedImage> trackedImages)
{
    bool hasTrackedChair = false;
    string trackedChairName = null;

    // 遍历找到当前正在跟踪的目标椅子
    foreach (var trackedImage in trackedImages)
    {
        if (Chairs.Contains(trackedImage.referenceImage.name) && trackedImage.trackingState == TrackingState.Tracking)
        {
            hasTrackedChair = true;
            trackedChairName = trackedImage.referenceImage.name;
            break; // 找到一个跟踪目标即可,避免多图像冲突
        }
    }

    // 根据跟踪状态处理Canvas显示/隐藏
    if (hasTrackedChair)
    {
        // 仅当跟踪的是新图像,或之前无跟踪时才触发显示
        if (currentTrackedChairName != trackedChairName)
        {
            // 取消可能存在的隐藏延迟
            if (disableCoroutine != null)
            {
                StopCoroutine(disableCoroutine);
                disableCoroutine = null;
            }
            // 启动显示延迟协程
            enableCoroutine = StartCoroutine(EnableCanvasAfterDelay(0.5f, trackedChairName));
        }
    }
    else
    {
        // 仅当之前有跟踪目标时才触发隐藏
        if (!string.IsNullOrEmpty(currentTrackedChairName))
        {
            // 取消可能存在的显示延迟
            if (enableCoroutine != null)
            {
                StopCoroutine(enableCoroutine);
                enableCoroutine = null;
            }
            // 启动隐藏延迟协程
            disableCoroutine = StartCoroutine(DisableCanvasAfterDelay(0.5f));
        }
    }
}

private IEnumerator EnableCanvasAfterDelay(float delay, string chairName)
{
    yield return new WaitForSeconds(delay);
    canvas.enabled = true;
    currentTrackedChairName = chairName;
    // 根据当前跟踪的图像更新按钮信息
    UpdateButtonInfo(chairName);
}

private IEnumerator DisableCanvasAfterDelay(float delay)
{
    yield return new WaitForSeconds(delay);
    canvas.enabled = false;
    currentTrackedChairName = null;
}

// 根据图像名称动态更新按钮的文本和点击事件
private void UpdateButtonInfo(string chairName)
{
    switch(chairName)
    {
        case "Chair1":
            button.text = "查看椅子1详情";
            button.onClick.RemoveAllListeners();
            button.onClick.AddListener(ShowChair1Info);
            break;
        case "Chair2":
            button.text = "查看椅子2详情";
            button.onClick.RemoveAllListeners();
            button.onClick.AddListener(ShowChair2Info);
            break;
        // 其他椅子的逻辑补充
    }
}

// 示例:椅子1详情展示逻辑
private void ShowChair1Info()
{
    // 自定义逻辑
}

// 示例:椅子2详情展示逻辑
private void ShowChair2Info()
{
    // 自定义逻辑
}

关键改进点

  • 协程替代Invoke:可以随时取消未执行的延迟操作,避免状态冲突,比如图像刚触发显示就丢失时,能直接切换到隐藏逻辑。
  • 跟踪状态记录:通过currentTrackedChairName记录当前跟踪的图像,确保只有状态变化时才更新Canvas,支持反复显示不同图像对应的Canvas。
  • 按钮动态更新:在Canvas显示时,根据跟踪的图像名称同步更新按钮的文本和点击事件,满足“按钮接收不同信息”的需求。
  • 修复无效重置:不再操作局部变量trackedImage,改用成员变量控制跟踪状态,彻底解决重置无效的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:05:22