跟着cherno手搓游戏引擎【6】ImGui和ImGui事件

这篇具有很好参考价值的文章主要介绍了跟着cherno手搓游戏引擎【6】ImGui和ImGui事件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

导入ImGui:

下载链接:

GitHub - TheCherno/imgui: Dear ImGui: Bloat-free Immediate Mode Graphical User interface for C++ with minimal dependencies

 新建文件夹,把下载好的文件放入对应路径:

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

 SRC下的premake5.lua文件:添加ImGui

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}"
-- 包含相对解决方案的目录
IncludeDir={}
IncludeDir["GLFW"]="YOTOEngine/vendor/GLFW/include"
IncludeDir["Glad"]="YOTOEngine/vendor/Glad/include"
IncludeDir["ImGui"] ="YOTOEngine/vendor/imgui"
--项目中包含某包
include "YOTOEngine/vendor/GLFW"
include "YOTOEngine/vendor/Glad"
include "YOTOEngine/vendor/imgui"

project "YOTOEngine"		--YOTOEngine项目
	location "YOTOEngine"--在sln所属文件夹下的YOTOEngine文件夹
	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",
		"%{IncludeDir.GLFW}",
		"%{IncludeDir.Glad}",
		"%{IncludeDir.ImGui}"
	}
	links{
		"GLFW",-- GLFW.lib库链接到YOTOEngine项目中
		"Glad",-- Glad.lib库链接到YOTOEngine项目中
		"ImGui",-- ImGui.lib库链接到YOTOEngine项目中
		"opengl32.lib"
	}
	-- 如果是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",
			"YT_ENABLE_ASSERTS",
			"GLFW_INCLUDE_NONE"-- 让GLFW不包含OpenGL
		}
		-- 编译好后移动Hazel.dll文件到Sandbox文件夹下
		postbuildcommands{
			("{COPY} %{cfg.buildtarget.relpath} ../bin/" .. outputdir .. "/Sandbox")
		}
	-- 不同配置下的预定义不同
	filter "configurations:Debug"
		defines "YT_DEBUG"
		buildoptions"/MDd"
		symbols "On"

	filter "configurations:Release"
		defines "YT_RELEASE"
		buildoptions"/MD"
		optimize "On"

	filter "configurations:Dist"
		defines "YT_DIST"
		buildoptions"/MD"
		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"
	}
	-- 引用YOTOEngine
	links{
		"YOTOEngine",
		"GLFW",
		"opengl32.lib"
	}

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

		defines{
			"YT_PLATFORM_WINDOWS"
		}

	filter "configurations:Debug"
		defines "YT_DEBUG"
		buildoptions"/MDd"
		symbols "On"

	filter "configurations:Release"
		defines "YT_RELEASE"
		buildoptions"/MD"
		optimize "On"

	filter "configurations:Dist"
		defines "YT_DIST"
		buildoptions"/MD"
		optimize "On"

在Platform下创建OpenGl,将imgui_impl_opengl3.cpp和.h加入到该文件夹。

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

并且更名:

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

150行改为:#include "backends/imgui_impl_opengl3_loader.h"

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

96行添加:#include"ytpch.h"跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎 至此错误消除,导入成功。

创建ImGui层:

在YOTO下创建ImGui文件夹创建ImGuiLayer.cpp和.h:

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

ImGuiLayer.h:UI层的.h文件

#pragma once
#include"YOTO/Layer.h"
namespace YOTO {

	class YOTO_API ImGuiLayer:public Layer
	{
	public:
		ImGuiLayer();
		~ImGuiLayer();
		void OnAttach();
		void OnDetach();
		void OnUpdate();
		void OnEvent(Event& event);
	private:
		float m_Time = 0.0f;

	};


}

ImGuiLayer.cpp:在层初始化的时候和刷新的时候对io的参数进行修改,达到修改UI的目的

#include"ytpch.h"
#include"ImGuiLayer.h"
#include"Platform/OpenGL/ImGuiOpenGLRenderer.h"
#include"GLFW/glfw3.h"
#include"YOTO/Application.h"
namespace YOTO {
	ImGuiLayer::ImGuiLayer()
	:Layer("ImGuiLayer") {

	}
	ImGuiLayer::~ImGuiLayer() {

	}
	void ImGuiLayer::OnAttach()
	{
		//创建上下文
		ImGui::CreateContext();
		//设置颜色
		ImGui::StyleColorsDark();
		//配置类:ImGuiIO
		ImGuiIO& io = ImGui::GetIO();
		io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;// 光标
		io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;

		// imgui输入key对应glfw的key,临时的:最终会对应引擎自身的key
		io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
		io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
		io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
		io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
		io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
		io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
		io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
		io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
		io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
		io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
		io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
		io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
		io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
		io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
		io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
		io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
		io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
		io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
		io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
		io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
		io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;

		ImGui_ImplOpenGL3_Init("#version 410");
	
	}
	void ImGuiLayer::OnDetach()
	{
	}
	void ImGuiLayer::OnUpdate() {
		//每帧刷新UI配置
		ImGuiIO& io = ImGui::GetIO();
		Application& app = Application::Get();
		//显示的size大小
		io.DisplaySize = ImVec2(app.GetWindow().GetWidth(), app.GetWindow().GetHeight());
	
		
		float time = (float)glfwGetTime();
		//时间
		io.DeltaTime = m_Time > 0.0f ? (time - m_Time) : (1.0f / 60.0f);
		m_Time = time;

		ImGui_ImplOpenGL3_NewFrame();
		ImGui::NewFrame();

		static bool show = true;
		// 显示ImGui Demo
		ImGui::ShowDemoWindow(&show);

		ImGui::Render();
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

	}
	void ImGuiLayer::OnEvent(Event& event) {

	}
}

 Application.h:将Application变为单例,添加Get方法和GetWindow方法

#pragma once
#include"Core.h"
#include"Event/Event.h"
#include"Event/ApplicationEvent.h"
#include "YOTO/Window.h"
#include"YOTO/LayerStack.h"
namespace YOTO {
	class YOTO_API Application
	{
	public:
		Application();
		virtual ~Application();
		void Run();
		void OnEvent(Event &e);
		void PushLayer(Layer* layer);
		void PushOverlay(Layer* layer);

		inline static Application& Get() {return * s_Instance;}
		inline Window& GetWindow() { return *m_Window; }
	private:
		bool  OnWindowClosed(WindowCloseEvent& e);
		std::unique_ptr<Window>  m_Window;
		bool m_Running = true;
		LayerStack m_LayerStack;
		
		static Application* s_Instance;
	};
	//在客户端定义
	Application* CreateApplication();
}

  Application.cpp:构造时候令s_Instance = this

#include"ytpch.h"
#include "Application.h"

#include"Log.h"
#include<glad/glad.h>
namespace YOTO {
#define BIND_EVENT_FN(x) std::bind(&x, this, std::placeholders::_1)

	 Application* Application::s_Instance = nullptr;

	Application::Application() {

		YT_CORE_ASSERT(!s_Instance, "Application需要为空!")
		s_Instance = this;
		//智能指针
		m_Window = std::unique_ptr<Window>(Window::Creat());
		//设置回调函数
		m_Window->SetEventCallback(BIND_EVENT_FN(Application::OnEvent));
		unsigned int id;
		glGenBuffers(1, &id);
	}
	Application::~Application() {

	}
	/// <summary>
	/// 所有的Window事件都会在这触发,作为参数e
	/// </summary>
	/// <param name="e"></param>
	void Application::OnEvent(Event& e) {
		//根据事件类型绑定对应事件
		EventDispatcher dispatcher(e);
		dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(Application::OnWindowClosed));
		//输出事件信息
		YT_CORE_INFO("{0}",e);
		for (auto it = m_LayerStack.end(); it != m_LayerStack.begin();) {
			(*--it)->OnEvent(e);
			if (e.m_Handled)
				break;
		}
	}

	bool Application::OnWindowClosed(WindowCloseEvent& e) {
		m_Running = false;
		return true;
	}
	void Application::Run() {
		WindowResizeEvent e(1280, 720);
		if (e.IsInCategory(EventCategoryApplication)) {
			YT_CORE_TRACE(e);
		}
		if (e.IsInCategory(EventCategoryInput)) {
			YT_CORE_ERROR(e);
		}

		while (m_Running)
		{
			glClearColor(1,0,1,1);
			glClear(GL_COLOR_BUFFER_BIT);

			for (Layer* layer : m_LayerStack) {
				layer->OnUpdate();
			}

			m_Window->OnUpdate();
		}
	}
	void Application::PushLayer(Layer* layer) {
		m_LayerStack.PushLayer(layer);
		layer->OnAttach();
	}
	void Application::PushOverlay(Layer* layer) {
		m_LayerStack.PushOverlay(layer);
		layer->OnDetach();
	}
}

YOTO.h:添加ImGuiLayer.h

#pragma once
#include "YOTO/Application.h"
#include"YOTO/Layer.h"
#include "YOTO/Log.h"
#include"YOTO/ImGui/ImGuiLayer.h"
//入口点
#include"YOTO/EntryPoint.h"

 SandboxApp.cpp:new且push这个层

#include<YOTO.h>
#include<stdio.h>

class ExampleLayer:public YOTO::Layer
{
public:
	ExampleLayer()
	:Layer("Example") {

	}
	void OnUpdate()override {
		//YT_CLIENT_INFO("测试update");
	}
	void	OnEvent(YOTO::Event& e)override {

		YT_CLIENT_TRACE("测试event{0}",e);
	}

private:

};


class Sandbox:public YOTO::Application
{
public:
	Sandbox() {
		PushLayer(new ExampleLayer());
		PushLayer(new YOTO::ImGuiLayer());
	}
	~Sandbox() {

	}

private:

};

YOTO::Application* YOTO::CreateApplication() {
	printf("helloworld");
	return new Sandbox();
}

 测试:

Bug:这里莫名爆红

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

注释掉:

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

 暂时解决(不知道这个bug会不会未来给我一脚)

运行成功但是什么都不能点,因为没添加事件。

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

 谢谢大家的支持,我会把每次可成改动的整个代码、类都粘上来,虽然有点儿多,但是防止迷路然后出现一些蜜汁bug。有问题欢迎评论区讨论(博主也是菜鸡,希望大佬指点)

ImGui事件:

ImGuiLayer.h:创建各种事件的函数声明

#pragma once
#include"YOTO/Layer.h"
#include"YOTO/Event/KeyEvent.h"
#include"YOTO/Event/MouseEvent.h"
#include"YOTO/Event/ApplicationEvent.h"
namespace YOTO {

	class YOTO_API ImGuiLayer:public Layer
	{
	public:
		ImGuiLayer();
		~ImGuiLayer();
		void OnAttach();
		void OnDetach();
		void OnUpdate();
		void OnEvent(Event& event);
	private:
		bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
		bool OnMouseButtonReleasedEvent(MouseButtonReleasedEvent& e);
		bool OnMouseMovedEvent(MouseMovedEvent& e);
		bool OnMouseScrolledEvent(MouseScrolledEvent& e);
		bool OnKeyPressedEvent(KeyPressedEvent& e);
		bool OnKeyReleasedEvent(KeyReleasedEvent& e);
		bool OnKeyTypedEvent(KeyTypedEvent& e);
		bool OnWindowResizedEvent(WindowResizeEvent& e);
		float m_Time = 0.0f;

	};


}

 ImGuiLayer.h:绑定拦截器,实现方法

#include"ytpch.h"
#include"ImGuiLayer.h"
#include"Platform/OpenGL/ImGuiOpenGLRenderer.h"

#include"YOTO/Application.h"

#include<GLFW/glfw3.h>
#include<glad/glad.h>

namespace YOTO {
	ImGuiLayer::ImGuiLayer()
	:Layer("ImGuiLayer") {

	}
	ImGuiLayer::~ImGuiLayer() {

	}
	void ImGuiLayer::OnAttach()
	{
		//创建上下文
		ImGui::CreateContext();
		//设置颜色
		ImGui::StyleColorsDark();
		//配置类:ImGuiIO
		ImGuiIO& io = ImGui::GetIO();
		io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;// 光标
		io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;

		// imgui输入key对应glfw的key,临时的:最终会对应引擎自身的key
		io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
		io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
		io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
		io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
		io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
		io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
		io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
		io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
		io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
		io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
		io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
		io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
		io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
		io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
		io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
		io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
		io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
		io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
		io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
		io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
		io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;

		ImGui_ImplOpenGL3_Init("#version 410");
	
	}
	void ImGuiLayer::OnDetach()
	{
	}
	void ImGuiLayer::OnUpdate() {
		//每帧刷新UI配置
		ImGuiIO& io = ImGui::GetIO();
		Application& app = Application::Get();
		//显示的size大小
		io.DisplaySize = ImVec2(app.GetWindow().GetWidth(), app.GetWindow().GetHeight());
	
		
		float time = (float)glfwGetTime();
		//时间
		io.DeltaTime = m_Time > 0.0f ? (time - m_Time) : (1.0f / 60.0f);
		m_Time = time;

		ImGui_ImplOpenGL3_NewFrame();
		ImGui::NewFrame();

		static bool show = true;
		// 显示ImGui Demo
		ImGui::ShowDemoWindow(&show);

		ImGui::Render();
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

	}
	void ImGuiLayer::OnEvent(Event& event) {


		EventDispatcher dispatcher(event);
		dispatcher.Dispatch<MouseButtonPressedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnMouseButtonPressedEvent));
		dispatcher.Dispatch<MouseButtonReleasedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnMouseButtonReleasedEvent));
		dispatcher.Dispatch<MouseMovedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnMouseMovedEvent));
		dispatcher.Dispatch<MouseScrolledEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnMouseScrolledEvent));
		dispatcher.Dispatch<KeyPressedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnKeyPressedEvent));
		dispatcher.Dispatch<KeyReleasedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnKeyReleasedEvent));
		dispatcher.Dispatch<KeyTypedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnKeyTypedEvent));
		dispatcher.Dispatch<WindowResizeEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnWindowResizedEvent));

	
	}	
	bool ImGuiLayer::OnMouseButtonPressedEvent(MouseButtonPressedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.MouseDown[e.GetMouseButton()] = true;
		return false;//返回false是因为希望其他层也处理这个事件(事件穿透)
	}
	bool ImGuiLayer::OnMouseButtonReleasedEvent(MouseButtonReleasedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.MouseDown[e.GetMouseButton()] = false;
		return false;//返回false是因为希望其他层也处理这个事件(事件穿透)
	}
	bool ImGuiLayer::OnMouseMovedEvent(MouseMovedEvent& e)
	{
		ImGuiIO &io = ImGui::GetIO();
		io.MousePos = ImVec2(e.GetX(), e.GetY());
		return false;//返回false是因为希望其他层也处理这个事件(事件穿透)
	}
	bool ImGuiLayer::OnMouseScrolledEvent(MouseScrolledEvent& e)
	{
		ImGuiIO&io = ImGui::GetIO();
		io.MouseWheel += e.GetXOffset();
		io.MouseWheelH += e.GetYOffset();
		return false;//返回false是因为希望其他层也处理这个事件(事件穿透)
	}
	bool ImGuiLayer::OnKeyPressedEvent(KeyPressedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.KeysDown[e.GetKeyCode()] = true;
		io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
		io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
		io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
		io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];

		return false;
	}
	bool ImGuiLayer::OnKeyReleasedEvent(KeyReleasedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.KeysDown[e.GetKeyCode()] = false;
		return false;
	}
	bool ImGuiLayer::OnKeyTypedEvent(KeyTypedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		int keycode = e.GetKeyCode();
		if (keycode > 0 && keycode < 0x10000)
			io.AddInputCharacter((unsigned short)keycode);

		return false;
	}
	bool ImGuiLayer::OnWindowResizedEvent(WindowResizeEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.DisplaySize = ImVec2(e.GetWidth(), e.GetHeight());
		io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
		glViewport(0, 0, e.GetWidth(), e.GetHeight());
		return false;
	}
}

KeyEvent.h:添加KeyTypedEvent类

#pragma once
#include"Event.h"
#include "ytpch.h"

namespace YOTO {
	/// <summary>
	/// 键盘事件基类
	/// </summary>
	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;

	};
	/// <summary>
	/// 键盘按下回调
	/// </summary>
	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;

	};
	/// <summary>
	/// 键盘释放回调
	/// </summary>
	class YOTO_API 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)
			
	};
	/// <summary>
	/// 输入字符回调
	/// </summary>
	class YOTO_API KeyTypedEvent :public KeyEvent
	{
	public:
		KeyTypedEvent(int keycode)
			:KeyEvent(keycode) { 

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

	};

}

 WindowsWindow.cpp:Init里添加KeyTyped的回调:

#include "ytpch.h"
#include "WindowsWindow.h"
#include"YOTO/Event/ApplicationEvent.h"
#include"YOTO/Event/MouseEvent.h"
#include"YOTO/Event/KeyEvent.h"
#include<glad/glad.h>

namespace YOTO {

	static bool s_GLFWInitialized = false;

	Window* Window::Creat(const WindowProps& props) {
		return new WindowsWindow(props);
	}
	WindowsWindow::WindowsWindow(const WindowProps& props) {
		Init(props);
	}
	WindowsWindow::~WindowsWindow() {
		ShutDown();
	}

	void WindowsWindow::Init(const WindowProps& props) {
		m_Data.Title = props.Title;
		m_Data.Width = props.Width;
		m_Data.Height = props.Height;
		YT_CORE_INFO("创建了{0},{1},{2}", props.Title, props.Width, props.Height);
		if (!s_GLFWInitialized) {
			int success = glfwInit();
			YT_CLIENT_ASSERT("不能创建新的glfw,{0}",success );
			glfwSetErrorCallback([](int error_code, const char* description) {
				YT_CORE_ERROR("GLFW错误:错误码({0}):{1} ", error_code, description);
				});
			s_GLFWInitialized = true;

		}
		m_Window = glfwCreateWindow((int)props.Width, (int)props.Height, m_Data.Title.c_str(), nullptr, nullptr);
		glfwMakeContextCurrent(m_Window); 
		//在运行时获取OpenGL函数地址并将其保存在函数指针中供以后使用
		int status = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
		YT_CORE_ASSERT(status, "glad初始化错误");
		glfwSetWindowUserPointer(m_Window, &m_Data);
		SetVSync(true);


		//GLFW回调,每次改变调用lambda里的部分
		//窗口大小回调
		glfwSetWindowSizeCallback(m_Window, [](GLFWwindow* window, int width, int height) {
			WindowData& data=*(WindowData*)glfwGetWindowUserPointer(window);
			data.Width = width;
			data.Height = height;
			WindowResizeEvent event(width, height);
			//调用回调函数
			data.EventCallback(event);
			});
		//窗口关闭回调
		glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			WindowCloseEvent event;
			data.EventCallback(event);
			});
		//键盘按键回调
		glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			switch (action) {
				case GLFW_PRESS:
				{
					KeyPressedEvent event(key, 0);
					data.EventCallback(event);
					break;
				}
				case GLFW_RELEASE:
				{
					KeyReleasedEvent event(key);
					data.EventCallback(event);
					break;
				}
				case GLFW_REPEAT:
				{
					KeyPressedEvent event(key, 1);
					data.EventCallback(event);
					break;
				}
				}
			});
		//鼠标按键回调
		glfwSetMouseButtonCallback(m_Window, [](GLFWwindow* window, int button, int action, int mods) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			switch (action)
			{
				case GLFW_PRESS:
				{
					MouseButtonPressedEvent event(button);
					data.EventCallback(event);
					break;
				}

				case GLFW_RELEASE:
				{
					MouseButtonReleasedEvent event(button);
					data.EventCallback(event);
					break;
				}
			}
			});
		//滚轮回调
		glfwSetScrollCallback(m_Window, [](GLFWwindow* window, double xoffset, double yoffset) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			MouseScrolledEvent event((float)xoffset, (float)yoffset);
			data.EventCallback(event);
			});
		//鼠标位置回调
		glfwSetCursorPosCallback(m_Window, [](GLFWwindow* window, double xpos, double ypos) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			MouseMovedEvent event((float)xpos, (float)ypos);
			data.EventCallback(event);
			});
		//字符回调
		glfwSetCharCallback(m_Window, [](GLFWwindow* window, unsigned int codepoint) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			KeyTypedEvent event(codepoint);
			data.EventCallback(event);
			});
	}
	void WindowsWindow::ShutDown() {
		glfwDestroyWindow(m_Window);
	}
	void WindowsWindow::OnUpdate()
	{
		//轮询事件
		glfwPollEvents();
		//交换缓冲区
		glfwSwapBuffers(m_Window);


	}
	void WindowsWindow::SetVSync(bool enable) {
		if (enable)
			glfwSwapInterval(1);
		else
			glfwSwapInterval(0);
		m_Data.VSync = enable;
		}
	bool WindowsWindow::IsVSync() const {
		return m_Data.VSync;
		}
}

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

#ifdef YT_ENABLE_ASSERTS
#define YT_CLIENT_ASSERT(x,...) {if(!(x)){YT_CLIENT_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#define YT_CORE_ASSERT(x,...) {if(!(x)){YT_CORE_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#else
#define YT_CLIENT_ASSERT(x,...)
#define YT_CORE_ASSERT(x,...)

#endif // YT_ENABLE_ASSERTS



#define BIT(x)(1<<x)
//绑定事件定义
#define YT_BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1)

测试:

跟着cherno手搓游戏引擎【6】ImGui和ImGui事件,游戏引擎

 cool现在ImGui就能接收到咱的事件了。文章来源地址https://www.toymoban.com/news/detail-797765.html

到了这里,关于跟着cherno手搓游戏引擎【6】ImGui和ImGui事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 跟着cherno手搓游戏引擎【5】layer(层)、Glad

    Layer.h:提供Attach链接、Detach解绑、Update刷新、Event事件、GetName方法 Layer.cpp:随便写写 LayerStack.h:建立用来存储层的栈(用vector)  LayerStack.cpp:看注释,需要解释的有点多  YOTO.h:加一个Layer.h Application.h:Stack实例,Push方法添加层。 Application.cpp:添加Push即可。 SandboxApp.cpp:创建测试

    2024年01月17日
    浏览(44)
  • 跟着cherno手搓游戏引擎【8】按键和鼠标的KeyCode

    先把glfw3.h里的KeyCode的定义抄到咱这里来。 在YOTO下创建KeyCode.h:  MouseButtonCodes.h:和KeyCode.h一样作用,把GLFW改成自己的 YOTO.h: SandboxApp.cpp:在ExampleLayer测试轮询和KeyCode  明日继续更新数学和ImGui停靠和视口

    2024年01月18日
    浏览(34)
  • Hazel游戏引擎(008-009)事件系统

    文中若有代码、术语等错误,欢迎指正 此节目的 理清顺序和设计才能更好的编码 设计如图 声明 图是我自己缝合的,流程与大意没错,但是不符合软件工程对应图的规范。 大致是根据视频草稿图与大意画的 使用时序图简单表示 使用类图详细表示 在软件工程中,类图没有消

    2024年02月01日
    浏览(40)
  • 【unity之IMGUI实践】游戏玩法逻辑实现【四】

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 : unityUI专题篇 🅰️ Target Texture 行为渲染 —————————————— ___________________________ 😶‍🌫️ 步骤 : 1.靠近武器,碰撞检测

    2024年02月16日
    浏览(56)
  • 【unity之IMGUI实践】游戏结束流程封装实现【七】

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 : unityUI专题篇 🅰️ 😶‍🌫️:步骤实现 1.坐标三个转化 2.GUI的原点和屏幕的原点 3.结构体的特点回顾——涉及Rect_结构体类型 4.血条的

    2024年02月14日
    浏览(46)
  • 【用unity实现100个游戏之4】手搓一个网格放置功能,及装修建造种植功能(2d3d通用,附源码)

    参考原视频链接 【视频】:https://www.youtube.com/watch?v=l0emsAHIBjU 注意 :本文为学习笔记记录,推荐支持原作者,去看原视频自己手敲代码理解更加深入

    2024年02月13日
    浏览(43)
  • 无敌!我用【C语言】手搓出了一个体系完整的【员工管理系统】还能玩游戏听音乐?(超详细,附完整源码)

    博主简介: Hello大家好呀,我是陈童学,一个与你一样正在慢慢前行的人。 博主主页: @陈童学哦 所属专栏: C语言程序设计实验项目 如果本文对你有所帮助的话,还希望可以点赞👍收藏📂支持一下哦! 前言:员工管理系统是一款面向公司管理员的管理工具,旨在提供员工

    2024年02月08日
    浏览(50)
  • 了解游戏引擎,游戏引擎的选择:2D3D游戏开发

    常用的游戏开发引擎有很多,以下是一些在游戏开发领域中较为流行和广泛应用的引擎: 1. Unity游戏引擎 特点: 强大的跨平台支持,可以发布到多个平台,包括PC、移动设备和主机。 大量的插件和资产商店,便于开发者获取各种功能和资源。 相对易学易用,拥有大量的教程

    2024年03月10日
    浏览(54)
  • HTML5游戏引擎(一)-egret引擎简介——一个开源免费的游戏框架

    游戏行业发展迅速, 给程序员提供了大量就业 (斗鱼, 微派, 腾讯, 蓝月, 网易 等等) 游戏开发薪资普遍比较高 (王者荣耀 , 蓝月) 游戏已经普遍被大众所认可,并且发展成一种竞技体育 重点学习Egret Typescrit 语法学习 一笔带过Cocos2d-x Egret跨平台,入手容易,性能较好,更

    2024年02月05日
    浏览(75)
  • 游戏引擎架构-游戏支持的系统

    本篇知识点来源于《游戏引擎架构》第五章,此章节主要讨论多数游戏引擎中都会出现的底层支持系统。 C++静态初始化次序是无法使用的,原因是我们无法预引擎子系统的构造函数调用次序和析构函数调用次序。比如我要启动引擎的A,B,C系统,无法保证这些系统是按照规定

    2024年01月16日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包