Event
This is an implemenation of an Event class in C++. Since C++ has no bult in event structure I created this one to facilitate the ability to assign listener functions for an arbitrary function definition.
It utilizes C++ Templates.
Implementation
Event.hpp
#pragma once
#ifndef BIT_EVENT_H
#define BIT_EVENT_H
#include <vector>
namespace bit
{
template<typename T>
class Event
{
private:
std::vector<T> listeners;
public:
template<typename A>
void trigger(A arg1)
{
for(unsigned int i=0; i < listeners.size(); i++)
listeners[i](arg1);
}
template<typename A, typename B>
void trigger(A arg1, B arg2)
{
for(unsigned int i=0; i < listeners.size(); i++)
listeners[i](arg1, arg2);
}
template<typename A, typename B, typename C>
void trigger(A arg1, B arg2, C arg3)
{
for(unsigned int i=0; i < listeners.size(); i++)
listeners[i](arg1, arg2, arg3);
}
// Registers the listener and returns its ID if it needs to remove it
unsigned int operator += (T listener)
{
listeners.push_back(listener);
return listeners.size() - 1;
}
// Removes a listener by its id
void operator -= (unsigned int index)
{
listeners.erase(listeners.begin() + index);
}
};
}
#endif
Example Usage
In a tile based game a Tile has an event called a onBodyEnter
which should fire when a character moves onto the tile. Listeners can react to this event.
Tile.hpp
// event definition
bit::Event<std::function<void(Tile* t, Body* body)>> onBodyEnter;
Tile.cpp
// event firing, body is what has entered the tile
onBodyEnter.trigger<Tile*, Body*>(this, body);
So our tile has the event defined with the function definition that the listeners should be prepared for. When a body enters the tile it triggers the event which iterates its listeners and runs them with the tile and body in context.
A listener example is a Door object that sits adjacent to tiles. It wants to know if a body enters an adjacent tile so that it can open automatically.
Door.cpp
void Door::registerTileTriggers(Tile* tile)
{
Door* d = this;
if(tile)
{
tile->onBodyEnter += [d] (Tile* t, Body* b) {
if(b->Body::schema.type == Body::Type::Character)
{
d->openerCount++;
d->attemptOpen();
}
};
tile->onBodyLeave += [d] (Tile* t, Body* b) {
if(b->Body::schema.type == Body::Type::Character)
{
d->openerCount--;
if(d->openerCount == 0)
{
d->attemptClose();
}
}
};
}
}
The Door registers a listener for the adjacent tile. When fired the lambda operation will attempt to open the door that was listening.