当使用 new 创建 MonoBehaviour 时,究竟会发生什么?

What exactly happens when a MonoBehaviour is created with new?

提问人:Michael Macha 提问时间:1/20/2022 更新时间:6/1/2023 访问量:730

问:

我知道这是“不允许的”;我无意中这样做了,它将从我的最终版本中彻底删除。显然,这条规则是有充分理由的。

奇怪的是,它位于单元测试组件中,尽管有警告,它仍然可以完美运行。我正在用继承自 MonoBehaviour 的类的几个构造实例填充列表,只是为了确保一个函数正在做我想让它做的事情,我收到了这个警告;但测试似乎运行良好。此外,这是一个警告,而不是真正的错误,这可能也是有原因的。

出于好奇,由于我的理解显然不完整,有人可以解释一下,如果可能的话,提供文档链接来解释为什么Unity不允许它显然能够做到的行为?为什么它禁止这样做,如果警告被忽略,会有什么缺点?

谢谢你完成我对它的理解。

C# unity-game-engine mono warnings 编译器警告

评论

1赞 derHugo 1/20/2022
像 etc 这样的内置属性都不起作用,因为没有附加到该对象的对象。除此之外,可能还有其他不良副作用,例如根本没有 等被调用gameObjectAwakeStart
0赞 derHugo 1/20/2022
为什么不以允许的方式创建实例 - 即使是测试 - 使用例如 ..您不必首先考虑可能出错的地方var component = new GameObject("some name"). AddComponent<YourComponent>();
0赞 Michael Macha 1/20/2022
@derHugo我正在研究的实际上是一种排序算法,用于确定物品可以在以后的场景中合理地放置在没有交集的位置;所以我认为在简化的单元测试中担心新的游戏对象是没有意义的,我只想确保它们被正确排序。我对此更感兴趣的是我自己受到启发,但谢谢。
0赞 derHugo 1/20/2022
那么,如果一个类实际上没有行为并且没有绑定到 一个,那么它有意义吗?为什么不把你的东西变成一个普通的类,而不是一个组件呢?MonoBehaviourGameObject
0赞 Michael Macha 1/23/2022
因为它将是一个组件,所以它是一种行为,我正在进行单元测试以确保我的排序函数正常工作。对不起,我真的不知道你错过了什么。“更改大量代码”不会对测试或最终实现产生任何好处。

答:

1赞 rutter 1/20/2022 #1

Unity 具有基于组件的体系结构。场景中存在的任何对象都由一个游戏对象表示,该游戏对象附加了一个或多个对象。Component

组件经常更改它们所附加到的游戏对象的行为或外观。在某些情况下,组件还会相互引用或依赖。例如,组件倾向于串联使用。RigidBodyCollider

MonoBehaviour脚本也派生自该类。您可以使用 创建行为对象,但它不会附加到任何游戏对象,因此不会在场景中正确存在。这可能会导致错误:Componentnew

  • 内置事件可能无法始终如一地工作。例如,、 、 或 。AwakeStartUpdateOnCollisionEnter
  • 内置引用根本不起作用。例如,、 或 和 函数系列。gameObjecttransformAddComponentGetComponent
  • 其他组件以标准方式与此组件交互是不安全的。
  • 场景转换可能会使问题复杂化,因为孤立的脚本不会附加到场景中的任何内容。

不过,您确实有一些其他选择。

您可以创建一个新的游戏对象,然后将脚本附加到该对象。这是用于管理整个场景(或跨多个场景)的游戏状态的脚本的常见工作流。这可能属于单例模式

如果需要这些类在场景之外可用,也可以创建不派生自 的类。MonoBehaviour

评论

1赞 Michael Macha 1/20/2022
所以你的意思是说,它不那么不可能编译,更多的是滥用代码的用途?这确实是有道理的。我最终要做的是一种排序算法,用于在我的场景中正确实例化这些,因此鉴于我在完成测试后删除了它们,我怀疑这将是一个问题。
1赞 PhilippR 6/1/2023 #2

虽然这是一个古老的话题,但其中的一部分似乎仍未得到解决。

我有一个类似的问题 - 也许它会省去其他人的麻烦:警告是在运行完全没有引用MonoBehaviours的编辑器单元测试时发出的。这令人困惑。该警告似乎源自 NUnit.Framework 内部,并导致了一个不是我编写的脚本。

经过一番努力,我发现包含测试的类仍然继承自 MonoBehaviour(因为这是新脚本模板的一部分)。删除该继承解决了该问题。