在 Unity 中,当我实现 Update() 以及来自 MonoBehaviour 的其他消息时到底发生了什么

In Unity what exactly is going on when I implement Update(), and other messages from MonoBehaviour

我是 C# 的新手,在 Java、python 和一些 "web" 方面有很强的背景。所以我可能只是在这里遗漏了一些知识,希望有人可以为我补充。

通过 Unity Scripting API,我注意到很多方法,列在 "Messages" 下,这是我的第一个困惑点。 "Message" 和 "Method" 之间到底有什么区别,对我来说它们似乎是同一回事,但术语让我失望。

我的第二个困惑是,当我在派生的 class 中实现类似 Update() 的 "Message" 时,我不必使用 override 关键字。这让我很烦恼,因为我不会只是隐藏它吗?在这种情况下,更新循环不会只知道 MonoBehaviour 而不是我派生的 class,并在 MonoBehaviour 中调用 Update() 而不是我的 class 吗?这让我陷入困境。我很好笑这是幕后发生的事情吗?

Unity 和 C# 一直相处得很好,这对我来说只是一个症结所在,我觉得我缺少一些知识。

要记住的一件事是,Unity 团队设计脚本 API(包括 MonoBehaviour class)不一定是为了促进良好的软件开发原则;他们将其设计为可访问性和易用性(特别是对于非程序员)。这正在慢慢改变,但仍然有很多惯性倾向于 "what's easy" 而不是 "what's right."

也就是说,让我们开始回答您的问题。关于 "messages," 查看文档对 Component.SendMessage 的看法:

Calls the method named methodName on every MonoBehaviour in this game object.

当您查看 Collider 的文档并看到“消息”部分下列出的方法时,这表明如果您实现这些方法,它们将被调用(通过 SendMessage)作为响应某些事件或动作(OnCollisionEnter,例如 "is called when this collider/rigidbody has begun touching another rigidbody/collider.")。我可能将它们实现为事件委托,但 Unity 团队选择使用字符串实现他们自己的消息传递系统,再次以 "ease of use."

的名义

为了同样的效果,如果您沿着 MonoBehaviour class 的继承链向上走,您会注意到在链中的任何地方您实际上都找不到名为 UpdateStart 或脚本的其他生命周期事件。 Unity 将它们视为魔术方法并调用它们(再次通过 SendMessage,看起来)如果它们存在于实现 class 中。这就是为什么您的 Update 方法是 public 或受保护甚至是私有的都没有关系的原因......它仍然会被调用。

他们在幕后的做法是使用反射来获取匹配的方法,这就是为什么

 void update(){}
 void Update(bool inVariable){}

不会被调用并且

void Update() {}

他们寻找一个匹配名称和参数签名的方法(在这种情况下不接受参数)。前两个在大小写或参数输入方面存在问题。

通过使用反射,您不需要让一个函数成为 public 来调用它,但如果它是,也不会伤害它。

它们对消息系统使用相同类型的东西,这就是为什么您可以调用任何函数的原因,尽管它们仅限于在消息中接收一个变量。