【问题标题】:Panel/Sprites won't update after being set inactive then reactivated面板/精灵在设置为非活动然后重新激活后不会更新
【发布时间】:2020-03-28 12:56:56
【问题描述】:

我已经遍历了整个故障树,试图诊断这一点,但没有任何乐趣。

我正在用 Unity/C# 编写一个 2D 纸牌游戏。我有四个面板(每个玩家一个),用于保存每个玩家的牌、姓名、弃牌堆等。当用户想要更改选项时,我需要在播放器面板上弹出一个对话框面板。出于某种原因,我无法让弹出窗口出现在卡片精灵上(它确实出现在其他元素上:内部面板、图像、文本框等)。我尝试调整对话框面板的 Zpos,但没有任何变化。这是一个问题,但它会导致一个更令人担忧的问题。

更大的问题是这个。由于选项面板不会显示在玩家卡片的前面,我想我只是停用玩家面板,显示对话框,然后停用它并在关闭时重新激活玩家面板。这很好用:对于三个面板。第四个面板恢复到之前的状态,但其上的图形将不再更新。

我已经调试并发现新卡正在正确处理(精灵名称更改等),丢弃堆正在更新,玩家的名字随着游戏的进展被突出显示/取消突出显示,但没有一个它出现了!它在视觉上停留在我停用它时的状态。

进一步调查,我已经确定,无论我是通过检查器(将这些事件附加到按钮单击)还是通过检查器执行此操作(将这些事件附加到按钮单击),或者在我停用并重新激活该播放器面板时,都会出现错误脚本。我什至不必打开选项对话框:我将 SetActive(false/true) 语句放在我的游戏代码中,它会立即终止该面板的图形更新。精灵、文本等保持在我停用时的状态并且不会更新。

    player3Obj.gameObject.SetActive(false)
    player3Obj.gameObject.SetActive(true);

对其他三个面板执行此操作没有任何效果并且工作正常。我看不出面板 4 有什么不同。事实上,我只能停用其中一个卡片精灵,当我重新打开它时,它现在“卡住”并且不会更新,即使该玩家的所有其他卡片手会。如果我停用/重新激活其中一个文本字段,则相同。它将不再更新,但其他一切都会更新。

我没有遇到异常错误或任何问题,但这在我看来像是某种内存问题,尽管我无法想象是什么问题。它出现在我的 Android 版本中,不,它不是特定于我的机器的。我提出这个问题,希望有人看到类似的东西。

如果没有别的,也许有人可以告诉我如何让我的选项面板显示在卡片精灵上。但我讨厌留下一个未诊断的问题:他们有办法回来咬人。

更新

这是未显示的代码。 cardBackSprit 值正在正确更新,gameObjectSprite 也是如此,但屏幕上的图像没有改变:

void DrawCardBitmap2(int Player, int cardSpot, int cardIndex)
{
    string spriteObjectName;

    spriteObjectName = "Sprite_Player" + Player + "_" + cardSpot;
    gameObjectSprite = GameObject.Find(spriteObjectName);
    gameObjectSprite.GetComponent<SpriteRenderer>().sprite = cardBackSprite;
}

【问题讨论】:

  • 在您更新面板的位置显示您的代码。我们无法调试您的话。
  • 能否提供停用和重新激活时未更新的面板的所有代码?

标签: unity3d


【解决方案1】:

这里有很多东西要解压。让我们将您的帖子分解为一系列问题:

1。我无法让弹出窗口出现在卡片精灵上

听起来您在 Unity 中使用 UI Canvas 来处理玩家的信息面板,而使用 gameObjects 来处理其他元素。这很好,但 UI Canvas 的排序顺序与标准游戏对象有点不同。

画布中的 UI 元素的绘制顺序与它们在层次结构中出现的顺序相同。首先绘制第一个孩子,然后绘制第二个孩子,依此类推。如果两个 UI 元素重叠,则后面的元素将出现在前面的元素之上。

为了让您的弹出窗口出现在画布中的其他元素之上,它们需要在场景的画布层次结构中更高。

重要提示:设置为任何屏幕空间渲染模式的画布将渲染场景中的其他游戏对象。设置为世界空间的画布将在场景中的世界位置进行渲染。唯一使用 Z 位置选择排序顺序的渲染模式是 World Space,但这不是我推荐的解决问题的方法。

我推荐的解决方案: 将您的 UI 分解为多个不同的画布。具体来说,将弹出窗口移动到不同的画布上,并将其放置在场景层次结构中高于卡片精灵的位置。当您启用/禁用或移动弹出窗口时,它现在将出现在卡片精灵上方。

2。四个面板(每个玩家一个)持有卡片

从上下文和您的一些代码来看,您的 UI 画布中似乎有 SpriteRenderers。众所周知,这是一个复杂的渲染问题。 Common advice 涉及使用 2 个摄像头进行渲染,并使用摄像头深度来提升 UI 元素上的精灵。但是,重新设计 UI 画布可能更简单。

3。在运行时使用 GameObject.Find 和复杂字符串

GameObject.Find 性能不高,也不健壮。它查看场景中的所有元素并返回它找到的第一个具有该名称的对象。

这带来了一些问题:

  • 您的层次结构中不能有同名的游戏对象,即使它们嵌套在不同的位置。
  • CPU 周期被浪费在搜索所有对象上。
  • 对象名称的隐藏依赖项仅在运行时显示。

Here's a great blog post on some better practices. 我推荐使用 [SerializeField] 属性并通过检查器进行配置。

4。当其中的对象发生变化时,Canvas 不会更新

您可以考虑在 LateUpdate() 中调用 Canvas.ForceUpdateCanvases()。这更像是一种 hack,而不是实际的解决方案,但如果这解决了您的问题,则可能是画布渲染的问题。如果这不能解决您的问题,那么这个问题很可能在您的代码中的其他地方,目前没有提供。

画布在一帧结束时,即在渲染之前执行其布局和内容生成计算,以确保它基于该帧期间可能发生的所有最新更改。这意味着在开始回调和第一次更新回调中,画布下的布局和内容可能不是最新的。

【讨论】:

  • 很棒的信息,谢谢。这是我的第一个 Unity 项目,所以我还在学习中。我没有尝试过多个画布,但听起来这可能是首选方法。我会试一试。让我知道走这条路是否有什么需要提防的。现在,我将精灵的不透明度设置为 0。一个可怕的 kluge,但它使我能够继续工作。哦,非常感谢您提供最佳实践的链接。正是我需要的解释级别!
  • 嗯...我有一个关于“最佳实践”链接的问题,Erik。我看到了使用“public”或“[SerializeField] private”的优势,因为我可以使用 Inspector 来连接对象,而不是使用 Find & GetComponent 和硬编码名称。但是如何在其他脚本中访问这些变量?好像我又回到了在这些脚本中使用 Find 。我通常会使用静态名称来避免这种情况,但是我似乎无法使用 Inspector,我又回到在第一个脚本中使用硬编码名称。我错过了什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-17
相关资源
最近更新 更多