跟着cherno手搓游戏引擎【7】Input轮询
在引擎程序中任何时间,任何位置都能知道按键是否按下、鼠标的位置等等信息。
与事件系统的区别:事件系统是在按下时调用并传递按键状态;轮询是每时每刻都能获取按键状态
创建基类:
YOTO/Input.h:名如其意
#pragma once
#include"YOTO/Core.h"
namespace YOTO {class YOTO_API Input {public:inline static bool IsKeyPressed(int keycode){return s_Instance->IsKeyPressedImpl(keycode);}inline static bool IsMouseButtonPressed(int button) {return s_Instance->IsMouseButtonPressedImpl(button);}inline static float GetMouseX() {return s_Instance->GetMouseXImpl();}inline static float GetMouseY() {return s_Instance->GetMouseYImpl();}inline static std::pair<float,float> GetMousePostion() {return s_Instance->GetMousePositionImpl();}protected:virtual bool IsKeyPressedImpl(int keycode )=0;virtual bool IsMouseButtonPressedImpl(int button) = 0;virtual float GetMouseXImpl() = 0;virtual float GetMouseYImpl() = 0;virtual std::pair<float, float> GetMousePositionImpl() = 0;private:static Input* s_Instance;};
}
实现基类:
在Platform/Windows/下创建WindowsInput.h:
#pragma once
#include"YOTO/Input.h"
namespace YOTO {class WindowsInput :public Input {protected:virtual bool IsKeyPressedImpl(int keycode) override;virtual bool IsMouseButtonPressedImpl(int button)override;virtual std::pair<float, float> GetMousePositionImpl()override;virtual float GetMouseXImpl()override;virtual float GetMouseYImpl() override;};
}
WindowsInput.cpp:获取window然后用glfw自带的事件检测来
#include"ytpch.h"
#include"WindowsInput.h"
#include<GLFW/glfw3.h>
#include"YOTO/Application.h"
namespace YOTO {Input* Input::s_Instance = new WindowsInput();bool WindowsInput::IsKeyPressedImpl(int keycode){// 获取GLFW原生窗口void*,转为GLFWwindow*auto window =static_cast<GLFWwindow*>( Application::Get().GetWindow().GetNativeWindow());// 用已有的GLFW函数来获取按键状态auto state= glfwGetKey(window, keycode);return state==GLFW_PRESS|| state== GLFW_REPEAT;}bool WindowsInput::IsMouseButtonPressedImpl(int button){auto window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());auto state = glfwGetMouseButton(window, button);return state == GLFW_PRESS ;}std::pair<float, float> WindowsInput::GetMousePositionImpl(){auto window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());double xpos, ypos;glfwGetCursorPos(window, &xpos, &ypos);return {(float)xpos,(float)ypos};}float WindowsInput::GetMouseXImpl(){auto [x, y] = GetMousePositionImpl();return x;}float WindowsInput::GetMouseYImpl(){auto [x, y] = GetMousePositionImpl();return y;}
}
为了能在任何时候获取到GLFWwindow,在Window.h中创建方法获取Window
#pragma once#include"ytpch.h"
#include"YOTO/Core.h"
#include"YOTO/Event/Event.h"
namespace YOTO {struct WindowProps {std::string Title;unsigned int Width;unsigned int Height;WindowProps(const std::string &title="YOTO Engine",unsigned int width =1280, unsigned int height = 1280 ):Title(title),Width(width),Height(height){}};class YOTO_API Window {public://用EventCallbackFn代替std::function<void(Event&)>:输入为Event&返回值为void 的函数using EventCallbackFn = std::function<void(Event&)>;virtual ~Window(){}//=0为纯虚函数virtual void OnUpdate() = 0;virtual unsigned int GetWidth() const = 0;virtual unsigned int GetHeight() const = 0;virtual void SetEventCallback(const EventCallbackFn& callback) = 0;virtual void SetVSync(bool enable)= 0;virtual bool IsVSync() const = 0;//返回当前窗口virtual void* GetNativeWindow() const=0;static Window* Creat(const WindowProps& props = WindowProps());};
}
WindowsWindow.h :实现返回window的方法:
#pragma once
#include "YOTO/Window.h"
#include<GLFW/glfw3.h>
#include"YOTO/Log.h"
struct GLFWwindow;
namespace YOTO {class WindowsWindow :public Window{public :WindowsWindow(const WindowProps& props);virtual ~WindowsWindow();void OnUpdate() override;inline unsigned int GetWidth() const override { return m_Data.Width; };inline unsigned int GetHeight() const override { return m_Data.Height; };inline void SetEventCallback(const EventCallbackFn& callback)override{ m_Data.EventCallback = callback; };void SetVSync(bool enable) ;bool IsVSync()const;//返回windowinline virtual void* GetNativeWindow() const { return m_Window; }private: virtual void Init(const WindowProps& props);virtual void ShutDown();private:GLFWwindow* m_Window;struct WindowData {std::string Title;unsigned int Width, Height;bool VSync;EventCallbackFn EventCallback;};WindowData m_Data;};
}
Application.cpp:在Run中获取鼠标位置:
#include"ytpch.h"
#include "Application.h"#include"Log.h"
#include<glad/glad.h>
#include"Input.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();}auto [x, y] = Input::GetMousePostion();YT_CORE_TRACE("{0},{1}",x, y);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();}
}
测试:
小改动:
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_DEBUG
#define YT_ENABLE_ASSERTS
#endif#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)
SRC下的premake5.lua:
workspace "YOTOEngine" -- sln文件名architecture "x64" configurations{"Debug","Release","Dist"}
startproject "Sandbox"
-- 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}")-- 中间目录staticruntime "Off"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会报错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"runtime "Debug"symbols "On"filter "configurations:Release"defines "YT_RELEASE"runtime "Release"optimize "On"filter "configurations:Dist"defines "YT_DIST"runtime "Release"optimize "On"project "Sandbox"location "Sandbox"kind "ConsoleApp"language "C++"staticruntime "Off"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"}-- 引用YOTOEnginelinks{"YOTOEngine","GLFW","opengl32.lib"}filter "system:windows"cppdialect "C++17"systemversion "latest"defines{"YT_PLATFORM_WINDOWS"}filter "configurations:Debug"defines "YT_DEBUG"runtime "Debug"symbols "On"filter "configurations:Release"defines "YT_RELEASE"runtime "Release"optimize "On"filter "configurations:Dist"defines "YT_DIST"runtime "Release"optimize "On"
相关文章:
跟着cherno手搓游戏引擎【7】Input轮询
在引擎程序中任何时间,任何位置都能知道按键是否按下、鼠标的位置等等信息。 与事件系统的区别:事件系统是在按下时调用并传递按键状态;轮询是每时每刻都能获取按键状态 创建基类: YOTO/Input.h:名如其意 #pragma …...
stm32 - GPIO高级用法
stm32 - GPIO高级用法 PWMPWM / LEDPWM / 电机 PWM PWM / LED PWM波通过改变占空比可以改变LED的亮度 PWM信号调节LED亮度时,信号频率保持不变,即一个周期时间不变,改变的是脉冲的高电平的时间,即LED的导通时间,占空比…...
CMake TcpServer项目 生成静态库.a / 动态库.so
CMake 实战构建TcpServer项目 静态库/动态库-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/135608829?spm1001.2014.3001.5501 在这篇博客的基础上,我们把头文件放在include里边,把源文件放在src里边,重新构建 hehedali…...
为什么光刻要用黄光
光刻是集成电路(IC或芯片)制造中的重要工艺之一。简单来说,它是通过使用光掩膜和光刻胶在基板上复制电路图案的过程。 基板将涂覆硅二氧化层绝缘层和光刻胶。光刻胶在被紫外光照射后可以容易地用显影剂溶解,然后在腐蚀后…...
Python 两种多值参数
有时可能需要一个函数中处理的参数的个数是不确定的,就需要使用多值参数 参数名前加上*,代表可以接收元组参数名前加上**,代表可以接收字典 代码: def demo(*args, **kwargs):print(args)print(kwargs)demo(1, 2, 3, 4, 5, nam…...
【Python学习】Python学习19- 异常处理
目录 【Python学习】Python学习19- 异常处理 前言python标准异常异常处理带异常类型语法不带异常类型语法使用except而带多种异常类型try-finally 语句触发异常 参考 文章所属专区 Python学习 前言 本章节主要说明Python的异常处理。 python标准异常 BaseException 所有异常…...
《A++ 敏捷开发》- 4 三点估算
估算是一个范围,不是一个数 唐工:你估计完成开发用户登录模块要多少天?小李:3天。唐工:能在3天完成的可能性有多高?小李:可能性很高。唐工:可否量化一点?小李:可能性为5…...
cesiumlab切片通过arcgisjs加载
cesiumlab切片通过arcgisjs加载 需要注意2个地方,一个是tileInfo,一个是getTileUrl, 在tileInfo中定义好cesiumlab切片的相关信息。 getTileUrl 格式化url的格式。 注意设置编辑,避免超出范围报404。 <html lang"en"…...
React16源码: React中调度之scheduleWork的源码实现
scheduleWork 1 ) 概述 在 ReactDOM.render, setState, forceUpdate 这几个方法最终都调用了 scheduleWork 这个方法 在 scheduleWork 当中,它需要去找到更新对应的 FiberRoot 节点 在使用 ReactDOM.render 的时候,传给 scheduleWork 的就是…...
【STM32】| 02——常用外设 | I2C
系列文章目录 【STM32】| 01——常用外设 | USART 【STM32】| 02——常用外设 | I2C 失败了也挺可爱,成功了就超帅。 文章目录 前言1. 简介2. I2C协议2.1 I2C物理连接2.2 I2C通信协议2.2.1 起始和停止信号2.2.2 数据有效性2.2.3 数据传输格式2.2.4 从机地址/数据方…...
微服务架构设计核心理论:掌握微服务设计精髓
文章目录 一、微服务与服务治理1、概述2、Two Pizza原则和微服务团队3、主链路规划4、服务治理和微服务生命周期5、微服务架构的网络层搭建6、微服务架构的部署结构7、面试题 二、配置中心1、为什么要配置中心2、配置中心高可用思考 三、服务监控1、业务埋点的技术选型2、用户行…...
.net core 6 集成和使用 mongodb
1、安装包 MongoDB.Driver 2、定义顶层类 /// <summary> /// monggodb规范 /// </summary> public abstract class MongoDBToolBase { /// <summary> /// 客户端 /// </summary> protected MongoClient mongoClient { get; private …...
07-微服务getaway网关详解
一、初识网关 在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。这样的话会产生很多问题,例…...
MS2660:L1 频段卫星导航射频前端低噪声放大器芯片
MS2660 是一款具有高增益、低噪声系数的低噪声放 大器(LNA)芯片,支持 L1 频段多模式全球卫星定位,可 以应用于 GPS、北斗二代、伽利略、Glonass 等 GNSS 导航 接收机中。芯片采用先进工艺制造,封装采用 2 mm 2 mm …...
微信小程序防止截屏录屏
一、使用css添加水印 使用微信小程序原生的view和css给屏幕添加水印这样可以防止用户将小程序内的隐私数据进行截图或者录屏分享导致信息泄露,给小程序添加一个水印浮层。这样即使被截图或者拍照,也能轻松地确定泄露的源头。效果图如下: 代码…...
126.(leaflet篇)leaflet松散型arcgis缓存切片加载
地图之家总目录(订阅之前必须详细了解该博客) arcgis缓存切片数据格式如下: 完整代码工程包下载,运行如有问题,可“私信”博主。效果如下所示: leaflet松散型arcgis缓存切片加载 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYP...
物联网介绍
阅读引言: 本文从多方面叙述物联网的定义以及在物联网当中的各种通信的介绍。 一、物联网的定义 1.1 通用的定义 物联网(Internet of Things,IOT;也称为Web of Things)是指通过各种信息传感设 备,如传感器、…...
Flume 之自定义Sink
1、简介 前文我们介绍了 Flume 如何自定义 Source, 并进行案例演示,本文将接着前文,自定义Sink,在这篇文章中,将使用自定义 Source 和 自定义的 Sink 实现数据传输,让大家快速掌握Flume这门技术。 2、自定…...
【1】SM4 CBC-MAC 机制
0x01 题目 MSG1: e55e3e24a3ae7797808fdca05a16ac15eb5fa2e6185c23a814a35ba32b4637c2 MAC1: 0712c867aa6ec7c1bb2b66312367b2c8 ----------------------------------------------------- MSG2: d8d94f33797e1f41cab9217793b2d0f02b93d46c2ead104dce4bfec453767719 MAC2: 4366…...
响应式编程Reactor API大全(下)
Reactor 是一个基于响应式编程的库,主要用于构建异步和事件驱动的应用程序。Reactor 提供了丰富的 API,包括创建、转换、过滤、组合等操作符,用于处理异步数据流。以下是一些 Reactor 的主要 API 示例: pom依赖 <dependencyMan…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
aardio 自动识别验证码输入
技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”,于是尝试整合图像识别与网页自动化技术,完成了这套模拟登录流程。核心思路是:截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...
