赞
踩
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时用的是反射?他们这样设计是出于什么目的的?有什么好处?
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>
interface IEvent < T > where T : EventArgs
{
void Raise ( object sender , T args );
}
令所有事件都声明一个继承于此接口的接口,如:
interface IReviveEvent : IEvent < EventArg >
{
}
所有包含此事件的类显示实现此接口:
class Mob : MonoBehaviour , IReviveEvent
{
void IReviveEvent . Raise ( object sender , EventArgs e )
{
//...
}
}
调用事件可以通过为GameObject类写一个扩展方法来实现,手机党就不挣扎码字了。
不过这只适用于自己的代码,Unity内建的那些事件(Update之类的)只能由它去了。
知乎用户
c++层做反射各大游戏引擎都能看到类似实现。IReviveEvent侵入性太强了,直接导致每个monoBhr都得有全部的方法,引擎也得对所有monoBhr的所有方法做无用功调用,而事实上只有少部分monoBhr需要update。
7 月前
更多回答
知乎用户 ,飘逸的程序员/初级制作人
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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。