最近几周,我使用c#作为脚本语言使用Unity3d。
我从来没有在c#和Unity3d之前使用过,我试图理解方法覆盖在Unity框架中是如何工作的。
令我感到奇怪的是,我可以扩展基类MonoBehavior
并覆盖诸如Start ()
,Update ()
之类的方法,而不必使用override
关键字,编译器也可以不要抱怨它!
取而代之的是#34;正常" C#程序我必须使用override
关键字,否则我会收到编译器警告。例如:
public class BaseClass {
public virtual void MyMethod () {
Console.WriteLine("BaseClass.MyMethod()");
}
}
public class SubClass : BaseClass {
public override void MyMethod () {
Console.WriteLine("SubClass.MyMethod()");
}
}
class Program {
static void Main () {
SubClass obj = new SubClass ();
obj.MyMethod ();
}
}
而在Unity中我可以做到:
class PlayerController : MonoBehaviour {
void Update () {
// code...
}
}
幕后会发生什么?团结是否利用"动态技巧"或者什么?
答案 0 :(得分:17)
因为MonoBehavior
没有Update
的定义。运行时检查一个名为Update
的方法是否存在(使用反射),如果存在,则调用它,但是你没有覆盖基础实现
由于您要求提供有关如何实现这一目标的示例,我已在此处制作了示例:https://dotnetfiddle.net/UrpYkf
答案 1 :(得分:2)
来源
Unity的工作方式有点不同。所有那些所谓的“事件”都不是 MonoBehaviour类的方法。如果你有C#反射器,你可以 只需打开UnityEngine.dll
即可查看类实现Unity主要用c ++编写,因此大多数魔法都发生在 本机代码。在您的脚本之后,Unity使用反射来确定 已编译,您实施的那些“事件”和 记住这个课程。 Unity仅调用Update / LateUpdate / OnGUI何时实施。
您可以注意到的另一点是您创建的时间 MonoBehaviour类并没有实现任何这些方法/事件 Unity将从脚本实例中删除已启用的复选框 因为它不包含受启用影响的任何事件。
使用SendMessage函数调度某些事件(如 OnCollisionEnter和此类事件)。
文档调用所有事件“Overridable Functions”但是那样 不是真的。如果它们被实现为虚拟功能你 必须使用override关键字,否则它将无效。
以下是MonoBehaviour的整个实现:
public class MonoBehaviour : Behaviour
{
public extern bool useGUILayout
{
get;
set;
}
public extern MonoBehaviour();
private extern void Internal_CancelInvokeAll();
private extern bool Internal_IsInvokingAll();
public extern void Invoke(string methodName, float time);
public extern void InvokeRepeating(string methodName, float time, float repeatRate);
public void CancelInvoke();
public extern void CancelInvoke(string methodName);
public extern bool IsInvoking(string methodName);
public bool IsInvoking();
public Coroutine StartCoroutine(IEnumerator routine);
public extern Coroutine StartCoroutine_Auto(IEnumerator routine);
public extern Coroutine StartCoroutine(string methodName, object value);
public Coroutine StartCoroutine(string methodName);
public extern void StopCoroutine(string methodName);
public extern void StopAllCoroutines();
public static void print(object message);
}
我几乎每次都删除了所有外部属性 方法/属性映射到本机函数。
顺便说一句。提到的C#事件是委托,它们只是某种形式 函数指针,但有点复杂;)
答案 2 :(得分:1)
在MonoBehaviour基类中没有声明Start,Update,Awake等。这就是您在声明它们时不写任何Override关键字的原因。如果Unity3D在您的课程中实现,它们将被调用,这可以提高性能。