0%

游戏引擎学习之旅(2)事件系统

视频学到了S022,分析一下Hazel的事件系统是如何实现的。

先看看Application类里如何处理jj下面这里的 变量层栈的for循环里,if(e.Handled)为true,就退出不处理了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Application::OnEvent(Event& e)
{
HZ_PROFILE_FUNCTION();

EventDispatcher dispatcher(e);
dispatcher.Dispatch<WindowCloseEvent>(HZ_BIND_EVENT_FN(Application::OnWindowClose));
dispatcher.Dispatch<WindowResizeEvent>(HZ_BIND_EVENT_FN(Application::OnWindowResize));

for (auto it = m_LayerStack.rbegin(); it != m_LayerStack.rend(); ++it)
{
if (e.Handled)
break;
(*it)->OnEvent(e);
}
}

这里显示用了一个dispatcher来处理窗口关闭和窗口重定义大小,这里的写法是判断事件类型是否符合传入的Callback处理函数,如果匹配了,就设置Handled为true(看下面的OnWindowClose返回的true,这样异或为true)。看下面的循环,Handled为true会直接退出。

dispatch
1
2
3
4
5
6
7
8
9
10
11
// F will be deduced by the compiler
template<typename T, typename F>
bool Dispatch(const F& func)
{
if (m_Event.GetEventType() == T::GetStaticType())
{
m_Event.Handled |= func(static_cast<T&>(m_Event));
return true;
}
return false;
}
1
2
3
4
5
6
7
8
9
    bool Application::OnWindowClose(WindowCloseEvent& e)

    {

        m_Running = false;

        return true;

    }

下面这个事件处理返回的就是false,表示这个事件没有处理完,穿透层,下一层继续处理。

1
2
3
4
5
6
  bool ImGuiLayer::OnMouseButtonPressedEvent(MouseButtonPressedEvent& e) {
ImGuiIO& io = ImGui::GetIO();
io.MouseDown[e.GetMouseButton()] = true;
ET_CORE_TRACE(e.ToString());
return false;
}

这个Handled可以在层设置阻挡,ImGuiLayer这里的设置:
阻挡成功Handled就设置为true。

1
2
3
4
5
6
7
8
9
void ImGuiLayer::OnEvent(Event& e)
{
if (m_BlockEvents)
{
ImGuiIO& io = ImGui::GetIO();
e.Handled |= e.IsInCategory(EventCategoryMouse) & io.WantCaptureMouse;
e.Handled |= e.IsInCategory(EventCategoryKeyboard) & io.WantCaptureKeyboard;
}
}

那么如何设置事件类型呢?
在事件发生的时候,glfw会自动调用下面我们在窗口初始化的时候设置的回调函数,这里的data.EventCallback(evnet)就是设置Event的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
        // Set GLFW callbacks

        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);

        });

data的类型就是下面的函数指针

1
using EventCallbackFn = std::function<void(Event&)>;

这里提供了Event类型,EventDispatcher提供了处理事件的函数。
这就是我对整个事件系统的理解了。