I am trying to implement a basic event system. This event system consists of a series of void pointers used for callback functions. The code below is BAD design. If I want to add many events, the code quickly gets bloated.
Currently, the bad solution needs to know what vector to add to, and which vector to run based off of the event type. Ideally, I could store all the void pointers in a single vector, and based off of the type of event that occurs, the function pointers using that event could be run.
If anyone has any ideas they would like to give for a better implementation, it would be greatly appreciated.
Example event handler class:
#include <vector>
typedef void(*CALLBACK)();
enum EventType {
WINDOW_RESIZE,
WINDOW_CLOSE,
};
class EventManager {
public:
// Add a callback function
void bind(CALLBACK f, EventType type) {
switch(type) {
// Note I would need to implement a case for all the events
case WINDOW_RESIZE: {
window_resize_event.push_back(f);
}
///...
}
}
// This would poll the event queue, and based on the
// event, run the callback functions
void update() const {
unsigned int event;
if (event == WINDOW_RESIZE) {
///iterate through vector
}
///...
}
private:
std::vector <callback> window_resize_event;
std::vector <callback> window_close_event;
};
Edit: The implemented solution using a multi map
#include <stdio.h>
#include "event.hpp"
EventManager::EventManager() {
std::vector <CALLBACK> callbacks;
// Copy callbacks vector into each
events.insert(std::pair <EventType, std::vector <CALLBACK>> (WINDOW_CLOSE , callbacks));
events.insert(std::pair <EventType, std::vector <CALLBACK>> (WINDOW_RESIZE , callbacks));
events.insert(std::pair <EventType, std::vector <CALLBACK>> (KEY_DOWN , callbacks));
events.insert(std::pair <EventType, std::vector <CALLBACK>> (KEY_UP , callbacks));
events.insert(std::pair <EventType, std::vector <CALLBACK>> (MOUSE_DOWN , callbacks));
events.insert(std::pair <EventType, std::vector <CALLBACK>> (MOUSE_UP , callbacks));
events.insert(std::pair <EventType, std::vector <CALLBACK>> (MOUSE_MOVED , callbacks));
events.insert(std::pair <EventType, std::vector <CALLBACK>> (MOUSE_SCROLLED, callbacks));
}
void EventManager::bind(const CALLBACK &f, const EventType &type) {
std::multimap <EventType, std::vector <CALLBACK>>::iterator it;
for (it = events.begin(); it != events.end(); it++) {
if (it->first == type) {
it->second.push_back(f);
return;
}
}
printf("Unknown event type\n");
}
void EventManager::update() {
std::multimap <EventType, std::vector <CALLBACK>>::iterator it;
while (SDL_PollEvent(&event)) {
for (it = events.begin(); it != events.end(); it++) {
// Cast event to the SDL equivalent
if (event.type == static_cast <uint32_t> (it->first)) {
run(it->second);
}
}
}
}
void EventManager::run(const std::vector <CALLBACK> &callbacks) {
// Call the registered functions
for (unsigned int i = 0; i < callbacks.size(); i++) {
(*callbacks[i])();
}
}