4

我在几个地方问过这个问题,但还没有完全弄清楚,所以也许这里的一些聪明人会知道如何解决这个问题。

在项目中维护深层嵌套的预制件层次结构的最佳方法是什么?比如说,我们有几个 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 并丢失 prefab 引用
    • 优点:保证组件预制参考得到维护,允许视图之间存在细微差异(恕我直言,这实际上是一个问题,因为这些应该属于配置层)
  3. 将整个 storeView 保存为预制件
    • 缺点:扩展性非常大,使得迭代新功能或小的 UX 更改更耗时(额外的 QA、验收测试等......)
    • 优点:这是一个快速而肮脏的解决方案,适用于小型项目
  4. 使用 Prefab Evolution 或类似的
    • 缺点:我假设该包将被路线图上的嵌套预制件淘汰?需要取决于 3rd 方代码并且可能不够灵活(这里有什么意见吗,伙计们?)
    • 优点:从我看到的许多(混合的)评论中,有些评论非常积极。然而,项目越复杂,这些评论就越不积极。
  5. 编写一堆自定义编辑器脚本:
    • 缺点:耗时,而且 - 似乎应该由平台提供,即使它主要处理游戏
    • 优点:完全控制行为,开发人员可以根据设计师的反馈进行改进。有人可能会争辩说,将实现、测试和对设计人员友好的工具作为功能要求进行自律听起来像是一种良好的设计实践(从而减少了技术债务,更容易维护)

这是我个人的,诉理想主义,不切实际的解决方案*:

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

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

  • 请不要以为我期望 Unity 提供所有这些,但这是可能的方向之一,即使其中 1% 是正确的。

澄清一下,这并不是对 Unity 的抱怨,作为一名以前使用移动(原生)和 Web 工作的开发人员,我发现它解决了我的许多问题,以及其中一些解决方案的简单程度,这给我留下了深刻的印象。

4

1 回答 1

1

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

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

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

通过一些命名约定,您可以实现像storeView = UIStoreView.Instance();.

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

于 2016-12-05T21:29:31.160 回答