120 Hazel游戏引擎将C#脚本融入ECS

文中若有代码、术语等错误,欢迎指正
文章目录总结复习C++调用C#函数Mono的步骤(118节) 代码思路+相关代码 其它要写的代码(省略) 效果遇到的BUG
前言实现此节目的思路 C#调用C++的函数
C++中定义好(C#中声明的)外部调用的函数
C#的函数
每帧获取实体的当前位置,检测根据WASD事件改变实体的位置,把新位置传给C++
C++调用C#的函数 给出名词解释
struct ScriptEngineData {....ScriptClass EntityClass;// 存储C#父类Entity的Mono类// 所有C#脚本map (脚本map),存储封装的Mono类std::unordered_map::string, Ref>> EntityClasses;// 需要运行的C#脚本map(运行脚本map),存储封装的Mono类对象std::unordered_map> EntityInstances; ....};
具体步骤总结复习C++调用C#函数Mono的步骤(118节)
有利于理解本节重点的代码
初始化Mono准备,需得到、、
// 0.1设置程序集装配路径(复制的4.5版本的路径)mono_set_assemblies_path("mono/lib");// 0.2声明根域MonoDomain* rootDomian = mono_jit_init("HazelJITRuntime");// 存储root domain指针s_Data->RootDomain = rootDomian;// 0.3创建一个应用 domains_Data->AppDomain = mono_domain_create_appdomain("HazelScriptRuntime", nullptr);mono_domain_set(s_Data->AppDomain, true);// 0.4加载c#项目导出的dll程序集s_Data->CoreAssembly = LoadCSharpAssembly("Resources/Scripts/GameEngine-ScriptCore.dll");// 0.5得到MonoImage对象MonoImage* assemblyImage = mono_assembly_get_image(s_Data->CoreAssembly);
根据命名空间、类名、得到加载C#的Mono类=>可以理解为创建类Class
MonoClass* monoClass = mono_class_from_name(assemblyImage, "Hazel", "Main");
根据和当前应用得到=>可以理解为Class cls = new Class()得到类的实例,会调用类的构造函数
MonoObject* instance = mono_object_new(s_Data->AppDomain, monoClass);mono_runtime_object_init(instance);// 这里初始化会调用C#类的构造函数
【120Hazel游戏引擎将C#脚本融入ECS】根据获取这个类的函数,根据和函数名称调用函数=>可以理解为**cls.Func();**调用类的函数
// 3.1根据MonoClass获取这个类的函数MonoMethod* printMessageFunc = mono_class_get_method_from_name(monoClass, "PrintMessage", 0);// 3.2根据MonoObject和函数名称调用函数mono_runtime_invoke(printMessageFunc, instance, nullptr, nullptr);
代码思路+相关代码 代码思路 C#调用C++的函数
比较简单,只需要列出相关的C#代码就能理解
C++调用C#的函数(C++项目的代码)
再调用C#类的函数(初始化)

120  Hazel游戏引擎将C#脚本融入ECS

文章插图
void ScriptEngine::OnCreateEntity(Entity entity){const auto& sc = entity.GetComponent>();// 得到这个实体的组件if (ScriptEngine::EntityClassExists(sc.ClassName)) {// 组件的脚本名称是否正确Ref> instance = CreateRef>(s_Data->EntityClasses[sc.ClassName], entity);// 实例化类对象,并存储OnCreate、OnUpdate函数,调用父类Entity的构造函数,传入实体的UUIDs_Data->EntityInstances[entity.GetUUID()] = instance; // 运行脚本map存储这些ScriptInstance(类对象)instance->InvokeOncreate();// 调用C#的OnCreate函数}}
存储、函数,并调用C#父类的构造函数传入当前实体的UUID给C#
(C#脚本有UUID后,C#的一个脚本才能 与 拥有这个C#脚本的C++实体联系在一起)
ScriptInstance::ScriptInstance(Ref> scriptClass, Entity entity):m_ScriptClass(scriptClass){// 获取Sandbox Player类构成的MonoObject对象,相当于new Sandbox.Player()m_Instance = scriptClass->Instantiate(); m_Constructor = s_Data->EntityClass.GetMethod(".ctor", 1);// 获取C#Entity类的构造函数m_OnCreateMethod = scriptClass->GetMethod("OnCreate", 0);// 获取并存储Sandbox.Player类的函数m_OnUpdateMethod = scriptClass->GetMethod("OnUpdate", 1);// 调用C#Entity类的构造函数{UUID entityID = entity.GetUUID();void* param = &entityID;m_ScriptClass->InvokeMethod(m_Instance, m_Constructor, ¶m);// 第一个参数传入的是Entity子类(Player)构成的mono对象}}