当前位置: 首页 > news >正文

Hazel游戏引擎(005)

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

我写的项目地址:https://github.com/liujianjie/GameEngineLightWeight(中文的注释适合中国人的你)

文章目录

  • 前言
  • 关键操作
  • 代码文件+关键代码+代码流程
    • 代码文件
    • 关键代码
      • extern外部定义CreateApplication
      • 包含头文件+条件编译和宏定义实现Dll导入与导出
    • 代码流程
  • 运行效果
  • Github
  • 涉及的C++知识

前言

  • 此节目的

    将上一小节的main函数入口点写在Hazel项目中,由引擎内部控制。

    优化dll导出导入代码,用条件编译+宏定义来编写dll导出与导入代码

  • Cherno本节完整代码链接

    https://github.com/TheCherno/Hazel/commit/f9fbbd2bf3d870a6586c5c4f70a867d78e27b113

关键操作

  • Hzel项目

    右键属性(所有配置)=>C/C++=>预处理器=>预处理器定义

    输入

    HZ_PLATFORM_WINDOWS;HZ_BUILD_DLL

  • Sandbox项目

    • 右键属性(所有配置)=>C/C++=>预处理器=>预处理器定义

      输入

      HZ_PLATFORM_WINDOWS;

    • 右键属性(所有配置)=>C/C++=>常规=>附加包含目录

      输入

      $(SolutionDir)Hazel\src

      为了Sandbox项目能引入Hazel项目的文件

      #include <Hazel.h>
      

代码文件+关键代码+代码流程

代码文件

  • Hazel项目

    • Application类

      引擎内部功能实现

    • Core.h

      来根据不同项目的条件编译,而写dll导入还是导出的宏定义

    • EntryPoint.h

      入口点,main函数

    • Hazel.h

      引入其它头文件,控制给Sandbox项目提供哪些引擎内部功能

  • Sandbox项目

    • SanboxApp.cpp

      应用层实现

关键代码

extern外部定义CreateApplication

  • 在Hazel项目的Application.h中

    namespace Hazel {class HAZEL_API Application{....};// To be defined in CLIENTApplication* CreateApplication();
    }
    

    在Hazel命名空间内声明了CreateApplication函数

  • 在Sandbox项目的SandboxApp.cpp中

    Hazel::Application* Hazel::CreateApplication()
    {return new Sandbox();
    }
    

    定义了CreateApplication函数

  • 在EntryPoint.h中调用

    extern Hazel::Application* Hazel::CreateApplication();
    int main(int argc, char** argv){auto app = Hazel::CreateApplication();...
    }
    

    将CreateApplication函数声明为extern,表示此函数会在外部定义,接下来使用的这函数时将使用在外部定义的CreateApplication

包含头文件+条件编译和宏定义实现Dll导入与导出

  • 在Core.h中

    #pragma once
    #ifdef HZ_PLATFORM_WINDOWS#ifdef HZ_BUILD_DLL#define HAZEL_API __declspec(dllexport)#else#define HAZEL_API __declspec(dllimport)#endif
    #else#error Hazel only supports Windows!
    #endif
    

    根据条件编译定义HAZEL_API是dll导入还是导出,由上的关键操作小点可知Hazel项目将是__declspec(dllexport),Sandbox项目是__declspec(dllimport)

  • 问题在于:这关Sandbox项目何事,这明明是Hazel项目中的头文件

    由于Sandbox#include <Hazel.h>,而Hazel项目的Hazel.h包含了Application.h,Application.h又包含了Core.h文件,

    所以这Core.h的代码也会被拷贝到Sandbox项目的SandboxApp.cpp中#include <Hazel.h>的位置,

    并且Application.h也会被拷贝到<Hazel.h>的位置。

    #include <Hazel.h>
    class Sandbox : public Hazel::Application
    {
    public:Sandbox(){}~Sandbox(){}
    };
    .....
    

    所以Sandbox项目也有HAZEL_API宏定义,且是__declspec(dllimport)

  • 所以SandboxApp.cpp的代码将变成

    #pragma once
    #ifdef HZ_PLATFORM_WINDOWS#ifdef HZ_BUILD_DLL#define HAZEL_API __declspec(dllexport)#else#define HAZEL_API __declspec(dllimport)#endif
    #else#error Hazel only supports Windows!
    #endif
    namespace Hazel {class HAZEL_API Application// HAZEL_API被替换成__declspec(dllimport){public:Application();virtual ~Application();void Run();};// To be defined in CLIENTApplication* CreateApplication();
    }
    ....省略EntryPoint.h的代码(下面将运行流程会有)....
    class Sandbox : public Hazel::Application
    {
    public:Sandbox(){}~Sandbox(){}
    };
    .....
    

    所以Sandbox类导入了dll中的Application类,且可以继承Application。

    对应003节的代码

    #pragma once
    namespace Hazel {_declspec(dllexport) void Print();// 导出
    }
    
    namespace Hazel {_declspec(dllimport) void Print(); // 导入
    }
    void main() {Hazel::Print();// 使用
    }
    

代码流程

  • 开始运行Sandbox.exe

    由于Sandbox中#include <Hazel.h>,而Hazel项目的Hazel.h包含了Application.h和EntryPoint.h入口文件

    Hazel.h

    #pragma once
    // For use by Hazel applications
    #include <iostream>
    #include "Hazel/Application.h"
    // ---Entry Point---------------------
    #include "Hazel/EntryPoint.h"
    // -----------------------------------
    
  • EntryPoint.h定义了main函数,即写了入口点,所以程序会在这运行

    因为SandboxApp.cpp在第一行包含Hazel.h,Hazel.h又包含EntryPoint.h,那么EntryPoint.h的代码会被拷贝到SandboxApp.cpp中

    #include <Hazel.h>
    

    将拥有以下EntryPoint.h中的代码

    #pragma once
    #ifdef HZ_PLATFORM_WINDOWS
    extern Hazel::Application* Hazel::CreateApplication();
    int main(int argc, char** argv)
    {std::cout << "Core::main" << std::endl;auto app = Hazel::CreateApplication();app->Run();delete app;
    }
    #endif
    

    main函数中执行CreateApplication函数,将调用定义在SandboxApp.cpp中的CreateApplication函数

    Hazel::Application* Hazel::CreateApplication()
    {return new Sandbox();
    }
    

    这函数返回的指针是Hazel项目中的Application父类指针,所以auto app的类型是Application*。

  • 当执行app->Run()函数时,由于Run()函数没有声明为虚函数,所以会调用Application中的Run()函数

    #include "Application.h"
    namespace Hazel {Application::Application(){}Application::~Application(){}void Application::Run(){while (true);}
    }
    

    Application的Run函数是一个while循环,所以循环会无限制运行中

运行效果

请添加图片描述

需要把最新生成的Hazel.dll放在Sandbox.exe文件夹下

请添加图片描述

Github

  • .gitignore

    在.git文件夹下新建.gitignore文件,可以声明一些不想提交到暂存区的文件

    # Binaries
    **/bin/
    bin-int/# Visual Studio files and folder
    .vs/
    **.sln
    **.vcxproj
    **.vcxproj.filters
    **.vcxproj.user
    **.csproj
    
  • 其它命令

    git add *// 提交文件到暂存区
    git reset . // 将暂存区文件返回
    git status // 查看文件有无提交到暂存区状态
    git commit -m "注释"// 将暂存区的内容添加到仓库
    git push origin main // 将本地的分支版本上传到远程并合并
    

涉及的C++知识

对应此节代码地方

Hazel::Application* Hazel::CreateApplication()
{return new Sandbox();
}
auto app = Hazel::CreateApplication();
app->Run();

转换为以下容易理解的代码

#include <iostream>
using namespace std;class Application {
public:void Run() {cout << "Application::Run()" << endl;}
};
class Sandbox : public Application {
public:void Run() {cout << "Sandbox::Run()" << endl;}
};
void main() {Application* app = new Sandbox();app->Run();// 由于Run()函数没有声明为virtual虚函数,所以执行父类的Run函数
}

请添加图片描述

http://www.lryc.cn/news/6077.html

相关文章:

  • 牛客网Python篇数据分析习题(四)
  • 盲盒如何创业?
  • 第1集丨Java中面向对象相关概念汇总
  • 高性能(二)
  • Allegro如何实现同一个屏幕界面分屏显示操作指导
  • 前后端一些下载与配置(第二篇 第10天过后)nuxt banner redis 短信服务
  • OSG三维渲染引擎编程学习之四十八:“第五章:OSG场景渲染” 之 “5.6 多重纹理映射”
  • 对Node.js 的理解?优缺点?应用场景?
  • Bean的生命周期
  • Python学习-----函数2.0(函数对象,名称空间,作用域-->全局变量与局部变量)
  • Java中Json字符串和Java对象的互转
  • 代码随想录NO42 | 动态规划_Leetcode70. 爬楼梯 (进阶) 322. 零钱兑换 279.完全平方数
  • 【C++从入门到放弃】初识C++(基础知识入门详解)
  • 企业工程项目管理系统源码+spring cloud 系统管理+java 系统设置+二次开发
  • 【GPLT 三阶题目集】L3-016 二叉搜索树的结构
  • 核心交换机安全多业务高性能万兆交换机
  • Android APK 签名打包原理分析(三)【静默安装的实现方案】
  • mulesoft MCIA 破釜沉舟备考 2023.02.14.05
  • 结构体的三种定义方法、结构体类型名(可选标志符)什么时候可以省略
  • cgo静态编译不能用glibc,用musl
  • ​力扣解法汇总1124. 表现良好的最长时间段
  • 12- 降维算法 (PCA降维/LDA分类/NMF) (数据处理)
  • QT+ OpenGL学习
  • C语言(字符串输入)
  • 背包问题求方案数(AcWing)(JAVA)
  • 一篇文章带你读懂HashMap
  • Java如何进行优雅的判空——Optional类的灵活应用
  • Fluent Python 笔记 第 12 章 继承的优缺点
  • Go语言读取解析yml文件,快速转换yml到go struct
  • 第二十六章 java并发常见知识内容(ThreadLocal 详解)