Unity遊戲狀態指令碼控制思考(二)
阿新 • • 發佈:2018-12-27
最近忙著專案上線,一攤子事,好久沒更了,於是乎補上一更。
上一篇聊到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++”,明白了這個就簡單了。