使用事件系统可以根据输入(即键盘、鼠标、触摸或自定义输入)将事件发送到应用程序中的对象。事件系统包含一些共同协作以发送事件的组件。
将事件系统组件添加到游戏对象时,应该会注意到该组件未公开太多功能,这是因为事件系统本身设计为事件系统模块之间通信的管理器和协调器。
事件系统的主要作用如下:
管理视为选中状态的游戏对象
管理正在使用的输入模块
管理射线投射(如果需要)
根据需要更新所有输入模块
话不多说,直接开始:
Event.h
,ApplicationEvent.h
,KeyEvent.h
,MouseEvent.h
作为所有事件的头文件 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), //BIT 在 Core.h 中定义 #define BIT(x) (1 << x)
EventCategoryInput = BIT(1),
EventCategoryKeyboard = BIT(2),
EventCategoryMouse = BIT(3),
EventCategoryMouseButton = BIT(4)
};
Event.h
创建 Event 基类#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 CategoryFlags() const override { return category; }
class HAZEL_API Event {
friend class EventDispatcher;
public:
virtual EventType GetEventType() const = 0;
virtual const char* GetName() const = 0;
virtual int GetCategoryFlags() const = 0;
virtual std::string ToString() const { return GetName(); }
inline bool IsInCategory(EventCategory category) {
return GetCategoryFlags() & category;
}
protected:
bool m_Handled = false; //显示当前工作的事件
};
class EventDispatcher //事件提交
{
public:
EventDispatcher(Event& event)
: m_Event(event)
{
}
// 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;
}
private:
Event& m_Event;
};
inline std::ostream& operator<<(std::ostream& os, const Event& e)
{
return os << e.ToString();
}
ApplicationEvent.h
创建 WindowResizeEvent class 继承自 Event ,用于对 windowSize 的修改 class HAZEL_API WindowResizeEvent : public Event {
public:
WindowResizeEvent(unsigned int width, unsigned int height)
: m_Width(width), m_Height(height) {}
inline unsigned int GetWidth() { return m_Width; }
inline unsigned int GetHeight() { 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;
};
class WindowCloseEvent : public Event
{
public:
WindowCloseEvent() = default;
EVENT_CLASS_TYPE(WindowClose)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
};
class AppTickEvent : public Event
{
public:
AppTickEvent() = default;
EVENT_CLASS_TYPE(AppTick)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
};
class AppUpdateEvent : public Event
{
public:
AppUpdateEvent() = default;
EVENT_CLASS_TYPE(AppUpdate)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
};
class AppRenderEvent : public Event
{
public:
AppRenderEvent() = default;
EVENT_CLASS_TYPE(AppRender)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
};
KeyEvent.h
在该头文件中定义了按下按键以及释放按键所触发的事件,均继承自 KeyEvent class class HAZEL_API KeyEvent : public Event {
public:
inline GetKeyCode() const { return m_KeyCode; }
EVENT_CLASS_CATEGORY(EventCategoryKeyboard | EventCategoryInput)
protected:
KeyEvent(int keycode) : m_Keycode(keycode) {} //nothing else can construct it
int m_KeyCode;
};
class HAZEL_API KeyPressedEvent : public KeyEvent {
public:
KeyPressedEvent(int keycode, int repeatCount) : KeyEvent(keycode),
m_RepeatCount(repeatCount) {}
inline GetRepeatCount() const { return m_RepeatCount; }
std::string ToString() const override {
std::stringstream ss;
ss << "KeyPressEvent: " << m_KeyCode << "(" << m_RepeatCount << "repeats)";
return ss.str();
}
EVENT_CLASS_TYPE(KeyPressed)
private:
int m_RepeatCount; //设置该成员的目的是为了让我们在只按一个键的时候,不至于一直重复
};
class HAZEL_API KeyRelseasedEvent : public KeyEvent {
public:
KeyRelseasedEvent(int keycode) : KeyEvent(keycode) {}
std::string ToString() const override {
std::stringstream ss;
ss << "KeyReleasedEvent: " << m_KeyCode;
return ss.str();
}
EVENT_CLASS_TYPE(KeyReleased)
};
MouseEvent.h
中定义了鼠标操作的各种事件, 包括鼠标的移动,滚动,以及鼠标按键的按下和释放 class HAZEL_API MouseMoveEvent : public Event {
public:
MouseMoveEvent(float x, float y) : m_MouseX(x), m_MouseY(y) {}
inline float GetX() { return m_MouseX; }
inline float GetY() { return m_MouseY; }
std::string ToString() const override {
std::stringstream ss;
ss << "MouseMoveEvent: " << m_MouseX << ", " << m_MouseY;
return ss.str();
}
EVENT_CLASS_TYPE(MouseMoved)
EVENT_CLASS_CATEGORY(EventCategoryMouse | EventCategoryInput)
private:
float m_MouseX, m_MouseY;
};
class HAZEL_API MouseScrolledEvent : public Event {
public:
MouseScrolledEvent(float xOffset, flaot yOffset) : m_XOffset(xOffset), m_YOffset(yOffset) {}
inline GetXOffset() { return m_XOffset; }
inline GetYOffset() { return m_YOffset; }
std::string ToString() const override {
std::stringstream ss;
ss << "MouseScrolledEvent: " << m_XOffset << ", " << m_YOffset;
return ss.str();
}
EVENT_CLASS_TYPE(MouseScrolled)
EVENT_CLASS_CATEGORY(EventCategoryMouse | EventCategoryInput)
private:
float m_XOffset, m_YOffset
};
class MouseButtonEvent : public Event
{
public:
MouseCode GetMouseButton() const { return m_Button; }
EVENT_CLASS_CATEGORY(EventCategoryMouse | EventCategoryInput | EventCategoryMouseButton)
protected:
MouseButtonEvent(const MouseCode button)
: m_Button(button) {}
MouseCode m_Button;
};
class MouseButtonPressedEvent : public MouseButtonEvent
{
public:
MouseButtonPressedEvent(const MouseCode button)
: MouseButtonEvent(button) {}
std::string ToString() const override
{
std::stringstream ss;
ss << "MouseButtonPressedEvent: " << m_Button;
return ss.str();
}
EVENT_CLASS_TYPE(MouseButtonPressed)
};
class MouseButtonReleasedEvent : public MouseButtonEvent
{
public:
MouseButtonReleasedEvent(const MouseCode button)
: MouseButtonEvent(button) {}
std::string ToString() const override
{
std::stringstream ss;
ss << "MouseButtonReleasedEvent: " << m_Button;
return ss.str();
}
EVENT_CLASS_TYPE(MouseButtonReleased)
};
至此,事件系统就设置完成了。