Hazel游戏引擎(122)C#分离游戏和核心库代码

文中若有代码、术语等错误,欢迎指正

前言

  • 此节目的

    将C#游戏代码作为新工作空间的项目,并引用C#核心库的项目

    • 1个C#核心库项目

    • 1个C#脚本项目

      里面脚本调用C#核心库的函数,从而实现脚本功能

    像Unity开发时,Unity有一套自己的dll,我们写脚本需要using UnityEngine;,调用Unity库dll才能实现相应效果

  • 如何实现

    使用premake5快速制作

  • 实现细节

    • 当分离了C#游戏代码和核心库代码,那C++加载dll从一个变成两个

    • 得到C# dll的Mono类

      应该区分是获取C#核心库程序集的 Mono类

      还是获取C#应用程序集的 Mono类

项目结构相关

新的工作空间新脚本项目

  • 新的工作空间文件路径

    在GameEngine-Editor编辑器项目下

    请添加图片描述

  • 新Sandbox脚本项目的premake

    local UnifyRootDir = "../../../.."
    
    workspace "Sandbox"
    	architecture "x86_64"
    	startproject "Sandbox"
    	configurations{
    		"Debug",
    		"Release",
    		"Dist"
    	}
    	flags{
    		"MultiProcessorCompile"
    	}
    
    outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"
    
    project "Sandbox"
    	kind "SharedLib"
    	language "C#"
    	dotnetframework "4.7.2"
    
    	targetdir ("Binaries")
    	objdir ("Intermediates")
    
    	files{
    		"Source/**.cs",
    		"Properies/**.cs"
    	}
    	links{
    		"GameEngine-ScriptCore"
    	}
    	filter "configurations:Debug"
    		optimize "Off"
    		symbols "Default"
    
    	filter "configurations:Release"
    		optimize "On"
    		symbols "Default"
    
    	filter "configurations:Dist"
    		optimize "Full"
    		symbols "Off"
    
    group "Unify"
    	include (UnifyRootDir .. "/GameEngine-ScriptCore")
    group ""
    

新Sandbox脚本项目结构

  • Sandbox项目引用GameEngine-ScriptCore项目
  • Sandbox项目包含从GameEngine-ScriptCore项目移动过来的Player.cs游戏逻辑脚本代码

新Sanbox脚本项目生成dll

请添加图片描述

  • 由premake设置的生成目录

    targetdir ("Binaries")
    objdir ("Intermediates")
    
  • 由于Sandbox项目引用GameEngine-ScriptCore项目

    所以生成不仅会生成Sandbox.dll也会生成GameEngine-ScriptCore.dll

项目代码改变

项目代码所做的改变都是为了加载两个dll,和根据不同dll反射不同的类

ScriptEngine.h

//ScriptClass(const std::string& classNamespace, const std::string& className);
ScriptClass(const std::string& classNamespace, const std::string& className, bool isCore = false);
static void LoadAppAssembly(const std::filesystem::path& filepath);
//static void LoadAssemblyClasses(MonoAssembly* assembly);
static void LoadAssemblyClasses();

ScriptEngine.cpp

struct ScriptEngineData {
    MonoAssembly* CoreAssembly = nullptr;
    MonoImage* CoreAssemblyImage = nullptr;
	// 新增,因加载脚本dll,需保存这两个
    MonoAssembly* AppAssembly = nullptr;
    MonoImage* AppAssemblyImage = nullptr;
};
LoadAssembly("Resources/Scripts/Hazel-ScriptCore.dll");
LoadAppAssembly("SandboxProject/Assets/Scripts/Binaries/Sandbox.dll");
s_Data->EntityClass = ScriptClass("Hazel", "Entity", true);

void ScriptEngine::LoadAssemblyClasses()
{
    // Entity类在核心库
    MonoClass* entityClass = mono_class_from_name(s_Data->CoreAssemblyImage, "Hazel", "Entity");
    // 从游戏逻辑脚本库里加载脚本类
    const char* nameSpace = mono_metadata_string_heap(s_Data->AppAssemblyImage, cols[MONO_TYPEDEF_NAMESPACE]);
    const char* name = mono_metadata_string_heap(s_Data->AppAssemblyImage, cols[MONO_TYPEDEF_NAME]);
	MonoClass* monoClass = mono_class_from_name(s_Data->AppAssemblyImage, nameSpace, name);
}
void ScriptEngine::LoadAppAssembly(const std::filesystem::path& filepath)
{
    // Move this maybe
    s_Data->AppAssembly = Utils::LoadMonoAssembly(filepath);
    auto assemb = s_Data->AppAssembly;
    s_Data->AppAssemblyImage = mono_assembly_get_image(s_Data->AppAssembly);
    auto assembi = s_Data->AppAssemblyImage;
    // Utils::PrintAssemblyTypes(s_Data->AppAssembly);
}
ScriptClass::ScriptClass(const std::string& classNamespace, const std::string& className, bool isCore)
    : m_ClassNamespace(classNamespace), m_ClassName(className)
{
    /*
    得到C# dll的Mono类
    应该**区分**是获取C#核心库程序集的 Mono类
    还是获取C#应用程序集的 Mono类
    */
   m_MonoClass = mono_class_from_name(s_Data->CoreAssemblyImage, classNamespace.c_str(), className.c_str());
   m_MonoClass = mono_class_from_name(isCore ? s_Data->CoreAssemblyImage : s_Data->AppAssemblyImage, classNamespace.c_str(), className.c_str());
}

遇到的Bug

  • GameEngine-ScriptCore.dll无法加载

    GameEngine-ScriptCore.dll生成在GameEngine-Editor\SandboxProject\Assets\Scripts\Binaries文件夹下

    而不是在GameEngine-Editor\Resources\Scripts文件夹下

    • 原因

      新Sandbox项目包含引用了GameEngine-ScriptCore项目

      而Sandbox的premake写的生成文件路径为

      targetdir ("Binaries")
      objdir ("Intermediates")
      

      而GameEngine-ScriptCore的premake又写的是

      targetdir ("%{wks.location}/GameEngine-Editor/Resources/Scripts")
      objdir ("%{wks.location}/GameEngine-Editor/Resources/Scripts/Intermediates")
      

      注意%{wks.location}这个代码,它获取的是**.sln**的所在位置

      • 原先GameEngineLightWeight工作空间包含它

        %{wks.location} = GameEngineLightWeight

        所以生成目录为:

        GameEngineLightWeight\GameEngine-Editor\Resources\Scripts

      • 但是新Sandbox也有自己的新的工作空间,并且也包含了这个GameEngine-ScriptCore项目

        %{wks.location} = GameEngineLightWeight\GameEngine-Editor\SandboxProject\Assets\Scripts

        所以这生成目录变成为:

        GameEngineLightWeight\GameEngine-Editor\SandboxProject\Assets\Scripts\GameEngine-Editor\Resources\Scripts

    • 如下生成路径

      请添加图片描述

      生成的路径与代码加载dll的路径不同,所以会报错

    • 如何解决

      在GameEngine-ScriptCore项目的premake中修改生成路径

      -- 获取的是.sln所在的位置
      --targetdir ("%{wks.location}/GameEngine-Editor/Resources/Scripts")
      --objdir ("%{wks.location}/GameEngine-Editor/Resources/Scripts/Intermediates")
      targetdir ("../GameEngine-Editor/Resources/Scripts")
      objdir ("../GameEngine-Editor/Resources/Scripts/Intermediates")
      

      由…/代替%{wks.location}

    • 重新生成路径

请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值