I've sold it with a few hacks; The problem came from trying to cast to the object it was originally from. I didnt fully understand the article though, I now have the system working in a queue like this:
extern void test_EventQueue()
{
EventQueue q;
Monster monster;
Event * test;
// add 4 events
q.push(new Explosion(10));
q.push(new Explosion(20));
q.push(new Explosion(30));
q.push(new Explosion(40));
for(int index = 0; index < 4; index++)
{
test = q.pop();
monster.handleEvent(test);
delete test;
}
};
Hi,
I've been playing with the event system i read in this gamedev.net article:
clicky
An Event, an EventHandler, and a callback function are extended from these classes:
#ifndef EVENTHANDLER_H
#define EVENTHANDLER_H
#include <map>
#include "type_info.h"
class Event
{
protected:
virtual ~Event() {};
};
class HandlerFunctionBase
{
public:
virtual ~HandlerFunctionBase() {};
void exec(const Event* event) {call(event);}
private:
virtual void call(const Event*) = 0;
};
template <class T, class EventT>
class MemberFunctionHandler : public HandlerFunctionBase
{
public:
typedef void (T::*MemberFunc)(EventT*);
MemberFunctionHandler(T* instance, MemberFunc memFn) : _instance(instance), _function(memFn) {};
void call(const Event* event)
{
(_instance->*_function)(static_cast<EventT*>(event));
}
private:
T* _instance;
MemberFunc _function;
};
class EventHandler
{
public:
~EventHandler();
void handleEvent(const Event*);
template <class T, class EventT>
void registerEventFunc(T*, void (T::*memFn)(EventT*));
private:
typedef std::map<TypeInfo, HandlerFunctionBase*> Handlers;
Handlers _handlers;
};
template <class T, class EventT>
void EventHandler::registerEventFunc(T* obj, void (T::*memFn)(EventT*))
{
_handlers[TypeInfo(typeid(EventT))]= new MemberFunctionHandler<T, EventT>(obj, memFn);
}
#endif
I then extend it to make a new event and event handler, to use the example in the article:
#include <iostream>
#include <vector>
#include "event_handler.h"
class Explosion : public Event
{
public:
Explosion(int pos) : _pos(pos), _damage(60) {};
int getPosition() const {return _pos;}
int getDamage() const {return _damage;}
private:
int _pos, _damage;
};
class Enemy
{
public:
Enemy() : _name("Bad Enemy"), _damage(15) {};
std::string getName() const {return _name;}
int getDamage() const {return _damage;}
private:
std::string _name;
int _damage;
};
class EnemyHit : public Event
{
public:
EnemyHit(Enemy* enemy) : _enemy(enemy){}
Enemy* getEnemy() const {return _enemy;}
private:
Enemy* _enemy;
};
class Monster : public EventHandler
{
public:
Monster() : _pos(20), _hp(100)
{
registerEventFunc(this, &Monster::onExplosion);
registerEventFunc(this, &Monster::onEnemyHit);
}
void receiveDamage(int dmg)
{
_hp -= dmg;
std::cout << "hp: " << _hp << std::endl;
if(_hp <= 0)
{
std::cout << "I'm dead" << std::endl;
}
}
void onExplosion(const Explosion* explosion)
{
if(abs(_pos - explosion->getPosition()) < 20)
{
std::cout << "Hit by explosion!!!" << std::endl;
receiveDamage(explosion->getDamage());
}
else
{
std::cout << "Out of explosion range :)" << std::endl;
}
}
void onEnemyHit(const EnemyHit* hit)
{
Enemy* enemy = hit->getEnemy();
std::cout << "Hit by enemy: " << enemy->getName().c_str() << " got damage: " << enemy->getDamage() << std::endl;
receiveDamage(enemy->getDamage());
}
int _pos;
int _hp;
};
class Tank
{
public:
Tank() : _eventHandler(this) {}
void handleEvent(const Event* event)
{
_eventHandler.handleEvent(event);
}
private:
class TankEventHandler : public EventHandler
{
public:
TankEventHandler(Tank* tank) : _tank(tank)
{
registerEventFunc(_tank, &Tank::onDamagedByExplosion);
}
Tank* _tank;
};
friend class TankEventHandler;
void onDamagedByExplosion(const Explosion* explosion)
{
std::cout << "Hit by explosion. Whatever" << std::endl;
}
TankEventHandler _eventHandler;
};
int main()
{
std::cout << "=== Monster ===" << std::endl;
Monster monster;
monster.handleEvent(new Explosion(40));
monster.handleEvent(new Explosion(10));
monster.handleEvent(new EnemyHit(new Enemy));
monster.handleEvent(new EnemyHit(new Enemy));
monster.handleEvent(new EnemyHit(new Enemy));
std::cout << "\n=== Tank ===" << std::endl;
Tank tank;
tank.handleEvent(new Explosion(40));
tank.handleEvent(new Explosion(10));
tank.handleEvent(new EnemyHit(new Enemy));
system("PAUSE");
}
My question is simple, how do I make a queue of the base type, whereby I can figure out which type of event im looking at? e.g. if I create a new Explosion, I want to push that to a queue of generic Event*, then later re-interpret it as an Explosion?
[Edited by - speciesUnknown on November 23, 2008 5:44:00 PM]