【问题标题】:Unity3D invisible Canvas performanceUnity3D 隐形 Canvas 性能
【发布时间】:2017-10-31 12:13:28
【问题描述】:

我正在开发一个 2d 菜单重的手机游戏,它使用了很多画布、面板、弹出窗口等。一开始我的所有菜单都处于活动状态,但只有用户可以使用的菜单位于截锥体(即,其他的只是翻译出来的)。然后我切换到停用用户看不到的菜单,只是为了提高游戏性能。然而,这给我带来了许多不便,例如取消和重新激活游戏对象时重置 Animator 组件中的状态变量。

那么最好的方法是什么?停用暂时未使用的画布是否值得,或者 Unity 会自动剪掉位于截锥体之外的 UI,因此基本上没有性能成本?

【问题讨论】:

    标签: android ios performance unity3d


    【解决方案1】:

    正如您所说,您的游戏菜单繁重,即使禁用/启用也会导致开销。这是我在过去的一个项目中遇到过的问题。

    一个建议是在您的菜单对象上使用Canvas Group 并更改它们的 alpha(0 = 关闭,1 = 打开)、Interactable 和 BlockRaycasts 参数。

    如果您在每个菜单/面板上都有菜单脚本,只需在打开/关闭时禁用/启用它。

    更新:

    Canvas Group 的典型用途是:

    • 通过在 Window 的 GameObject 上添加 Canvas Group 并控制其 Alpha 属性来淡入或淡出整个窗口。
    • 通过将 Canvas Group 添加到父 GameObject 并将其 Interactable 属性设置为 false,使整套控件不可交互(“灰显”)。
    • 通过在元素或其父元素之一上放置 Canvas Group 组件并将其 Block Raycasts 属性设置为 false,使一个或多个 UI 元素不阻止鼠标事件。

    其他参考资料:

    https://www.youtube.com/watch?v=wbmjturGbAQ

    https://github.com/Unitarian/Unity-Extensions/tree/master/Menus

    希望对你有帮助

    【讨论】:

    • 每个菜单都有自己的画布组件,但它们都有不同的脚本。仅停用画布而不是游戏对象就足以提高性能吗?这样脚本可以继续运行,例如动画组件不会重置其变量。或者在这种情况下使用 CanvasGroup 组件是否有实际好处?
    • 建议在父对象上放置一个画布,因为它将获得 ui Raycast 等。并且 CanvasGroup 专门用于服务菜单对象,从其公开的属性中可以看出。如果您不想禁用菜单脚本,只需在 Open()/Close() 方法中设置画布组,如我在回答中所述。
    • 以确保正确理解您:我应该向所有单独菜单(例如选项菜单)添加一个canvasgroup,并且只要播放器都不应该看到选项,我就可以设置Alpha,交互和互操作BlocksRaycasts 全部为 0?这对我来说似乎很奇怪,因为通常您希望在优化性能时避免透明。
    • 没错。这与设置任何对象的透明度不同。您想要使用 CanvasGroup 的唯一原因是如果您的菜单(主/选项菜单)有很多子菜单,并且启用/禁用将强制子菜单上的许多组件执行某些操作。 (就像 ScrollRect 在性能方面是可怕的)。检查我对 CanvasGroup 用途的​​更新答案。
    【解决方案2】:

    如何创建类似的界面

    public interface IOpenable
        {
    
            bool IsClosed { get; set; }
    
            void OpenWindow();
        }
    }
    

    然后让每个元素都订阅某个控制器,并且该控制器可以像这样处理所有事情

    public class MenuController: MonoBehaviour
    {
        public List<IOpenable> MenuList;
    
        void Awake()
        {
            MenuList = new List<IOpenable>();
        }
        public void TryClose(IOpenable sender)
        {
            foreach (var i in MenuList)
            {
                if (!i.IsClosed && !sender.Equals(i))
                            i.OpenWindow();         
            }
        }
    }
    

    这样您可以在打开新窗口时尝试关闭所有其他不需要的窗口。这只是一个粗略的想法,但对我来说似乎干净又快速。

    【讨论】:

    • 这样的界面可以稍微统一打开和关闭过程,但它并不能从一开始就消除不便。这里的主要问题是,停用是否真的值得,或者每个剪辑的画布是否只需要 1 个取消的渲染调用或其他东西(我不知道它是如何工作的细节)并且在运行时基本上不会产生任何成本?跨度>
    • 根据 [link]unity3d.com/learn/tutorials/topics/best-practices/…,如果我们不需要它们,建议禁用包含任何画布或 ui 对象的游戏对象。我自己现在还不知道画布的批处理是如何工作的,但是如果与网格相同,那么您可能会为每个画布调用 1 个绘制调用。但是您可以使用 Unity 中的分析器工具轻松检查它。
    • 我在对象上有脚本,但我不想停用这些脚本。这就是为什么我正在寻找解决方案,例如只禁用隐藏菜单上的画布组件,但正如我现在所了解的,并非每个菜单都应该有自己的画布。
    【解决方案3】:

    根据this Unity optimization document,禁用画布(不是停用其游戏对象!)是隐藏它的最佳方法。

    禁用和重新启用画布很便宜。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-21
      • 2015-08-02
      • 2018-09-26
      • 2014-06-29
      • 2011-05-11
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多