【问题标题】:Are there best practices for "Singletons" (persistent GameObjects) in Unity?Unity 中是否有“单例”(持久游戏对象)的最佳实践?
【发布时间】:2020-04-03 12:13:01
【问题描述】:

我对 Unity 还是很陌生,事实上 C# 也是如此!

我现在正在做的是:

  • 我有一个“单例”(它不是真正的单例,但这不是重点)GameObject 称为 GameManager,附有我的 GameManager.cs 脚本,其中包含大部分游戏信息(该教程文本已已显示,加载本地化文本的功能,加载最后一个场景...)
  • 作为GameManager 对象的子对象,我有不同类型的游戏对象,我也不想在加载时销毁,例如后处理配置文件、全局灯光、音频管理器、UI 画布(canvi?)和其他东西。 .

有很多关于 Unity 的优秀教程,它是一个很棒的社区,但我真的找不到任何关于 Unity 关于游戏对象管理的“最佳实践”的信息。

这是一个正确的方法吗?我将来会遇到这种方法的问题吗?我是否应该创建一个实现 Unity 的 DontDestroyOnLoad() 的通用类,并让我想要保留的对象继承自该类?有没有更好的办法?

目前它运行良好,但我想确保我没有以错误的方式执行此操作,并可能会破坏游戏的性能或稳定性。

非常感谢。

【问题讨论】:

  • 这完全是基于意见的,因为它甚至完全是controversial 如果应该使用单例模式根本! Unity 的DontDestroyOnLoad 使得开始在各处使用单例非常诱人,是的,有时您至少需要一个在我看来应该控制所有其余部分的方法。不要使用多个!
  • 单例模式本身并不是最佳实践。它被认为是反模式是有充分理由的。完全不需要单例。如果您正在编写可测试和可扩展的软件,您应该更喜欢遵循依赖注入模式。通过这种方式,您可以将共享实例注入相关类。这实现了 Singleton 的所有优点,而没有 Singleton 的所有缺点(例如,您不能模拟静态代码)。单例模式的缺点是事实而非意见。
  • 尽管负面事实确实是基于意见的,但您仍然可以或应该使用这种模式。如果你能付出代价(忍受所有的缺点)你可能很高兴。由于像MEF 这样的框架非常易于使用,因此单例可能永远不值这个价。 MEF 是一个功能强大且易于使用的框架,支持依赖注入和生命周期管理。
  • @BionicCode 单例模式有很多问题。但是建议 DI 更好就是忽略上下文:这是针对 Unity3D 的。 DI 对 Unity3D 来说是一个糟糕的匹配,因为正在创建的应用程序(游戏)和可用的 API 框架(正在迁移到 DOTS)。

标签: c# unity3d design-patterns singleton


【解决方案1】:

这里有两个最佳实践。

  1. 构建大量单例,并替换 Unity 内置的初始化系统

  2. 构建很少的单例,并在 Unity 的初始化系统中工作,并大量使用新的多场景编辑系统。

选项 1 非常受游戏工作室和专业游戏开发者的欢迎,他们擅长此操作并且之前已经做过很多次。主要的问题是,一旦你开始走这条路,你就致力于维护你自己的并行初始化系统。主要优点是您的系统可能比 Unity 的内部系统更好、肯定更强大,而且通常更快(!)。

选项 2 更受游戏编程新手的欢迎,他们希望尽可能多地使用 Unity 的内置功能。


也就是说,你的问题有些奇怪。

例如……帆布?你到底为什么要把 Canvas 变成一个单例?这表明您在很大程度上滥用了 Canvas(可能还有其他一些类)。

标准方法(也是 Unity 唯一支持的方法)是让每个场景都有自己独特的画布。做一些不同的事情……很奇怪。

我怀疑您误解了“DontDestoryOnLoad”的作用。它不能防止东西在加载时被破坏!

相反,它可以防止在加载新场景时被破坏,并且它们只存在于旧场景中。一个更好的名字应该是:“DontDestroyWhenLoadingANewScene”

在使用 DontDestroyOnLoad 的 Unity 中有很多错误(可以追溯到很多年前),因此通常最好尽可能避免它。对于简单的情况,它工作得很好,但如果你使用它太多,你会遇到复杂的边缘情况以及与 Unity 自己的内部类的交互。

【讨论】:

  • 我想知道实现单例需要什么“技能”。每个计算机科学一年级的学生都可以并且实际上可以做到这一点。更换内置引导程序 - 好的。但是辛格尔顿?您应该承认,这只是编写“脏”代码以支持快速发布的范例。在客户不关心质量的市场中最大化收入是一种权衡。让事情尽可能简单。游戏行业的大玩家对产品发布后的维护不感兴趣。发布后,他们开始了一个新项目。
  • 我还认为,单例使 “您的系统可能更好,肯定更强大,而且通常更快”。单身人士往往会污染你的记忆。但我同意,以今天的机器内存大小,这不是问题。这同样适用于 IoC 实现与老式 Singleton 相比的小开销。这是微不足道的。 Sigleton 模式的唯一优点是简单。它们很容易理解,因为它们没有任何复杂性。基于Singleton的软件实现非常简单。 维护不是。这就是(游戏)项目所有者喜欢它的原因。
  • @BionicCode 你有没有实现过真正的线程安全的单例?几乎每个(计算机科学专业的毕业生!)都犯了这个错误,这是一个严重的、破坏数据的、长期的错误,最终会给你带来巨大的问题。特别是在 Unity3D 中:您是否曾经实现过正确的初始化单例,它了解编辑器的静态初始化系统,尊重 Unity 的自定义启动顺序(在编辑器和运行时 - 它们不兼容!),并支持多场景而不会损坏?哦,你的 PrefabStageMode 是正确的,对吧? 所有这些都需要你的单例中的额外代码
【解决方案2】:

强制性的 utopic 程序员回答:尽量避免使用单例。

话虽如此,请随意使用我的单例实现,多年来一直在生产中使用它,它运行良好。

https://gist.github.com/ronrejwan/7a4f0037effec3c9e8943542cf9cfbc9

【讨论】:

  • 非常感谢,这比其他答案对我的帮助更大。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-06
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 1970-01-01
相关资源
最近更新 更多