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函数
}
相关文章:

Hazel游戏引擎(005)
本人菜鸟,文中若有代码、术语等错误,欢迎指正 我写的项目地址:https://github.com/liujianjie/GameEngineLightWeight(中文的注释适合中国人的你) 文章目录前言关键操作代码文件关键代码代码流程代码文件关键代码exter…...

牛客网Python篇数据分析习题(四)
1.现有一个Nowcoder.csv文件,它记录了牛客网的部分用户数据,包含如下字段(字段与字段之间以逗号间隔): Nowcoder_ID:用户ID Level:等级 Achievement_value:成就值 Num_of_exercise&a…...
盲盒如何创业?
所谓的“盲盒”,受众群体大部分是那些爱碰运气的人,顾客买的是那种在打开盲盒时一刹那的惊喜感和神秘感,在打开盲盒之前,谁也不知道自己会得到什么,这也是为什么消费者更愿意购买的原因。网上的盲盒,主要是…...
第1集丨Java中面向对象相关概念汇总
目录一、基本概念1.1 类1.2 属性1.3 方法1.4 静态1.5 包1.6 import二、高级概念2.1 构造方法2.2 继承2.3 super & this2.4 多态2.5 方法重载2.6 方法重写2.7 访问权限2.8 内部类2.9 final2.10 抽象2.11 接口2.12 匿名类面向对象的编程思想力图使计算机语言中对事物的描述与…...

高性能(二)
三、读写分离和分库分表 1.读写分离 1.1 概述 将数据库的读写操作分散到不同的数据库节点上 通常一主多从一台主数据库负责写,多台从数据库负责读。 主库和从库之间会进行数据同步,以保证从库中数据的准确性。 1.2 问题及解决 1.2.1 问题 主从同…...

Allegro如何实现同一个屏幕界面分屏显示操作指导
Allegro如何实现同一个屏幕界面分屏显示操作指导 在做PCB设计的时候,会需要分屏显示,比如一边是放大的视图,另外一边是缩小的视图,Allegro支持同一个屏幕界面下进行分屏显示,如下图 而且会实时同步起来 如何分屏,具体操作如下 点击View...

前后端一些下载与配置(第二篇 第10天过后)nuxt banner redis 短信服务
NUXT 应该是不用怎么装? 有现成的 axios 还需要在npm吗 好像已经有现成的了 banner banner 笔记汇总P396 Redis Linux安装redis tar -xzvf redis-6.2.6.tar.gz cd redis-6.2.6 照着他做 然后 cd /usr/local/redis/bin ./redis-server /usr/local/redis…...
OSG三维渲染引擎编程学习之四十八:“第五章:OSG场景渲染” 之 “5.6 多重纹理映射”
目录 第五章 OSG场景渲染 5.6 多重纹理映射 5.6.1 多重纹理映射介绍 5.6.2 多重纹理映射示例...

对Node.js 的理解?优缺点?应用场景?
一、是什么 Node.js 是一个开源与跨平台的 JavaScript 运行时环境 在浏览器外运行 V8 JavaScript 引擎(Google Chrome 的内核),利用事件驱动、非阻塞和异步输入输出模型等技术提高性能 可以理解为 Node.js 就是一个服务器端的、非阻塞式I/…...
Bean的生命周期
所谓的生命周期指的是一个对象从诞生到销毁的整个生命过程,我们把这个过程就叫做一个对象的生命周期~~ Bean的生命周期分为以下五大部分: 实例化(为 Bean 分配内存空间) 设置属性(Bean对象注入/装配) 初…...
Python学习-----函数2.0(函数对象,名称空间,作用域-->全局变量与局部变量)
目录 前言: 1.函数对象 (1)函数对象的引用 (2)函数可以放到序列里面 (3)函数可以作为参数 , 传递给另一个函数 2.名称空间 3.作用域 (1)作用域的理解 …...
Java中Json字符串和Java对象的互转
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。诞生于 2002 年。易于人阅读和编写。同时也易于机器解析和生成。JSON 是目前主流的前后端数据传输方式。 JSON 采用完全独立于语言的文本格式,但是也使用了类似于 C 语言家族的…...
代码随想录NO42 | 动态规划_Leetcode70. 爬楼梯 (进阶) 322. 零钱兑换 279.完全平方数
动态规划_Leetcode70. 爬楼梯 (进阶) 322. 零钱兑换 279.完全平方数70. 爬楼梯 (进阶) 在原题基础上,改为:一步一个台阶,两个台阶,三个台阶,…,直到 m个台阶…...

【C++从入门到放弃】初识C++(基础知识入门详解)
🧑💻作者: 情话0.0 📝专栏:《C从入门到放弃》 👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢! C基础…...
企业工程项目管理系统源码+spring cloud 系统管理+java 系统设置+二次开发
工程项目各模块及其功能点清单 一、系统管理 1、数据字典:实现对数据字典标签的增删改查操作 2、编码管理:实现对系统编码的增删改查操作 3、用户管理:管理和查看用户角色 4、菜单管理:实现对系统菜单的增删改查操…...

【GPLT 三阶题目集】L3-016 二叉搜索树的结构
二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分…...
核心交换机安全多业务高性能万兆交换机
RG-S5750-24SFP/12GT交换机是锐捷网络推出的融合了高性能、高安全、多业务的新一代三层交换机。RG-S5750-24SFP/12GT 交换机能够提供灵活的介质接口,满足网络建设中不同介质的连接需要。全千兆的端口形态,加上可扩展的高密度万兆端口,提供1&a…...
Android APK 签名打包原理分析(三)【静默安装的实现方案】
背景 小编目前从事的系统定制类工作,有客户提出了,需要后台“静默安装”他们的app,也就是悄无声息的安装,而且特别强调,不可以跳出任何安装引导页面,他们的app下载完成之后,后台调用公开的android install代码,系统就后台完成安装,安装完成之后,重新打开应用就可以。…...
mulesoft MCIA 破釜沉舟备考 2023.02.14.05
mulesoft MCIA 破釜沉舟备考 2023.02.14.05 1. Refer to the exhibit.2. A Kubernetes controller automatically adds another pod replica to the resource pool in response to increased application load.3. An XA transaction Is being configured that involves a JMS c…...

结构体的三种定义方法、结构体类型名(可选标志符)什么时候可以省略
结构体的三种定义方法 一、单独定义: 先定义结构体类型,再定义变量 定义结构体的格式如下: struct 结构体名 { 若干数据项; } ; 其中,struct为关键字; 结构体名是用户定…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...

springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...