Sign in to follow this  
speciesUnknown

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

Recommended Posts

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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this