在Unity3D中管理复杂的预制层次结构

时间:2016-12-05 17:22:51

标签: c# user-interface unity3d unity3d-gui unity3d-editor

我在几个地方问了这个问题,但还没有完全弄明白,所以也许这里的一些聪明人会知道如何处理这个问题。

在项目中维护预制件的深层嵌套层次结构的最佳方法是什么?比如,我们有一些GUI屏幕,由较小的通用组件组成。为简单起见,我们称之为前“视图”,后者称为“组件”。视图处理语义(例如库存视图,商店视图);组件是可配置的,但没有任何业务逻辑连接到它们(例如,一个按钮只关心它的OnTap回调/事件处理程序)。

可以嵌套视图和组件。

GUI视图需要在多个场景中重复使用。

Unity中这种方法的主要问题是,任何嵌套的层次结构一旦变成预制件,就会失去对其子预制件的引用,就像在这个(完全组成但仍然有效)的例子中一样:

- storeView - UIViewHeader - UIHeaderLabel<Text> - UIList - UIListItem - UIThumbnail - UITitleLabel<Text> - UISubTitleLabel<Text> - UIPrimaryButton<Button> - ...

我希望将所有这些小型UI *组件保存在单独的预制件中,同时保留storeView预制件,以便我可以轻松地将其添加到不同的场景中。不幸的是,在我们创建storeView预制件时,很快就会丢失所有UI *预制件引用。 鉴于此,我们可以尝试一种不同的方法,其中不是使用带有内容的storeView预制,而是将其保持为空并选择以下几个选项中的一个:

  1. 将行为附加到storeView并在运行时加载子预制件
    • 缺点:使设计人员的工作流程更加复杂,将复杂性放在脚本中,从开发角度来看也可能更容易出错
    • 专业人士:可以更轻松地在场景之间重复使用storeView,可以对组件预制件进行样式设置,全局修改
  2. 将storeView保留为空预制件,并在需要它的每个场景中重新组装
    • 缺点:组件需要手动连接,仍然很容易意外地保存整个storeView并丢失预制参考
    • 专业人员:保证维护组件预制件引用,允许视图之间存在细微差别(imho实际上是一个问题,因为这些应该属于配置层)
  3. 将整个storeView保存为预制件
    • 缺点:严重缩放,使新功能或小型UX更改的迭代更耗时(额外的QA,验收测试等......)
    • 专业人士:这是一个快速而肮脏的解决方案,适用于小型项目
  4. 使用Prefab Evolution或类似产品
    • 缺点:我认为包装将被Nested Prefabs淘汰,这是在路线图上?需要依赖第三方代码,可能不够灵活(这里有任何意见,伙计们?)
    • 专业人士:从我见过的很多(混合)评论中,有些评论非常积极。然而,项目越复杂,这些评论就越不正面。
  5. 写一堆自定义编辑器脚本:
    • 缺点:耗时,也 - 似乎应该由平台提供,即使它主要涉及游戏
    • 专业人士:完全控制行为,开发人员可以通过设计师的反馈进行改进。有人可能会说,对于实施,测试和设计师友好的工具作为功能要求的规范听起来像一个好的设计实践(导致技术债务减少,维护更容易)
  6. 这是我个人的,对理想主义的,不切实际的解决方案*:

    使用组件化架构,默认情况下,子预制参考存储在复杂的预制件中。在内部将它们视为UIView和移动(Cocoa)上的子视图,或React中的组件类或更好的功能组件 - React / Cycle / Elm /与FRP相关的任何东西(是的,我知道这些方法在很多方面都有所不同,但关键是可组合性,可以通过功能组合,装饰器等等来实现。)

    • 缺点:我认为我的困难来自于我缺乏Unity的经验,并且有一个更明显的,也许是惯用的解决方案(我很恳请:) :)
    • 专业人士:让测试和迭代新功能变得更容易,使预制件更强大,同时不会失去任何好处(如果我错了请纠正我,我仍然熟悉Unity)

    • 请不要认为我期待Unity的所有这些,但这是可能的方向之一,即使其中1%是真的。

    为了说清楚,这不是一个关于Unity的咆哮,作为一个以前使用移动(本机)和网络工作的开发人员,我发现它解决了我解决了多少问题,以及这些解决方案有多荒谬简单

1 个答案:

答案 0 :(得分:1)

我可能在单独的场景中维护复合视图。简单地将这些场景视为预制件,仅包含给定类的单个原型对象。

SceneManager.LoadSceneLoadSceneMode.Additive一起使用,您甚至可以创建一些静态工厂方法,例如:

public class UIStoreView
{
    public static UIStoreView Instance()
    {
        SceneManager.LoadScene("UIStoreView", LoadSceneMode.Additive);
        return GameObject.Find("UIStoreView");
    }
}

通过一些命名对话,您可以实现像storeView = UIStoreView.Instance();这样简单的事情。

不是通用/可扩展的东西,但至少你有一些轻量级/可维护的东西,直到他们推出嵌套的预制件(timeline uncertain,如他们所说)。