事件的注册
引擎支持多种窗口,如glfw窗口,Win窗口。每个都有自己的事件系统。
希望引进统一事件的管理,并且方便把事件分发到我们游戏中的各个部分,就需要自己实现一套事件系统,这样事件系统可以跟窗口类解耦。
本节解决事件如何产生与分发。
1、事件系统的实现主要是设计各种事件类
事件注册,
在事件发生那一刻,最先是由window类中注册的回调函数捕捉到事件,这个回调函数要做的事情是创建对应的事件类,并把类交给Application,这样是为让了Application将事件分发给各个Layer。
那么如何实现?
首先Application和window类是包含关系,在Application的初始化中创建了具体的Window,另外我们需要在Window类中添加一个回调函数,在创建Window时,Application立马将这个Window的回调函数注册为自己的Application::OnEvent(Event& e)。然后Window类的每个事件的回调函数只做两个事情:1-创建事件类对象。2-执行OnEvent(e)。
以glfw窗口为例,主要代码如下。
class WindowsWindow : public Window
{
public:
void WindowsWindow::Init(const WindowProps& props)
{
glfwSetWindowUserPointer(m_Window, &m_Data); //注意这个函数是为了glfw的回调中获取WindowData指针
...
//这里注册了glfw的键盘事件
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); //1-创建事件类
data.EventCallback(event); //2-执行Application的OnEvent
break;
}
case GLFW_RELEASE:
{
KeyReleasedEvent event(key);
data.EventCallback(event);
break;
}
case GLFW_REPEAT:
{
KeyPressedEvent event(key, 1);
data.EventCallback(event);
break;
}
}
});
...
}
private:
GLFWwindow* m_Window;
struct WindowData
{
std::string Title;
unsigned int Width, Height;
bool VSync;
EventCallbackFn EventCallback; //这个就是Application:OnEvent的回调
};
WindowData m_Data;
};
class HAZEL_API Application
{
public:
Application::Application()
{
m_Window = std::unique_ptr<Window>(Window::Create()); //创建Window
m_Window->SetEventCallback(HZ_BIND_EVENT_FN(Application::OnEvent)); //注册回调
}
void Application::OnEvent(Event& e)
{
EventDispatcher dispatcher(e);
dispatcher.Dispatch<WindowCloseEvent>(HZ_BIND_EVENT_FN(Application::OnWindowClose));
for (auto it = m_LayerStack.end(); it != m_LayerStack.begin(); )
{
(*--it)->OnEvent(e);
//避免事件往下派发,例如 防止UI层和游戏层同时响应点击
if (e.Handled)
break;
}
}
private:
bool OnWindowClose(WindowCloseEvent& e);
std::unique_ptr<Window> m_Window;
LayerStack m_LayerStack;
bool m_Running = true;
};
事件注册: