当前位置:   article > 正文

Unity3d是如何调用MonoBehaviour子类中的Start等方法的?_unity 继承单例 怎么调用start

unity 继承单例 怎么调用start

 

Unity3d开发,需要继承MonoBehaviour,实现Start方法:
 

  1. using UnityEngine;
  2. using System.Collections;
  3. public class ExampleClass : MonoBehaviour {
  4. private GameObject target;
  5. void Start() {
  6. target = GameObject.FindWithTag("Player");
  7. }
  8. }
但是这个Start方法是私有的,而不是override MonoBehaviour中已有的方法。

按我的理解,应该在MonoBehaviour中设计一个abstract或virtual的Start方法,然后让子类去实现它才对啊!

难道Unity3d 引擎部分在调用ExampleClass时用的是反射?他们这样设计是出于什么目的的?有什么好处?

 

 

查看全部 8 个回答

 

18 人赞同

2016/1/21:阅读到这篇文章: (English) Going deep with IMGUI and Editor Customization,本答案中的部分内容是不正确的,特此更正:

Unity使用类反射而非虚函数的方式来调用Update等函数,主要原因是在于,并非所有的MonoBehaviour都需要Update(或Start,Awake等等,下同)。Unity会维护一个需要Update的Behaviour列表,藉此避免进行空的虚函数调用,提高性能。
但这一点与原回答第5条的建议并不冲突。

以下是原回答。

1. 是使用反射来调用的,这一点@愤怒的泡面 已经说过了。反射可以访问私有方法;
@庞巍伟 指出这是用mono的API来实现的(而不是C#内建的反射机制),我没看过Unity的源码所以不敢做定论,但我的理解是,mono的这套机制也是reflection,只不过不是The Reflection而已,不需要太教条地去理解。Mono的API可能效率更高,但对于单次调用,性能仍然逊于虚方法调用。不过能了解Unity的实际实现方式也是收益良多,感谢。

2. 反射实际上是开销非常大的调用方式,比之虚方法来说要高得多,因此Unity选择使用反射并非是出于性能方面的考虑。实际上,每帧调用的这些事件方法从数量级上来说是很卑微的,反射造成的性能影响亦可忽略不计;

3. Unity使用这种事件机制的根本原因是出于对灵活性的考虑。Unity采用组件式设计,触发一个事件,需要通知到相应gameobject的所有组件。如果使用多态来实现,则必须假设所有组件都派生自包含此事件的基类,或者筛选出派生自此基类的组件逐一通知。这样一来是麻烦,二来则容易带来复杂的继承关系,与组件式这种倡导用聚合代替继承的设计从理念上就是相悖的。
另一方面的原因则是为了跟JS保持一致性。这种事件机制对于JS这种动态类型语言来说是浑然天成的。

4. 这种设计最大的缺陷在于事件名通过字符串耦合,如此一来,完全绕开了编译期静态检查,无法为事件调用的正确性提供保障;在复杂的系统里,也可能因为事件重名而导致bug。

5. 我个人倾向的改良性设计是:提供基础接口IEvent<T>
 

  1. interface IEvent < T > where T : EventArgs

  2. {

  3. void Raise ( object sender , T args );

  4. }

  • 1



令所有事件都声明一个继承于此接口的接口,如:
 

  1. interface IReviveEvent : IEvent < EventArg >

  2. {

  3. }

  • 1



所有包含此事件的类显示实现此接口:

 
  1. class Mob : MonoBehaviour , IReviveEvent

  2. {

  3. void IReviveEvent . Raise ( object sender , EventArgs e )

  4. {

  5. //...

  6. }

  7. }

  •  


调用事件可以通过为GameObject类写一个扩展方法来实现,手机党就不挣扎码字了。
不过这只适用于自己的代码,Unity内建的那些事件(Update之类的)只能由它去了。
 

知乎用户

c++层做反射各大游戏引擎都能看到类似实现。IReviveEvent侵入性太强了,直接导致每个monoBhr都得有全部的方法,引擎也得对所有monoBhr的所有方法做无用功调用,而事实上只有少部分monoBhr需要update。

7 月前
 

更多回答

 

知乎用户  ,飘逸的程序员/初级制作人

20 人赞同

unity用的是mono,mono的api就支持基于字符串查找的方法, 然后存下来指针,以后调用:

最后给你贴一段unity源代码吧:
 

inline void MonoBehaviour::Start ()
{
….

method = m_Methods[MonoScriptCache::kCoroutineStart];
if (method)
InvokeMethodOrCoroutineChecked (method, SCRIPTING_NULL);
}

 

https://www.zhihu.com/question/27752591

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/108043
推荐阅读
相关标签
  

闽ICP备14008679号