Multiple iEventReceivers

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Archive
Posts: 6
Joined: Tue Nov 14, 2006 8:08 am

Multiple iEventReceivers

Post by Archive »

I've been playing with the ieventreceiver nodes, and it seems i can only have one onEvent() active at a time, please correct me if im wrong.

This annoyed me cause i didn't want an enormous onEvent code. So instead i created a EventReceiverManger Class, so i figured i'd share that code with you guys.

This way you can create a event, then register it with the manager, and it will parse all events registered with it. It stores these events as a linked list.

This code is also useful if you want to activate different sets of on_events at different times, so you could declare one manager for your intro screen, one for a general gaming mode, one for a alternate gaming mode, etc.

Hell it can be used to set up all kinds of hierchial input so you can use abstraction to its fullest to simplify code.


example use:

Code: Select all

//initializes the onevent controller

GEventController eventintro(device);

//registers arbitrary classes that inherits iEventReceiver
eventdefault.AddEvent(&node1); 
eventdefault.AddEvent(&MyEvent2);
eventdefault.AddEvent(&class3);

GEventController eventgaming();

eventgaming.AddEvent(&class4);
eventgaming.AddEvent(&class5);

if(intro == done && gamingmode == started) 
device->setEventReceiver( eventgaming );

another example:

Code: Select all

gEventController player1();
gEventController player2();
/... some assignments of event to both players .../

gEventController allPlayers(device);
if (player1active ==  TRUE) allPlayers.AddEvent(player1);
if (player2active ==  TRUE) allPlayers.AddEvent(player2); 

gEventController.h

Code: Select all

#include <irrlicht.h>
#include <iostream>

struct GEventNode
{    
       GEventNode* Next;
       irr::IEventReceiver* Event;
};


using namespace irr;

#pragma comment(lib, "Irrlicht.lib")



class GEventController : public IEventReceiver
{
      public:
      
      //Constructor, initalizes controller without activating
      GEventController();
      
      //Constructor, initializes controller and activates it on the passed device
      GEventController(IrrlichtDevice* device);
      
      // Adds an onEvent Node to the linked list
      bool AddEvent(IEventReceiver* IEvent);   
      
      // Parses through all registers on_Events when primary On_event is called
      bool OnEvent(SEvent event);

      private:
      GEventNode* leadnode;
      
};     
gEventController.cpp

Code: Select all

#include "geventcontroller.h"


      //Constructor, initalizes controller without activating
      GEventController::GEventController()
      {
       leadnode = 0; //Sets Point to zero. 
      }
      
      //Constructor, initializes controller and activates it on the passed device
      GEventController::GEventController(IrrlichtDevice* device)
      {
       //sets GEventController as primary Controller
       device->setEventReceiver( this );
       leadnode = 0;  
      }  
      
      // adds a new event to the linked list
      bool GEventController::AddEvent(IEventReceiver* IEvent)
      {
           GEventNode* newnode = new GEventNode; //creates a new node
           newnode->Event = IEvent; // Sets the object to point to the event
           newnode->Next = leadnode; //Points to the previous node
           leadnode = newnode; // Sets head of the list to the newest node
           return true;
      }        
      
      // Parses through all registers Events and executes them.
      bool GEventController::OnEvent(SEvent event)
      {
           GEventNode* node = leadnode; //first event to call.
           while (node != 0) //if node points to an event, run OnEvent
           {
            node->Event->OnEvent(event);
            node = node->Next; //Goes to next node.
           }     
      }
[/code]
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

A few issues...

The custom singly-linked list leaks memory [all of the GEventNode instances] when the event controller is destructed. Maybe you should use a core::list<IEventReceiver> or core::array<IEventReceiver> instead.

There is no provision for removing event receivers. It would not be hard to do, but it would be even easier if this code were using core::array<> or core::list<>.

There is also no provision for destruction of the event receivers. There doesn't really need to be, but if the user can't remove them, then somebody has to manage them. If the user allocated their event receivers on the heap and expects the controller to manage their lifetime, they will see a memory leak. If they are smart and they deallocate their event receiver at the right time, then the event controller has a pointer to the defunct event receiver, which is likely to cause a crash.

The event controller does nothing to prevent multiple event receivers from responding to the same event. This is really just a restriction in the use of the controller, but it is something that users of this code should know.

I'm not trying to be harsh, I'm just pointing out some flaws in code that others will be likely to use.

Travis
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Oh, and most compilers I know of consider this to be a local function declaration...

Code: Select all

GEventController eventgaming(); 
It thinks you have a function named eventgaming that takes no parameters and returns a GEventController. You should remove the parens if you want to create an event controller instance.

Travis
ssexton
Posts: 54
Joined: Wed Oct 25, 2006 7:46 am
Location: South Florida
Contact:

Post by ssexton »

I hear ya on the not wanting a huge OnEvent() method. But a delegate was sufficient for my purposes. I only have one event receiver at a time, but I can change it dynamically as I switch from splash screens to login screens to game screens. Performance-wise, it only costs me one method call.

Here's the code. Its pretty straightforward:

Code: Select all

class IrrEventDelegate : public irr::IEventReceiver {
	IrrCtx* ctx;
public:
	IrrEventDelegate(IrrCtx* ctx) : ctx(ctx) {}
	
	bool OnEvent(const irr::SEvent &event) {
		return ctx->target->OnEvent(event, ctx);
	}
};
FYI, IrrCtx is my Irrlicht Context (clever name, eh?). ctx->target is the IEventReceiver that is active. More or less, its actually a custom event receiver so I can pass in the context. But you get the idea. You could easily replace the IrrCtx* with a irr::IEventReceiver**.
ssexton
Posts: 54
Joined: Wed Oct 25, 2006 7:46 am
Location: South Florida
Contact:

Post by ssexton »

Just noticed this in your code:

Code: Select all

node->Event->OnEvent(event); 
I think you want:

Code: Select all

if (node->Event->OnEvent(event)) break; 
As I understand it, the semantics of the OnEvent return bool is that "true" should be taken to mean that the handler consumed the event. So I think you want to stop running the chain at that point.
Archive
Posts: 6
Joined: Tue Nov 14, 2006 8:08 am

Post by Archive »

Thanks for the comments,

This code was initially posted as a template for how a beginner might approach the creation of an event manager. I previously hadn't worked much on the ihrlicht engine but i'm more familiar with it now.

I will update this code to use the irrlict linked lists, and break on a true return value. I'll also put a destructor and repair the memory leak. I should get this done in the next week or to.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Probably not really necessary. This suggestion has been covered several times on these forums. I did it back in March right here.

Travis
Post Reply