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; } #endifmain函数中执行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为关键字; 结构体名是用户定…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
