unity游戏引擎- c#方法覆盖Unity3d

本文关键字:方法 覆盖 Unity3d 游戏 引擎 unity | 更新日期: 2023-09-27 17:51:21

最近几周,我使用c#作为脚本语言来玩Unity3d。我从来没有使用过c#和Unity3d之前,我试图了解方法重写如何在Unity框架的工作。让我感到奇怪的是,我可以扩展基类MonoBehavior并覆盖Start (), Update ()等方法,而不必使用override关键字,编译器也不会抱怨它!相反,在"正常"的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...
    }
}

幕后发生了什么?unity是否使用了"动态技巧"?

unity游戏引擎- c#方法覆盖Unity3d

因为MonoBehavior没有Update的定义。运行时检查一个名为Update的方法是否存在(使用反射),如果存在,则调用它,但您没有覆盖基本实现

更新

既然你要求一个例子来说明这是如何可能的,我在这里做了一个例子:https://dotnetfiddle.net/UrpYkf

来源 by bunny83 at http://answers.unity3d.com/answers/177292/view.html

Unity的工作方式有点不同。所有那些所谓的"事件"都不是MonoBehaviour类的方法。如果你有一个c#反射器,你可以通过打开UnityEngine.dll 查看类实现

Unity主要是用c++编写的,因此大多数神奇的事情发生在本机代码。Unity使用反射来确定脚本之后编译完成后,你实现了哪些"事件"记住这堂课。Unity只调用Update/LateUpdate/OnGUI,当它已经实现。

您可以注意到的另一点是创建MonoBehaviour类,并且不实现任何这些方法/事件Unity将从你的脚本实例中移除enabled复选框因为它不包含任何受启用影响的事件。

一些事件是用它们的SendMessage函数分派的(比如OnCollisionEnter等事件)。

文档称所有事件为"可重写函数",但那是并非如此。如果它们被实现为虚函数必须使用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#事件是委托,它只是某种函数指针,但有点复杂;)

在MonoBehaviour基类中没有声明Start, Update, Awake等。这就是为什么在声明Override关键字时不需要编写它们的原因。如果在你的类中实现它们,它们将被Unity3D调用,这可以导致性能改进。