Advertisement

How can i make an event system?

Started by April 27, 2024 11:41 PM
4 comments, last by The Luke 6 months, 3 weeks ago

Hello, can anyone help me with how I can implement an event system in my game engine that I'm making in C++?

Well, i think its fair to say that you need to provide some more information.
What have you tried so far? Do you have any existing code that is not working correctly?

Without knowing anything about your requirements for the event system, a theoretical system (simple as it may be) could work something like this:

Create a interface “EventListener” providing the virtual function “onEvent”, each time you allocate something that inherits from that interface you also register the instance in the event system. Somewhere else in your code something uses the event system to fire events and thus looping over all registered listeners and invoking “onEvent”.

And voila there you have an event system.

This example is very simple an may not be what you are looking for. But it should provide you with a starting point in figuring out how you want your system to work.

Advertisement

@Noxil Well, I created a very basic event system because as I'm already using SDL, which also has its events, I didn't feel the need to create something so complex, as this event system would just be to decouple and be able to call events from anywhere without know who called or who will receive this event.

As in my case the engine is started by the Application class and this class that controls the main loop of the engine and the SDL events will be managed by the Window class, so when the window receives the SDL_QUIT event or any other event it would send an event to terminate the application and in the Application class when receiving the event to close, the bool variable that maintains the loop will be equal to false.

My implementation is as follows:
Event.h
#ifndef EVENT_H

#define EVENT_H

#include <vector>

namespace TES

{

enum EventType

{

NONE,

CLOSE_APPLICATION

};

class Event

{

public:

EventType type_;

Event(EventType type)

: type_(type)

{

}

};

class EventManager

{

public:

static EventManager& Get()

{

static EventManager* instance = new EventManager();

return *instance;

}

void RegisterEvent(EventType type)

{

Event event(type);

events.push_back(event);

}

EventType GetEventType() const

{

for (Event event : events)

{

return event.type_;

}

}

void ClearEvents()

{

if (events.size() != 0)

{

events.pop_back();

}

}

private:

EventManager() {}

std::vector<Event> events;

};

}

#define REGISTER_EVENT(type) ::TES::EventManager::Get().RegisterEvent(type);

#endif

Window.cpp
void Window::Update()

{

while (SDL_PollEvent(&event))

{

switch (event.type)

{

case SDL_QUIT:

REGISTER_EVENT(CLOSE_APPLICATION);

break;

default:

break;

}

}

}


Application.cpp
void Application::Run()

{

window.Create();

while (running)

{

OnEvent();

EventManager::Get().ClearEvents();

window.Update();

}

}


void Application::OnEvent()

{

switch (EventManager::Get().GetEventType())

{

case CLOSE_APPLICATION:

LOG_INFO("CLOSE_APPLICATION");

running = false;

break;

default:

break;

}

}

To explain: in the event header file, the event types will be in the EventType enum, the Event class is an event with a type that will be sent/received, and the EventManager is a singleton so it can be accessed by every engine where the events vector stores the current events, RegisterEvent creates a new Event and pushes it to the event vector, GetEventType will loop to the last event and return it, and ClearEvents will remove the last event from the vector.

But I feel that my implementation is not good, and I wanted to know how I could improve or remake it in a reasonably good way, in a flexible and scalable way, so if you have any good articles, books or videos on how I can implement a good system of events I'll be happy to learn. And it's also worth mentioning that I'm still an apprentice.

Alright so im gonna give you an example on how you could implement an event system like i described in my first post.

First we have the “EventListener”, its an interface that will be used on classes that should be notified when an event is fired. It takes as an argument the event type (your event class).

class EventListener {
public: 

	virtual ~EventListener() = default;
	
	virtual void onEvent( Event pEvent ) = 0;
	
};

Then we can modify your “Application” class like this:

// .h
class Application : public EventListener {
public:
		
	void onEvent( Event pEvent ) override;

private:

	bool isRunning = true;

};

// .cpp
void Application::onEvent( Event pEvent ) {
	if( pEvent.type_ == CLOSE_APPLICATION ) {
		isRunning = false;
	}
}

So with these changes the “Application” is now ready to be a receiver of events and will set a member variable “isRunning” to false whenever it would get the “CLOSE_APPLICATION” event.

Before we can get things going we need to update your “EventManager” class like this:

// .h
class EventManager {
public:

	void register( EventListener * pListener );
	void fire( Event pEvent );

private:

	std::vector< EventListener * > listeners;

};

// .cpp
void EventManager::register( EventListener * pListener ) {
	listeners.push_back( pListener );
}

void EventManager::fire( Event pEvent ) {
	for( auto listener : listeners ) {
		listener->onEvent( pEvent );
	}
}

The final piece of the puzzle is then to register your application class to the event manager.

This code changes how your “EventManager” currently does things, but its fairly straight forward in terms of how it works and i think you can get it to work for your needs.

Note that this code is intended to be clear and easy to understand. Best practices regarding performance, maintainability, extensibility etc is a topic on its own.

@Noxil Ok, Thank you!

This topic is closed to new replies.

Advertisement