Hazel游戏引擎(005)

news2024/12/22 23:34:43

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

我写的项目地址: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 CLIENT
    	Application* 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 CLIENT
    	Application* 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.coloradmin.cn/o/344420.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5、MyBatis框架——Mapper接口映射、给类起别名、MyBatis开启驼峰映射、MyBatis开启日志打印

目录 一、Mapper接口映射 1、创建数据库 2、搭建MVC分层结构 3、配置MyBatis全局参数 4、编辑DAO层接口 5、配置Mapper文件与DAO层绑定 &#xff08;1&#xff09;配置Mapper文件 &#xff08;2&#xff09;DAO层与Mapper文件标签的快速生成 6、代码测试 二、给类起别…

python|第四章考试题及练习题

本篇文章是对北京理工大学嵩天老师的《Python语言程序设计》第四章考试题及练习题的学习记录。 一、考试题 1、四位玫瑰数 问题描述&#xff1a; 四位玫瑰数是4位数的自幂数。自幂数是指一个 n 位数&#xff0c;它的每个位上的数字的 n 次幂之和等于它本身。‪‬‪‬‪‬‪‬…

【云原生-Docker】docker容器自定义DNS解析

描述 在特定的情况下&#xff0c;或者在网络策略特殊定义下&#xff0c;需要自定义dns进行域名访问&#xff0c;在宿主机上配置了域名解析&#xff0c;对于docker容器无效。对于局域网内的域名解析&#xff0c;Docker 需要到 Docker 容器中配置 hosts 文件。 实现方式 docke…

使用Pandas也可以进行数据可视化

数据可视化是数据分析的一个重要方面&#xff0c;它提供了一种理解数据并从中得出有意义见解的方法。Pandas 是最常见的于数据分析的 Python 库&#xff0c;它基于Matplotlib扩展了一些常用的可视化图表&#xff0c;可以方便的调用&#xff0c;本篇文章就让我们看看有哪些图表可…

使用JavaScript+Selenium玩转Web应用自动化测试

自动化测试 在软件开发过程中, 测试是功能验收的必要过程, 这个过程往往有测试人员参与, 提前编写测试用例, 然后再手动对测试用例进行测试, 测试用例都通过之后则可以认为该功能通过验收. 但是软件中多个功能之间往往存在关联或依赖关系, 某一个功能的新增或修改可能或影响到…

牛客网Python篇数据分析习题(四)

1.现有一个Nowcoder.csv文件&#xff0c;它记录了牛客网的部分用户数据&#xff0c;包含如下字段&#xff08;字段与字段之间以逗号间隔&#xff09;&#xff1a; Nowcoder_ID&#xff1a;用户ID Level&#xff1a;等级 Achievement_value&#xff1a;成就值 Num_of_exercise&a…

每日学术速递2.14

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CL 1.Type-Aware Decomposed Framework for Few-Shot Named Entity Recognition 标题&#xff1a;识别少数命名实体的类型感知分解框架 作者&#xff1a;Yongqi Li, Tieyun Qian 文章链…

Flink 连接流详解

连接流 1 Union 最简单的合流操作&#xff0c;就是直接将多条流合在一起&#xff0c;叫作流的“联合”&#xff08;union&#xff09;。联合操作要求必须流中的数据类型必须相同&#xff0c;合并之后的新流会包括所有流中的元素&#xff0c;数据类型不变。这种合流方式非常简…

tensorflow.js 对视频 / 直播人脸检测和特征点收集

前言&#xff1a;这里要介绍的是 Tensorflow.js 官方提供的两个人脸检测模型&#xff0c;分别是 face-detection 和 face-landmarks-detection。他们不但可以对视频中的人间进行精确定位&#xff0c;而且还能对当前设备 (手机 / 电脑摄像头) 采集的直播流实时监测人脸。所以这些…

大华城市安防监控系统平台管理存在任意文件下载漏洞

大华城市安防监控系统平台管理存在任意文件下载漏洞1.大华城市安防监控系统平台管理存在任意文件下载漏洞1.1.漏洞描述1.2.漏洞影响1.3.FOFA2.漏洞复现2.1.登录页面2.2.抓包1.大华城市安防监控系统平台管理存在任意文件下载漏洞 1.1.漏洞描述 大华城市安防监控系统平台管理存在…

企业级数据平台为什么要“可观测”? | StartDT Hackathon

近日&#xff0c;奇点云黑客马拉松“StartDT Hackathon”正式收官。 这期黑客松以“可观测性”为核心选题&#xff0c;旨在通过加强数据云平台DataSimba的可观测性&#xff0c;提升企业用户“自交付、自运维”的易用性和友好度&#xff0c;降低运维门槛&#xff0c;提升发现、…

4.7 反射

文章目录1.概述2.为什么需要反射3.反射需要用到的API3.1 获取字节码对象3.2 常用方法4.反射的应用4.1 创建 : 测试物料类4.2 练习 : 获取类对象4.3 练习 : 类获取构造方法4.4 练习 : 获取成员方法4.5 练习&#xff1a;获取成员变量4.6 练习 : 创建对象4.7 熟悉API4.7.1 创建物科…

定时任务框架xxl-job及quartz

本文主要介绍分布式定时任务框架xxl-job&#xff0c;本文首先会对xxl-job做一个基本的介绍&#xff0c;接着将xxl-job与quartz做一个比较&#xff0c;最后就是介绍xxl-job调度的详细过程。 xxl-job官方文档 xxl-job的介绍 xxl-job是一个开源的分布式定时任务框架&#xff0c;其…

若依前后端分离版集成nacos

根据公司要求&#xff0c;需要将项目集成到nacos中&#xff0c;当前项目是基于若依前后端分离版开发的&#xff0c;若依的版本为3.8.3&#xff0c;若依框架中整合的springBoot版本为2.5.14。Nacos核心提供两个功能&#xff1a;服务注册与发现&#xff0c;动态配置管理。 一、服…

【django项目开发】用户登录后缓存权限到redis中(十)

这里写目录标题一、权限的数据的特点二、首先settings.py文件中配置redis连接redis数据库一、权限的数据的特点 需要去数据库中频繁的读和写&#xff0c;为了项目提高运行效率&#xff0c;可以把用户的权限在每次登录的时候都缓存到redis中。这样的话&#xff0c;权限判断的中…

基于投票策略的室内家具检测:VoteNet、BRNet 最全总结

文章目录一、基本概述二、VoteNet三、BRNet四、最新研究成果一、基本概述 最近几年&#xff0c;基于点云的3D目标检测是自动驾驶场景研究的热点。但是&#xff0c;自动驾驶主要聚焦于室外场景。本文&#xff0c;我们主要介绍两篇文章&#xff08;VoteNet&#xff0c;BRNet&…

HTML第一章总结

<h1~h6>标题标签 <br />换行标签&#xff08;单&#xff09; <p>分段标签 <strong>加粗标签 <em>倾斜标签 <del>删除线标签 <ins>下划线标签 <div>独占一行的布局标签 <span>进行分割的布局标签 <img>图片标签&a…

Go-micro[windows]安装以及踩坑

一.首先安装protochttps://github.com/protocolbuffers/protobuf/releases进入网址&#xff0c;点击tag&#xff0c;然后选择v3版本进入之后找到随后下载安装然后将protoc解压缩到任意目录&#xff08;自己选&#xff09;再将protoc/bin的路径放置环境变量中二.获取protoc-gen-…

RK3568 UBOOT的问题解决案例

一、UBOOT下的波特率 原始的波特率为1500000,串口工具虽然可以设置任意波特率&#xff0c;但工作时不正常。 输入不了。本文描述如何修改成115200。 二、确认UBOOT的配置 ./build.sh uboot processing option: uboot Start building uboot TARGET_UBOOT_CONFIGrk3568## make …

【C++】二叉树之力扣经典题目1——详解二叉树的递归遍历,二叉树的层次遍历

如有错误&#xff0c;欢迎指正。 如有不理解的地方&#xff0c;可以私信问我。 文章目录题目1&#xff1a;根据二叉树创建字符串题目实例思路与解析代码实现题目2&#xff1a;二叉树的层序遍历题目思路与解析代码实现题目1&#xff1a;根据二叉树创建字符串 点击进入题目链接—…