1. 程式人生 > >Unity遊戲狀態指令碼控制思考(二)

Unity遊戲狀態指令碼控制思考(二)

最近忙著專案上線,一攤子事,好久沒更了,於是乎補上一更。
上一篇聊到Unity的指令碼控制,這一篇就細說下Unity的實現原理. 

核心點

C#指令碼+Mono+C++
 
UnityEngine裡的核心類似這麼寫的:

public class Component
    {

        private IntPtr native_handle=IntPtr.Zero;
        [MethodImpl(MethodImplOptions.InternalCall)]
        public extern static Component[] GetComponents();
        [MethodImpl(MethodImplOptions.InternalCall)]
        public extern static int get_id_Internal(IntPtr native_handle);
        [MethodImpl(MethodImplOptions.InternalCall)]
        public extern static int get_tag_Internal(IntPtr native_handle);
        public int ID { 
            get {
                return get_id_Internal(native_handle);        
            }
        }

        public int Tag
        {

            get
            {
                return get_tag_Internal(native_handle);
            }
        }
    }

關鍵的部分我們都是反編譯看不到的,看不到的部分都是通過底層C++去實現的,然後通過Mono進行互動(託管程式碼與非託管程式碼之間的互動).

對應C++程式碼是這樣的:
struct Component
{
int id;
int tag;
};

Component* Components;
uint32_t num_Components;
MonoClassField* native_handle_field;
MonoDomain* domain;
MonoClass* Component_class;


//獲取屬性
int ManagedLibrary_Component_get_id_Internal(const Component* component)
{
    return component->id;
}
 //獲取tag
int ManagedLibrary_Component_get_tag_Internal(const Component* component)
{
    return component->tag;
}
//獲取元件
MonoArray* ManagedLibrary_Component_GetComponents()
{
    MonoArray* array = mono_array_new(domain, Component_class, num_Components);

    for(uint32_t i = 0; i < num_Components; ++i)
    {
        MonoObject* obj = mono_object_new(domain, Component_class);
        mono_runtime_object_init(obj);
        void* native_handle_value = &Components[i];
        mono_field_set_value(obj, native_handle_field, &native_handle_value);
        mono_array_set(array, MonoObject*, i, obj);
    }

    return array;
}

int main(int argc, char* argv[])
{
//------------------------------------------------------------------------------------------------
    //例子3:模仿Unity的實現方式
    //mono執行時的配置
      mono_set_dirs("C:\\Program Files\\Mono\\lib",
        "C:\\Program Files\\Mono\\etc");

      mono_config_parse(NULL);
      const char* managed_binary_path = "E:\\test\\ManagedLibrary.dll";

      //獲取應用域
     domain = mono_jit_init(managed_binary_path);
     //載入程式集
     MonoAssembly* assembly = mono_domain_assembly_open(domain, managed_binary_path);
     MonoImage* image = mono_assembly_get_image(assembly);

     //通過Mono的mono_add_internal_call方法將C#中的介面和C/C++中的具體實現關聯起來
     mono_add_internal_call("ManagedLibrary.Component::get_id_Internal",reinterpret_cast<void*>(ManagedLibrary_Component_get_id_Internal));
     mono_add_internal_call("ManagedLibrary.Component::get_tag_Internal",reinterpret_cast<void*>(ManagedLibrary_Component_get_tag_Internal));
     mono_add_internal_call("ManagedLibrary.Component::GetComponents",reinterpret_cast<void*>(ManagedLibrary_Component_GetComponents));
     //Component.cs
     Component_class =mono_class_from_name(image,"ManagedLibrary","Component");
     native_handle_field =mono_class_get_field_from_name(Component_class,"native_handle");
     num_Components =5;
     Components = new Component[5];
    for(uint32_t i = 0; i < num_Components; ++i)
    {
        Components[i].id = i;
        Components[i].tag = i * 5;
    }

    // Main.cs
     MonoClass* main_class = mono_class_from_name(image, "ManagedLibrary", "Main");
     const bool include_namespace = true;
    MonoMethodDesc* managed_method_desc = mono_method_desc_new("ManagedLibrary.Main:TestComponent()", include_namespace);
    MonoMethod* managed_method = mono_method_desc_search_in_class(managed_method_desc, main_class);
    mono_method_desc_free(managed_method_desc);
    //執行
    mono_runtime_invoke(managed_method, NULL, NULL, NULL);
    //釋放應用域
    mono_jit_cleanup(domain);
    //釋放元件
    delete[] Components;

    return 0;
//--------------------------------------------------------------------------
}

著重理解下核心點“C#指令碼+Mono+C++”,明白了這個就簡單了。

附件

工程原始碼