Hazel游戏引擎(008-009)事件系统

这篇具有很好参考价值的文章主要介绍了Hazel游戏引擎(008-009)事件系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

008、事件系统-设计

  • 此节目的

    理清顺序和设计才能更好的编码

  • 设计如图

    • 声明

      图是我自己缝合的,流程与大意没错,但是不符合软件工程对应图的规范。

      大致是根据视频草稿图与大意画的

    • 使用时序图简单表示

      引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

    • 使用类图详细表示

      在软件工程中,类图没有消息传递的,不符合规范,但大意是这样

      引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

009、事件系统-自定义事件

前言

  • 此节目的

    由008节的计划窗口事件图中的2.3将glfw窗口事件分组成自己系统的事件Event,即写出对应glfw窗口事件的自定义事件Event类

  • 事件最终的设计

    为了简便,自定义事件是立即处理事件,没有缓冲事件。

    缓冲事件:键盘a一直按下第一个立刻输出,顿了一下才一直输出。

  • glfw窗口事件

    • 窗口相关事件

      重新调整大小、窗口关闭等

    • 鼠标事件

      移动、滚动、按下

    • 键盘事件

      键盘按下、释放

  • 类图

    引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

自定义事件类与使用

声明与定义类代码

  • 声明

    由于类过多,只写几个类

  • Event

    /*
    	为了简便,自定义事件是立即处理事件,没有缓冲事件。
    	缓冲事件:键盘a一直按下第一个立刻输出,顿了一下才一直输出。
    */
    // 事件类别-一个类一个标识
    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),	// 1
        EventCategoryInput			= BIT(1),	// 2
        EventCategoryKeyboard		= BIT(2),	// 4
        EventCategoryMouse			= BIT(3),	// 8
        EventCategoryMouseButton	= BIT(4)	// 16
    };
    // 宏定义:每个子类都需要重写父类虚函数代码,可以用宏定义简洁代码
    #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; }
    
    class HAZEL_API Event
    {
        friend class EventDispatcher;
        public:
        virtual EventType GetEventType() const = 0;		// 获取本事件是哪个类型
        virtual const char* GetName() const = 0;		// 获取本事件的名称c字符数组
        virtual int GetCategoryFlags() const = 0;		// 获取本事件属于哪个分类
        virtual std::string ToString() const { return GetName(); }	// 获取本事件的名称从c字符数组转为字符串
    
        inline bool IsInCategory(EventCategory category)
        {
            return GetCategoryFlags() & category;
        }
        protected:
        bool m_Handled = false;
    };
    
  • WindowResizeEvent

    class HAZEL_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 << "WindowResizeEvent: " << m_Width << ", " << m_Height;
            return ss.str();
        }
    	// 关键地方:用宏定义来重写虚函数
        EVENT_CLASS_TYPE(WindowResize)
            EVENT_CLASS_CATEGORY(EventCategoryApplication)
            private:
        unsigned int m_Width, m_Height;
    };
    
  • 关键地方:用宏定义来重写虚函数

    // 宏定义:每个子类都需要重写父类虚函数代码,可以用宏定义简洁代码
    #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; }
    
    EVENT_CLASS_TYPE(WindowResize)
    EVENT_CLASS_CATEGORY(EventCategoryApplication)
    // 会编译成
    static EventType GetStaticType() { return EventType::WindowResize; } virtual EventType GetEventType() const override { return GetStaticType(); } virtual const char* GetName() const override { return "WindowResize"; }
    virtual int GetCategoryFlags() const override { return EventCategoryApplication; }
    

    可见,##type,是保持为变量,#type是转换为字符串

包含头文件

  • premake的lua脚本中

    includedirs
    {
        "%{prj.name}/src",
        "%{prj.name}/vendor/spdlog/include"
    }
    

    所以Hazel项目的包含目录包含src目录

    // 因为Event.h所在src/Hazel/Events/Event.h
    // 其它类包含Event.h,可以写成
    #include "Hazel/Events/Event.h"// 而不用前缀src
    

    重新编译

使用事件

  • application.h

    #include "Core.h"
    #include "Events/Event.h"// 包含事件基类
    
    namespace Hazel {
    
  • Application.cpp

    #include "Application.h"
    #include "Hazel/Events/ApplicationEvent.h" // 包含具体事件
    #include "Hazel/Log.h"
    
    namespace Hazel {
    	Application::Application(){}
    	Application::~Application(){}
    	void Application::Run()
    	{
    		WindowResizeEvent e(1280, 720);	// 使用自定义事件
    		if (e.IsInCategory(EventCategoryApplication))	// 判断是否对应的分类
    		{
    			HZ_TRACE(e);	// 输出事件
    		}
    		if (e.IsInCategory(EventCategoryInput))
    		{
    			HZ_TRACE(e);
    		}
    		while (true);
    	}
    }
    
  • 效果

    引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

事件调度器代码

// 事件调度器类
class EventDispatcher
{
    template<typename T>
    using EventFn = std::function<bool(T&)>;	// 声明function,接受返回类型bool,参数是T&的函数
    public:
    EventDispatcher(Event& event)
        : m_Event(event)
        {
        }
    template<typename T>
    bool Dispatch(EventFn<T> func)				// function参数接收函数指针
    {
        if (m_Event.GetEventType() == T::GetStaticType())	// 拦截的事件和想处理的事件类型是否匹配
        {
            m_Event.m_Handled = func(*(T*)&m_Event);		// 处理拦截的事件
            return true;
        }
        return false;
    }
    private:
    Event& m_Event;								// 拦截的事件
};

这个类的本身与作用由于(function+模板)变得很难看懂,可以看结合开头的事件设计图和后面的function基本使用代码一步一步理解

C++知识:Function

Bind用法

#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;// 占位符空间
void f(int a, int b, int c, int d, int e)
{
	cout << a << " " << b << " " << c << " " << d << " " << e << endl;
}
// _1 是在命名空间里的,bind可以翻转参数位置
int main(){
	int a = 1, b = 2, c = 3;
	auto g = bind(f, a, b, c, _2, _1);
	g(4, 5);	// 1 2 3 5 4
	return 0;
}
  • 说明
    • bind可以用_1,_2预占位,g可以理解是function<void(int a, int b, int c, int d, int e);function对象
    • auto g = bind(f, a, b, c, _2, _1);将f函数绑定到function对象g上,并定好第一、二、三个参数
    • g(4, 5),将调用执行f函数,4将绑定到_1上,5将绑定到_2上,本来_1实参会赋给f函数的d形参,_2实参给e形参,但由于bind时改变了对应位置
    • 于是_1给e,_2给d,输出 1 2 3 5 4

function基本使用

#include <iostream>
#include <string>
#include <functional>
using namespace std;
using namespace std::placeholders;// 占位符空间

// 事件类与函数定义
class Event {							// 事件基类
public:
	virtual void Say() { cout << "Event::Say()" << endl; }
	bool m_Handled;						// 事件是否处理完
};
class WindowCloseEvent : public Event {	// 窗口关闭事件子类
public:
	virtual void Say() { cout << "WindowEvent::Say()" << endl;}
};
void LayerOnEvent(Event& e) {
	e.Say();
	cout << "LayerOnEvent(Event& e)" << endl;
}

// 4.using+带泛型的function
template<typename T>
using TemplateEventFn = std::function<void(T&)>;

// 5.额外理解,宏定义
#define BIND_EVENT_FN(x) bind(&x, _1)

int main() {
	// 1.普通的function
	Event e1;
	function<void(Event&)> func1 = LayerOnEvent;// 绑定返回类型void,参数是Event的函数
	func1(e1);

	// 2.使用using 代替function
	using EventFn = std::function<void(Event&)>;
	EventFn func2 = LayerOnEvent;
	func2(e1);
	
	// 3.使用bind
	function<void(Event&)> func3_1 = bind(&LayerOnEvent, _1);
	func3_1(e1);

	EventFn func3_2 = bind(&LayerOnEvent, _1);// bind第一个参数函数地址,第二个参数是调用Print函数时的参数
	func3_2(e1);

	// 4.使用template的 function
	TemplateEventFn<Event> func4 = LayerOnEvent;
	func4(e1);

	func4 = bind(&LayerOnEvent, _1);
	func4(e1);

	// 5.额外理解,宏定义
	TemplateEventFn<Event> func5 = BIND_EVENT_FN(LayerOnEvent);
	func5(e1);

	// 6.额外理解。尝试引用类型是否能执行子类的虚函数
	function<void(Event&)> func6 = LayerOnEvent;
	WindowCloseEvent windowe1;
	Event& event1 = windowe1;
	func6(event1);	
	/*
		WindowEvent::Say()
		LayerOnEvent(Event& e)
	*/
	return 0;
}

012、事件系统-Demo

  • 声明

    由于008节设计了事件系统,而009只是实现了自定义事件,占整个事件系统的很小部分

    于是我把012窗口事件的内容简化成demo,符合一开始的计划事件图。

    demo是分为一个小点一个小点的,更好来理解整个事件系统。

Layer用EventDispacher拦截处理事件(56)(难理解)

  • 前言

    此点Demo代码是对应一开始计划事件系统类图的第5、6步,而其它步骤的代码是模拟并且略过

    引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

  • 代码

    阅读代码,请按照注释的1、2、3、4、5、5.1…顺序阅读

    #include <iostream>
    #include <string>
    #include <functional>
    using namespace std;
    using namespace std::placeholders;// 占位符空间
    
    // 事件类定义//
    class Event {							// 事件基类
    public:
    	virtual void Say() { cout << "Event::Say()" << endl; }
    	bool m_Handled;						// 事件是否处理完
    };
    class WindowCloseEvent : public Event {	// 窗口关闭事件子类
    public:
    	virtual void Say() { cout << "WindowEvent::Say()" << endl; }
    };
    
    // 事件调度器//
    class EventDispatcher {
    public:
    	EventDispatcher(Event& event) :m_Event(event) {}
    	
    	template<typename T>
    	using TemplateEventFn = std::function<bool(T&)>;	// 使用using+模板function
    
    	// 5.2 using TemplateEventFn = function<void(WindowCloseEvent&)> 与 TemplateEventFn<WindowCloseEvent> func
    	template<typename T>
    	void Dispatch(TemplateEventFn<T> func) {			// 此时func = Layer::OnWindowClose
    		// 5.3 拦截的事件m_Event与layer层想处理的事件类型是否匹配
    		if (true) {										// 假设匹配
    			cout << "EventDispatcher::Dispatch(TemplateEventFn<T> func)" << endl;
    			// 6 执行layer的OnWindowClose处理拦截的m_Event事件
    			m_Event.m_Handled = func(*(T*)&m_Event);
    			/*	
    				(0)	函数声明:OnWindowClose(WindowEvent& e);
    				(0) 显式调用:OnWindowClose(*(WindowEvent*)&m_Event)	
    				(1) OnWindowClose参数要求WindowEvent,而m_Event是Event类型,所以要(WindowEvent*)&m_Event
    				(2) OnWindowClose参数是引用类型,所以要*(WindowEvent*)&m_Event
    			*/
    		}
    	}
    private:
    	Event& m_Event;										// 拦截的事件
    };
    // Layer层//
    class Layer {											// 属于Application的layer层
    public:
    	// 5.每个Layer层的OnEvent,用事件调度器,拦截自己层想要拦截的事件并且处理
    	void OnEvent(Event& e) {
    		EventDispatcher dispatcher(e);
    		// 5.1拦截WindowCloseEvent事件,并用本类的OnWindowClose函数处理
    		dispatcher.Dispatch<WindowCloseEvent>(bind(&Layer::OnWindowClose, this, _1));// bind在上一小点有demo,this在类时要使用,_1依旧是执行OnWindowClose的参数
    	}
    	bool OnWindowClose(WindowCloseEvent& e) {
    		e.Say();
    		cout << "Layer::OnWindowClose(WindowCloseEvent& e)" << endl;
    		return true;									// 代表处理完了
    	}
    };
    
    int main() {
    	// 1.Application对象创建窗口类,窗口类初始化了glfw窗口
    	// 2.将glfw窗口事件封装成自己系统的事件
    	WindowCloseEvent windowe1;				
    	// 3.回调Application的OnEvent函数,并将事件作为其OnEvent的参数
    	// 4.Application的OnEvent,将事件传递给Application的所有Layer层的OnEvent
    	Layer layer;
    	layer.OnEvent(windowe1);
    	return 0;
    }
    
  • 效果

    引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

Application设置window回调函数与回调(123)

  • 前言

    此点是对应一开始计划事件系统类图的第1、2、3步,但没有glfw窗口,只能模拟glfw窗口事件

    引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

  • 代码

    #include <iostream>
    #include <string>
    #include <functional>
    using namespace std;
    using namespace std::placeholders;// 占位符空间
    
    // 事件类定义//
    class Event {							// 事件基类
    public:
    	virtual void Say() { cout << "Event::Say()" << endl; }
    	bool m_Handled;						// 事件是否处理完
    };
    class WindowCloseEvent : public Event {	// 窗口关闭事件子类
    public:
    	virtual void Say() { cout << "WindowEvent::Say()" << endl;}
    };
    
    // 窗口类定义//
    class Window {
    public:
    	using EventCallbackFn = std::function<void(Event&)>;	// 声明function类型void function(Event&)
    	static Window* CreateWindow() {							// 模拟创建窗口
    		return new Window;
    	}
    	void SetEventCallback(const EventCallbackFn& callback) {
    		EventCallback = callback;							// 绑定Application::OnEvent
    	}
    	void SendEvent() {
    		cout << "Window::模拟glfw窗口事件" << endl;
    		// 2.将glfw窗口事件封装成自己系统的事件
    		WindowCloseEvent windowe;
    		// 3.回调Application的OnEvent函数,并将事件作为其OnEvent的参数
    		EventCallback(windowe);
    	}
    	EventCallbackFn EventCallback;							// 定义function
    };
    
    // 应用层类定义//
    class Application {
    public:
    	Window* win;											// 持有的窗口类
    	void OnEvent(Event& event) {
    		event.Say();
    		cout << "Application::OnEvent(Event& event)" << endl;
    		// 4.Application的OnEvent,将事件传递给Application的所有Layer层的OnEvent
    		// ......
    	}
    };
    int main() {
    	Application app;
    	// 1.1Application对象创建窗口类,窗口类初始化了glfw窗口
    	app.win = Window::CreateWindow();
    	// 1.2Application设置窗口事件的回调函数
    	app.win->SetEventCallback(bind(&Application::OnEvent, app, _1));// bind的argument1是函数地址,arug2是哪个类,arug3是调用OnEvent的参数
    	// 1.3模拟glfw窗口事件
    	app.win->SendEvent();
    	return 0;
    }
    
  • 效果

    引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

Application将事件传给Layer(4)与整个事件系统流程

  • 前言

    此点是对应一开始计划事件系统类图的第4步,并且整合前两点的代码,除了缺少glfw窗口与glfw窗口事件是完整的事件系统流程

    引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function

  • 代码

    #include <iostream>
    #include <string>
    #include <functional>
    using namespace std;
    using namespace std::placeholders;// 占位符空间
    
    // 事件类定义//
    class Event {							// 事件基类
    public:
    	virtual void Say() { cout << "Event::Say()" << endl; }
    	bool m_Handled;						// 事件是否处理完
    };
    class WindowCloseEvent : public Event {	// 窗口事件子类
    public:
    	virtual void Say() { cout << "WindowEvent::Say()" << endl;}
    };
    // 事件调度器//
    class EventDispatcher {
    public:
    	EventDispatcher(Event& event) :m_Event(event) {}
    
    	template<typename T>
    	using TemplateEventFn = std::function<bool(T&)>;	// 使用using+模板function
    
    	// 5.2 using TemplateEventFn = function<void(WindowCloseEvent&)> 与 TemplateEventFn<WindowCloseEvent> func
    	template<typename T>
    	void Dispatch(TemplateEventFn<T> func) {			// 此时func = Layer::OnWindowClose
    		// 5.3 拦截的事件m_Event与layer层想处理的事件类型是否匹配
    		if (true) {										// 假设匹配
    			cout << "EventDispatcher::Dispatch(TemplateEventFn<T> func)" << endl;
    			// 6 执行layer的OnWindowClose处理拦截的m_Event事件
    			m_Event.m_Handled = func(*(T*)&m_Event);
    			/*
    				(0)	函数声明:OnWindowClose(WindowEvent& e);
    				(0) 显式调用:OnWindowClose(*(WindowEvent*)&m_Event)
    				(1) OnWindowClose参数要求WindowEvent,而m_Event是Event类型,所以要(WindowEvent*)&m_Event
    				(2) OnWindowClose参数是引用类型,所以要*(WindowEvent*)&m_Event
    			*/
    		}
    	}
    private:
    	Event& m_Event;										// 拦截的事件
    };
    // Layer层//
    class Layer {											// 属于Application的layer层
    public:
    	// 5.每个Layer层的OnEvent,用事件调度器,拦截自己层想要拦截的事件并且处理
    	void OnEvent(Event& e) {
    		EventDispatcher dispatcher(e);
    		// 5.1拦截WindowCloseEvent事件,并用本类的OnWindowClose函数处理
    		dispatcher.Dispatch<WindowCloseEvent>(bind(&Layer::OnWindowClose, this, _1));// bind在上一小点有demo,this在类时要使用,_1依旧是执行OnWindowClose的参数
    	}
    	bool OnWindowClose(WindowCloseEvent& e) {
    		e.Say();
    		cout << "Layer::OnWindowClose(WindowCloseEvent& e)" << endl;
    		return true;									// 代表处理完了
    	}
    };
    // 窗口类定义//
    class Window {
    public:
    	using EventCallbackFn = std::function<void(Event&)>;	// 声明function类型void function(Event&)
    	static Window* CreateWindow() {							// 模拟创建窗口
    		return new Window;
    	}
    	void SetEventCallback(const EventCallbackFn& callback) {
    		EventCallback = callback;							// 绑定Application::OnEvent
    	}
    	void SendEvent() {
    		cout << "Window::模拟glfw窗口事件" << endl;
    		// 2.将glfw窗口事件封装成自己系统的事件
    		WindowCloseEvent windowe;
    		// 3.回调Application的OnEvent函数,并将事件作为其OnEvent的参数
    		EventCallback(windowe);
    	}
    	EventCallbackFn EventCallback;							// 定义function
    };
    
    // 应用层类定义//
    class Application {
    public:
    	Window* win;											// 持有的窗口类
    	void OnEvent(Event& event) {
    		cout << "Application::OnEvent(Event& event)" << endl;
    		// 4.Application的OnEvent,将事件传递给Application的所有Layer层的OnEvent
    		Layer layer;
    		layer.OnEvent(event);
    	}
    };
    int main() {
    	Application app;
    	// 1.1Application对象创建窗口类,窗口类初始化了glfw窗口
    	app.win = Window::CreateWindow();
    	// 1.2Application设置窗口事件的回调函数
    	app.win->SetEventCallback(bind(&Application::OnEvent, app, _1));// bind的argument1是函数地址,arug2是哪个类,arug3是调用OnEvent的参数
    	// 1.3模拟glfw窗口事件
    	app.win->SendEvent();
    	return 0;
    }
    
  • 效果

    引擎中的事件系统,Hazel游戏引擎,游戏引擎,软件工程,事件系统,function文章来源地址https://www.toymoban.com/news/detail-789830.html

到了这里,关于Hazel游戏引擎(008-009)事件系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 游戏引擎中的物理系统

    1.1 对象 Actor 一般来说,游戏中的对象(Actor)分为以下四类: 静态对象 Static Actor 动态对象 Dynamic Actor ---- 可能受到力/扭矩/冲量的影响 检测器 Trigger Kinematic Actor 运动学对象 ---- 忽略物理法则,由游戏逻辑直接控制(可能表现的反物理) 1.2 形状 Shape 由于真实世界中很多物体

    2024年04月10日
    浏览(35)
  • Hazel 引擎学习笔记

    https://youtu.be/etdSXlVjXss 我感觉自己照抄视频中的脚本还是有点慢了 因为你不知道他什么时候加了什么东西,或者自己照抄就很容易抄错 我觉得最好的方法就是自己快速过一遍他的视频,知道他大概的思路是怎么样的,然后自己再拉取那个 commit 的代码,用 diff 方便看他具体修

    2024年02月13日
    浏览(50)
  • 跟着cherno手搓游戏引擎【6】ImGui和ImGui事件

    下载链接: GitHub - TheCherno/imgui: Dear ImGui: Bloat-free Immediate Mode Graphical User interface for C++ with minimal dependencies  新建文件夹,把下载好的文件放入对应路径:  SRC下的premake5.lua文件:添加ImGui 在Platform下创建OpenGl,将imgui_impl_opengl3.cpp和.h加入到该文件夹。 并且更名: 150行改为:

    2024年01月17日
    浏览(40)
  • 跟着cherno手搓游戏引擎【4】窗口抽象、GLFW配置、窗口事件

    在vendor里创建GLFW文件夹: 在github上下载,把包下载到GLFW包下。 GitHub - TheCherno/glfw: A multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input修改SRC/premake5.lua的配置:12、13、15、36、37、38、39、40行的代码是新加上去的: GLFW中的premake5.lua:  如出现此BUG:请找GLFW中的premake5文件,

    2024年01月21日
    浏览(39)
  • JS引擎中的线程,事件循环,上下文

      线程 浏览器中有哪些进程呢? 1.浏览器进程:浏览器的主进程,负责浏览器的界面界面显示,与用户交互,网址栏输入、前进、后退,以及页面的创建和销毁。 2.渲染进程(浏览器内核):默认一个tab页面一个渲染进程,主要的作用为页面渲染,脚本执行,事件处理等。 3.

    2024年02月08日
    浏览(91)
  • 游戏引擎中的物理应用

    Character Controller和普通的动态对象(Dynamic Actor )是不同的,主要的三个特点是: 它拥有可控制的刚体间的交互 假设它是有无穷的摩擦力(可以站停在位置上),没有弹性 加速和刹车几乎立即改变方向并传送 所以其实角色控制器其实是反物理的。 1.1 构建一个控制器 首先,这

    2024年04月14日
    浏览(38)
  • 游戏引擎架构-游戏支持的系统

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

    2024年01月16日
    浏览(44)
  • 游戏物理引擎+特效系统

    原文链接:游戏开发入门(六)游戏物理引擎_游戏开发物理引擎-CSDN博客 游戏开发入门(七)特效系统_csdn 游戏效果开发-CSDN博客 1.游戏应用物理的目的就是为了真实 2.物理引擎: 可以认为属于游戏引擎的一个构成部分,但是可以独立剥离开来。游戏中的物理模拟的计算都是

    2024年02月22日
    浏览(36)
  • 游戏引擎架构-资源及文件系统

    本篇知识点来源于《游戏引擎架构》第六章,主要讨论现代三维游戏引擎中典型资源管理器的运作方式。 对于大部分资产来说,游戏引擎并不会使用其原本的格式。资产需要经过一些资产调节管道,把资产转换为引擎所需的格式。当流经资产调节管道时,每个资源都需要用一

    2024年01月18日
    浏览(47)
  • 游戏引擎的cpu/gpu粒子系统设计思想

    网上有很多篇粒子系统源码解析,但是只是简单的接口罗列,没有从最原理出发去讲清楚粒子系统的来龙去脉,我将从粒子系统的本质去讲清楚它的设计理念,当理解了它的理念以后,很多粒子遇到的问题就会迎刃解决了,这篇文章主讲粒子的实现和一些框架级的优化方式,

    2024年02月12日
    浏览(50)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包