跟着cherno手搓游戏引擎【3】事件系统和预编译头文件

news2024/11/26 13:56:28

不多说了直接上代码,课程中的架构讲的比较宽泛,而且有些方法写完之后并未测试。所以先把代码写完。理解其原理,未来使用时候会再此完善此博客。

文件架构:

Event.h:核心基类

#pragma once
#include"../Core.h"
#include<string>
#include<functional>
namespace YOTO {
	// Hazel中的事件当前是阻塞的,这意味着当一个事件发生时,它立即被分派,必须立即处理。
	//将来,一个更好的策略可能是在事件总线中缓冲事件,并在更新阶段的“事件”部分处理它们。
	//事件类型
	enum class EventType
	{
		None = 0,
		WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved,
		AppTick, AppUpdate, AppRender,
		KeyPressed, KeyReleased,
		MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled
	};
	//事件分类
	enum EventCategory {
		None = 0,
		EventCategoryApplication = BIT(0),
		EventCategoryInput = BIT(1),
		EventCategoryKeyboard = BIT(2),
		EventCategoryMouse = BIT(3),
		EventCategoryMouseButton = BIT(4)
	};
	//定义一些重复的重写的函数,只需要传入固定参数,就能少些一大部分代码
#define EVENT_CLASS_TYPE(type) static EventType GetStaticType(){return EventType::##type; }\
								virtual EventType GetEventType() const override {return GetStaticType();}\
								virtual const char* GetName() const override {return #type;}
#define EVENT_CLASS_CATEGORY(category) virtual int GetCategoryFlags() const override {return category; }
	/// <summary>
	/// 事件基类,事件需要继承此类
	/// </summary>
	class Event
	{
	public:
		//获得该事件的具体类型
		virtual EventType GetEventType() const = 0;
		//获得事件的名称
		virtual const char* GetName() const = 0;
		//获得该事件的大类型
		virtual int GetCategoryFlags() const = 0;
		//toString方法,返回事件名
		virtual std::string ToString() const { return GetName(); }
		//判断该事件是否是category类
		inline bool IsInCategory(EventCategory category) {
			return GetCategoryFlags() & category;
		}

	protected:
		//事件是否被处理了
		bool m_Handled = false;
	};
	/// <summary>
	/// 基于事件类型调度事件的方法(暂时没有测试,不知道怎么用)
	/// </summary>
	class EventDispatcher
	{
		template <typename T>
		using EventFn = std::function<bool(T&)>;

	public:
		EventDispatcher(Event& event)
			:m_Event(event) {

		}
		template <typename T>
		bool Dispatch(EventFn<T> func) {
			if (m_Event.GetEventType() == T::GetStaticType()) {
				m_Event.m_Handled = func(*(T*)&m_Event);
				return true;
			}
			return false;
		}

	private:
		Event& m_Event;
	};
	//暂无测试,方便输出
	inline std::ostream& operator<<(std::ostream& os, const Event& e){
		return  os << e.ToString();
	}



}

 ApplicationEvent.h:处理appwindow的各种事件

#pragma once
#include"Event.h"
#include<sstream>
namespace YOTO {
	class YOTO_API WindowResizeEvent :public Event {
	public:
		WindowResizeEvent(unsigned int width, unsigned int height) :m_Width(width), m_Height(height) {}
		inline unsigned int GetWidth() const { return m_Width; }
		inline unsigned int GetHeight() const { return m_Height; }
		std::string ToString() const override {
			std::stringstream ss;
			ss << "窗口大小改变事件:" << m_Width << "," << m_Height;
			return ss.str();
		}
		EVENT_CLASS_TYPE(WindowResize)
		EVENT_CLASS_CATEGORY(EventCategoryApplication)
	private:
		unsigned int m_Width, m_Height;
	};
	class YOTO_API WindowCloseEvent :public Event
	{
	public:
		WindowCloseEvent(){}
		EVENT_CLASS_TYPE(WindowClose)
		EVENT_CLASS_CATEGORY(EventCategoryApplication)
	};
	class YOTO_API AppTickEvent :public Event {
	public:
		AppTickEvent(){}
		EVENT_CLASS_TYPE(AppTick)
		EVENT_CLASS_CATEGORY(EventCategoryApplication)
	};
	class YOTO_API AppUpdateEvent :public Event {
	public:
		AppUpdateEvent(){}
		EVENT_CLASS_TYPE(AppUpdate)
		EVENT_CLASS_CATEGORY(EventCategoryApplication)
	};
	class YOTO_API AppRenderEvent :public Event {
	public:
		AppRenderEvent() {}
		EVENT_CLASS_TYPE(AppRender)
		EVENT_CLASS_CATEGORY(EventCategoryApplication)
	};
}

KeyEvent.h:处理键盘事件

#pragma once
#include"Event.h"
#include<sstream>
namespace YOTO {
	class YOTO_API KeyEvent:public Event
	{
	public:
		inline int GetKeyCode() const { return m_KeyCode; }
		EVENT_CLASS_CATEGORY(EventCategoryKeyboard | EventCategoryInput)
	protected:
		KeyEvent(int keycode)
			:m_KeyCode(keycode){}
		int m_KeyCode;

	};

	class YOTO_API KeyPressedEvent :public KeyEvent
	{
	public:
		KeyPressedEvent(int keycode, int repeatCount)
			:KeyEvent(keycode),m_RepeatCount(repeatCount){}
		inline int GetRepeatCount() const { return m_RepeatCount; }
		std::string ToString() const override{
			std::stringstream ss;
			ss << "键盘按下事件:" << m_KeyCode << "(" << m_RepeatCount << "重复)";
			return ss.str();
		}
		//static EventType GetStaticType() { return EventType::KeyPressed; }
		//virtual EventType GetEventType()const override { return GetStaticType(); }
		//virtual const char* GetName()const override { return "KeyPressed"; }
		EVENT_CLASS_TYPE(KeyPressed)
	private:
		int m_RepeatCount;

	};
	class KeyReleasedEvent:public KeyEvent
	{
	public:
		KeyReleasedEvent(int keycode)
		:KeyEvent(keycode){

		}
		std::string ToString()const override {
			std::stringstream ss;
			ss << "键盘释放事件:" << m_KeyCode;
			return ss.str(); 
		}
	EVENT_CLASS_TYPE(KeyReleased)
			
	};

}

 MouseEvent.h:处理鼠标事件

#pragma once
#include"Event.h"
#include<sstream>
namespace YOTO {

	class YOTO_API MouseMovedEvent :public Event
	{
	public:
		MouseMovedEvent(float x, float y)
			:m_MouseX(x), m_MouseY(y) {}
		inline float GetX() const { return m_MouseX; }
		inline float GetY() const { return m_MouseY; }
		std::string ToString() const override {
			std::stringstream ss;
			ss << "鼠标移动事件:" << m_MouseX << "," << m_MouseY;
			return ss.str();
		}
		EVENT_CLASS_TYPE(MouseMoved)
		EVENT_CLASS_CATEGORY(EventCategoryMouse |EventCategoryInput )
	private:
		float m_MouseX, m_MouseY;
	};

	class YOTO_API MouseScrolledEvent :public Event
	{
	public:
		MouseScrolledEvent(float x, float y)
			:m_XOffset(x), m_YOffset(y) {}
		inline float GetXOffset() const { return m_XOffset; }
		inline float GetYOffset() const { return m_YOffset; }
		std::string ToString() const override {
			std::stringstream ss;
			ss << "鼠标滚动事件:" << GetXOffset() << "," << GetYOffset();
			return ss.str();
		}
		EVENT_CLASS_TYPE(MouseScrolled)
			EVENT_CLASS_CATEGORY(EventCategoryMouse | EventCategoryInput)
	private:
		float m_XOffset, m_YOffset;
	};

	class YOTO_API MouseButtonEvent :public Event
	{
	public:
		inline int GetMouseButton() const { return m_Button; }
		EVENT_CLASS_CATEGORY(EventCategoryMouse | EventCategoryInput)

	protected:
		MouseButtonEvent(int button)
			:m_Button(button){}
		int m_Button;

	};
	class YOTO_API MouseButtonPressedEvent :public MouseButtonEvent
	{
	public:
		MouseButtonPressedEvent(int button) 
			:MouseButtonEvent(button) {}
		std::string ToString() const override {
			std::stringstream ss;
			ss << "鼠标按下事件:" << m_Button;
			return ss.str();
		}
	EVENT_CLASS_TYPE(MouseButtonPressed)
	};
	class YOTO_API MouseButtonReleasedEvent :public MouseButtonEvent
	{
	public:
		MouseButtonReleasedEvent(int button)
			:MouseButtonEvent(button) {}
		std::string ToString() const override {
			std::stringstream ss;
			ss << "鼠标松开事件:" << m_Button;
			return ss.str();
		}
		EVENT_CLASS_TYPE(MouseButtonReleased)
	};
}

说白了就是写了个基类,然后写了实现类。

修改:

Core.h

#pragma once
//用于dll的宏
#ifdef YT_PLATFORM_WINDOWS
#ifdef YT_BUILD_DLL
#define YOTO_API __declspec(dllexport) 
#else
#define YOTO_API __declspec(dllimport) 

#endif // DEBUG
#else
#error YOTO_ONLY_SUPPORT_WINDOWS
#endif // YOTO_PLATFORM_WINDOWS
#define BIT(x)(1<<x)

记得加Event.h的头文件

premake5.lua

workspace "YOTOEngine"		-- sln文件名
	architecture "x64"	
	configurations{
		"Debug",
		"Release",
		"Dist"
	}
-- https://github.com/premake/premake-core/wiki/Tokens#value-tokens
-- 组成输出目录:Debug-windows-x86_64
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"

project "YOTOEngine"		--Hazel项目
	location "YOTOEngine"--在sln所属文件夹下的Hazel文件夹
	kind "SharedLib"--dll动态库
	language "C++"
	targetdir ("bin/" .. outputdir .. "/%{prj.name}") -- 输出目录
	objdir ("bin-int/" .. outputdir .. "/%{prj.name}")-- 中间目录

	-- 包含的所有h和cpp文件
	files{
		"%{prj.name}/src/**.h",
		"%{prj.name}/src/**.cpp"
	}
	-- 包含目录
	includedirs{
		"%{prj.name}/src",
		"%{prj.name}/vendor/spdlog-1.x/include"
	}
	-- 如果是window系统
	filter "system:windows"
		cppdialect "C++17"
		-- On:代码生成的运行库选项是MTD,静态链接MSVCRT.lib库;
		-- Off:代码生成的运行库选项是MDD,动态链接MSVCRT.dll库;打包后的exe放到另一台电脑上若无这个dll会报错
		staticruntime "On"	
		systemversion "latest"	-- windowSDK版本
		-- 预处理器定义
		defines{
			"YT_PLATFORM_WINDOWS",
			"YT_BUILD_DLL"
		}
		-- 编译好后移动Hazel.dll文件到Sandbox文件夹下
		postbuildcommands{
			("{COPY} %{cfg.buildtarget.relpath} ../bin/" .. outputdir .. "/Sandbox")
		}
	-- 不同配置下的预定义不同
	filter "configurations:Debug"
		defines "YT_DEBUG"
		symbols "On"

	filter "configurations:Release"
		defines "YT_RELEASE"
		optimize "On"

	filter "configurations:Dist"
		defines "YT_DIST"
		optimize "On"

project "Sandbox"
	location "Sandbox"
	kind "ConsoleApp"
	language "C++"

	targetdir ("bin/" .. outputdir .. "/%{prj.name}")
	objdir ("bin-int/" .. outputdir .. "/%{prj.name}")

	files{
		"%{prj.name}/src/**.h",
		"%{prj.name}/src/**.cpp"
	}
	-- 同样包含spdlog头文件
	includedirs{
		"YOTOEngine/vendor/spdlog-1.x/include",
		"YOTOEngine/src"
	}
	-- 引用hazel
	links{
		"YOTOEngine"
	}

	filter "system:windows"
		cppdialect "C++17"
		staticruntime "On"
		systemversion "latest"

		defines{
			"YT_PLATFORM_WINDOWS"
		}

	filter "configurations:Debug"
		defines "YT_DEBUG"
		symbols "On"

	filter "configurations:Release"
		defines "YT_RELEASE"
		optimize "On"

	filter "configurations:Dist"
		defines "YT_DIST"
		optimize "On"

测试: 

Application.cpp

#include "Application.h"
#include"Event/ApplicationEvent.h"
#include"Log.h"
namespace YOTO {
	Application::Application() {

	}
	Application::~Application() {

	}
	void Application::Run() {
		WindowResizeEvent e(1280, 720);
		if (e.IsInCategory(EventCategoryApplication)) {
			YT_CORE_TRACE(e);
		}
		if (e.IsInCategory(EventCategoryInput)) {
			YT_CORE_ERROR(e);
		}

		while (true)
		{

		}
	}
}

 预编译头文件:

ytpch.h

#pragma once
#include<iostream>
#include<memory>
#include<utility>
#include<algorithm>
#include<functional>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<sstream>
#ifdef YT_PLATFORM_WINDOWS
#include<Windows.h>
#endif // YT_PLATFORM_WINDOWS


ytpch.cpp

#include "ytpch.h"

premake5.lua:

workspace "YOTOEngine"		-- sln文件名
	architecture "x64"	
	configurations{
		"Debug",
		"Release",
		"Dist"
	}
-- https://github.com/premake/premake-core/wiki/Tokens#value-tokens
-- 组成输出目录:Debug-windows-x86_64
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"

project "YOTOEngine"		--Hazel项目
	location "YOTOEngine"--在sln所属文件夹下的Hazel文件夹
	kind "SharedLib"--dll动态库
	language "C++"
	targetdir ("bin/" .. outputdir .. "/%{prj.name}") -- 输出目录
	objdir ("bin-int/" .. outputdir .. "/%{prj.name}")-- 中间目录
	pchheader "ytpch.h"
	pchsource "YOTOEngine/src/ytpch.cpp"
	-- 包含的所有h和cpp文件
	files{
		"%{prj.name}/src/**.h",
		"%{prj.name}/src/**.cpp"
	}
	-- 包含目录
	includedirs{
		"%{prj.name}/src",
		"%{prj.name}/vendor/spdlog-1.x/include"
	}
	-- 如果是window系统
	filter "system:windows"
		cppdialect "C++17"
		-- On:代码生成的运行库选项是MTD,静态链接MSVCRT.lib库;
		-- Off:代码生成的运行库选项是MDD,动态链接MSVCRT.dll库;打包后的exe放到另一台电脑上若无这个dll会报错
		staticruntime "On"	
		systemversion "latest"	-- windowSDK版本
		-- 预处理器定义
		defines{
			"YT_PLATFORM_WINDOWS",
			"YT_BUILD_DLL"
		}
		-- 编译好后移动Hazel.dll文件到Sandbox文件夹下
		postbuildcommands{
			("{COPY} %{cfg.buildtarget.relpath} ../bin/" .. outputdir .. "/Sandbox")
		}
	-- 不同配置下的预定义不同
	filter "configurations:Debug"
		defines "YT_DEBUG"
		symbols "On"

	filter "configurations:Release"
		defines "YT_RELEASE"
		optimize "On"

	filter "configurations:Dist"
		defines "YT_DIST"
		optimize "On"

project "Sandbox"
	location "Sandbox"
	kind "ConsoleApp"
	language "C++"

	targetdir ("bin/" .. outputdir .. "/%{prj.name}")
	objdir ("bin-int/" .. outputdir .. "/%{prj.name}")

	files{
		"%{prj.name}/src/**.h",
		"%{prj.name}/src/**.cpp"
	}
	-- 同样包含spdlog头文件
	includedirs{
		"YOTOEngine/vendor/spdlog-1.x/include",
		"YOTOEngine/src"
	}
	-- 引用hazel
	links{
		"YOTOEngine"
	}

	filter "system:windows"
		cppdialect "C++17"
		staticruntime "On"
		systemversion "latest"

		defines{
			"YT_PLATFORM_WINDOWS"
		}

	filter "configurations:Debug"
		defines "YT_DEBUG"
		symbols "On"

	filter "configurations:Release"
		defines "YT_RELEASE"
		optimize "On"

	filter "configurations:Dist"
		defines "YT_DIST"
		optimize "On"

把所有使用库文件的地方都换成#include"ytpch.h"即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1349670.html

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

相关文章

javaScript中的常用事件

文章目录 javaScript中什么是事件&#xff1f;基本原理javaScript中的时间使用1&#xff0c;窗口事件1.1、onblur1.2、onfocus1.3、onload1.4、onresize 2&#xff0c;表单事件2.1、onchange2.2、**oninput**2.3、oninvalid2.4、onselect2.5、onsubmit 3&#xff0c;键盘事件3.…

最优化总结

最优化 引入问题例1 运输问题例2 生产计划问题例3 指派问题例4 数据拟合问题 线性规划向量和矩阵范数拟合线性拟合非线性拟合 无约束最优化问题的基本思想实验plot函数meshgrid函数linprog函数 引入问题 例1 运输问题 例2 生产计划问题 例3 指派问题 例4 数据拟合问题 线性规划…

BGP路由知识点

目录 1.BGP的工作原理&#xff1a; 2.BGP路由的一般格式&#xff1a; 3.三种不同的自治系统AS 4.BGP的路由选择 5.BGP的四种报文 BGP&#xff08;Border Gateway Protocol&#xff09;是一种用于自治系统&#xff08;AS&#xff09;之间的路由选择协议。它是互联网中最常用…

如何确保云中高可用?聊聊F5分布式云DNS负载均衡

在当今以应用为中心的动态化市场中&#xff0c;企业面临着越来越大的压力&#xff0c;不仅需要提供客户所期望的信息、服务和体验&#xff0c;而且要做到快速、可靠和安全。DNS是网络基础设施的重要组成部分&#xff0c;拥有一个可用的、智能的、安全和可扩展的DNS基础设施是至…

面试高频算法专题:数组的双指针思想及应用(算法村第三关白银挑战)

所谓的双指针其实就是两个变量&#xff0c;不一定真的是指针。 快慢指针&#xff1a;一起向前走对撞指针、相向指针&#xff1a;从两头向中间走背向指针&#xff1a;从中间向两头走 移除值为val的元素 题目描述 27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 给你…

IoT 物联网常用协议

物联网协议是指在物联网环境中用于设备间通信和数据传输的协议。根据不同的作用&#xff0c;物联网协议可分为传输协议、通信协议和行业协议。 传输协议&#xff1a;一般负责子网内设备间的组网及通信。例如 Wi-Fi、Ethernet、NFC、 Zigbee、Bluetooth、GPRS、3G/4G/5G等。这些…

ArkTS - @Prop、@Link

一、作用 Prop 装饰器 和Link装饰器都是父组件向子组件传递参数&#xff0c;子组件接收父组件参数的时候用的&#xff0c;变量前边需要加上Prop或者Link装饰器即可。&#xff08;跟前端vue中父组件向子组件传递参数类似&#xff09; // 子组件 Component struct SonCom {Prop…

python实现Ethernet/IP协议的客户端(二)

Ethernet/IP是一种工业自动化领域中常用的网络通信协议&#xff0c;它是基于标准以太网技术的应用层协议。作为工业领域的通信协议之一&#xff0c;Ethernet/IP 提供了一种在工业自动化设备之间实现通信和数据交换的标准化方法。python要实现Ethernet/IP的客户端&#xff0c;可…

影视后期: PR调色处理,调色工具面板介绍

写在前面 整理一些影视后期的相关笔记博文为 Pr 调色处理&#xff0c;涉及调色工具面板简单认知包括 lumetri 颜色和范围面板理解不足小伙伴帮忙指正 元旦快乐哦 _ 名词解释 饱和度 是指色彩的鲜艳程度&#xff0c;也被称为色彩的纯度。具体来说&#xff0c;它表示色相中灰色…

python实现平滑线性滤波器——数字图像处理

原理&#xff1a; 平滑线性滤波器是一种在图像处理中广泛使用的工具&#xff0c;主要用于降低图像噪声或模糊细节。这些滤波器的核心原理基于对图像中每个像素及其邻域像素的线性组合。 邻域平均&#xff1a; 平滑线性滤波器通过对目标像素及其周围邻域像素的强度值取平均来工…

Linux驱动学习—ioctl接口

1、unlock_ioctl和ioctl有什么区别&#xff1f; kernel 2.6.36 中已经完全删除了struct file_operations 中的ioctl 函数指针&#xff0c;取而代之的是unlocked_ioctl 。ioctl是老的内核版本中的驱动API&#xff0c;unlock_ioctl是当下常用的驱动API。unlocked_ioctl 实际上取…

易舟云财务软件使用教程【文章目录】

易舟云财务软件使用教程【文章目录】 1、财务软件导论2、易舟云财务软件3、财务软件原理4、账套5、会计凭证6、资金日记账7、发票8、员工工资9、固定资产10、期末处理(结转与结账)11、会计账簿12、财务报表13、财务软件设置 1、财务软件导论 财务软件导论 2、易舟云财务软件 …

STM32与TB6612电机驱动器的基础入门教程

TB6612是一款常用的双路直流电机驱动芯片&#xff0c;适用于小型机器人以及其他需要控制电机方向和转速的应用。在STM32微控制器的配合下&#xff0c;可以实现对TB6612电机驱动器的控制&#xff0c;进而实现电机的控制。本文将带领读者一步步了解如何搭建基于STM32与TB6612的电…

Android 13 - Media框架(29)- MediaCodec(四)

上一节我们了解了如何通过 onInputBufferAvailable 和 getInputBuffer 获取到 input buffer index&#xff0c;接下来我们一起学习上层如何拿到buffer并且向下写数据的。 1、获取 input Buffer 获取 MediaCodec 中的 buffer 有两种方式&#xff0c;一种是调用 getInputBuffers…

Linux:/proc/sys/vm/目录各文件详解

目录 前言一、/proc/sys/vm/目录各文件二、相关功能的API函数 前言 /proc/sys/vm/ 目录是 Linux 系统中的一个特殊目录&#xff0c;它包含了与虚拟内存子系统相关的系统内核参数。这些参数可以用来配置系统的虚拟内存管理策略&#xff0c;包括内存分配、页面置换、内存压缩、NU…

【软件工程】航行敏捷之路:深度解析Scrum框架的精髓

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 软件工程 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 Scrum&#xff08;敏捷开发框架之一&#xff09; 详细介绍和解释&#xff1a; 优缺点&#xff1a; 优点&#xff1a; 缺点&…

2.3 设计FMEA步骤三:功能分析

2.3.1 目的 设计功能分析确保要求/规范中的功能适当分配给系统要素。分析必须使用功能术语进行编写。 功能分析地主要目标是: 产品或过程功能可视化。制作功能树/网或功能分析表格和参数图(P图)。展开与顾客(内部和外部)功能相关的要求。将要求或特性与功能关联。促进工…

cocos creator + vscode debug

安装插件 安装插件&#xff1a;JavaScript Debugger 配置 7456 为本地cocos creator的启动端口 启动debug调试 选择对应的启动方式

计算机网络第一课

先了解层级&#xff1a; 传输的信息称为协议数据单元&#xff08;PDU&#xff09;&#xff0c;PDU在每个层次的称呼都不同&#xff0c;见下图&#xff1a;

关于MySQL Cluster

目录 1.MySQL Cluster2.MySQL Cluster架构3.MySQL Cluster 与 MySQL 主从架构有什么区别4.参考 MySQL Cluster是MySQL的一个高可用性&#xff0c;高性能的分布式数据库解决方案。它结合了内存数据库和共享无状态架构的技术&#xff0c;提供了99.999%的可用性&#xff0c;满足严…