您当前的位置: 首页 >  ar

Peter_Gao_

暂无认证

  • 0浏览

    0关注

    621博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity3d是如何调用MonoBehaviour子类中的Start等方法的?

Peter_Gao_ 发布时间:2021-04-29 11:13:14 ,浏览量:0

 

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

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    private GameObject target;
    void Start() {
        target = GameObject.FindWithTag("Player");
    }
}
但是这个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  

  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

 

 

关注
打赏
1664521772
查看更多评论
立即登录/注册

微信扫码登录

0.0380s