[solved] How to make an event queue for...

Started by
1 comment, last by ChaosEngine 15 years, 4 months ago
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]
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!
Advertisement
I think you'll either have to use a dynamic_cast<>, or keep the data-type known with the Event class, such as...

class Event{    protected:        enum EventType { EVT_ESPOSION, EVT_ENEMYHIT };    public:         ~Event();                    virtual EventType GetEventType() const = 0;}class Explosion : public Event{     ...     public:         ...         virtual EventType GetEventType() const         {                return EVT_EXPLOSION;         }};Then, based on what GetEventType() returns, you can cast it to the necessary type.
have a look at this article. http://www.ddj.com/cpp/184405527
if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight

This topic is closed to new replies.

Advertisement