Best Object Manager/Handling Practices
Best Object Manager/Handling Practices
What are the theories out there on object handling/managers?
e.g. A class for NPC's; A class for Weapons; A class for Players and accessing single objects from one class in another?
My thought is to store all elements of a certain type in their own vector Vector *NPC; Vector *Weapons; Vector *Players
Have a seperate function for each which will iterate through each vector and do said function passing it the ISceneNode to compare to the whole vector and do said function on the specific object
e.g. Void HurtNPC(ISceneNode* theNPC, int Dmg) would iterate through the entire vector of NPC finding the specific NPC we want to hurt and then call its member function it->Hurt(Dmg);
Is there a better method to use to accomplish this? Or am I on the right track?
e.g. A class for NPC's; A class for Weapons; A class for Players and accessing single objects from one class in another?
My thought is to store all elements of a certain type in their own vector Vector *NPC; Vector *Weapons; Vector *Players
Have a seperate function for each which will iterate through each vector and do said function passing it the ISceneNode to compare to the whole vector and do said function on the specific object
e.g. Void HurtNPC(ISceneNode* theNPC, int Dmg) would iterate through the entire vector of NPC finding the specific NPC we want to hurt and then call its member function it->Hurt(Dmg);
Is there a better method to use to accomplish this? Or am I on the right track?
Dream Big Or Go Home.
Help Me Help You.
Help Me Help You.
Re: Best Object Manager/Handling Practices
Well you could thing about something like this.
Code: Select all
/*
Copyright (C) 2012 Daniel Sudmann
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Daniel Sudmann suddani@googlemail.com
*/
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct ISceneNode
{
};
struct Message
{
virtual int getMessageType() = 0;
};
template<class T>
struct Message_ : Message
{
static T* convert(Message* msg)
{
return (T*)(msg);
}
int getMessageType()
{
return getType();
}
static int getType()
{
static int type_id = 0;
return (int)&type_id;
}
};
struct MessageDispatcher
{
struct EventHandlerBase
{
virtual bool check(Message* message) = 0;
virtual void call(Message* message) = 0;
};
template<class T, class MessageType>
struct EventHandler : EventHandlerBase
{
typedef void (T::*Callback)(MessageType*);
EventHandler(T* object, Callback call)
{
Object = object;
MyCallback = call;
}
void call(Message* message)
{
(Object->*MyCallback)(Message_<MessageType>::convert(message));
}
bool check(Message* message)
{
return message->getMessageType() == Message_<MessageType>::getType();
}
T* Object;
Callback MyCallback;
};
void sendMessage(Message* msg)
{
for (int i=0;i<handlers.size();i++)
{
if (handlers[i]->check(msg))
handlers[i]->call(msg);
}
}
template<class T, class MessageType>
void bind(T* t, void (T::*func)(MessageType* msg))
{
handlers.push_back(new EventHandler<T, MessageType>(t, func));
}
std::vector<EventHandlerBase*> handlers;
};
struct DMGMessage : Message_<DMGMessage>
{
DMGMessage(int d, ISceneNode* n)
{
dmg = d;
node = n;
}
int dmg;
ISceneNode* node;
};
struct WhateverMessage : Message_<WhateverMessage>
{
};
struct NPC
{
NPC(ISceneNode* n)
{
node = n;
}
ISceneNode* node;
void onDamage(DMGMessage* dmg)
{
if (dmg->node != node)
return;
printf("NPC received %i damage\n", dmg->dmg);
}
};
struct Player
{
Player(ISceneNode* n)
{
node = n;
}
ISceneNode* node;
void takeDamage(DMGMessage* dmg)
{
if (dmg->node != node)
return;
printf("Player received %i damage\n", dmg->dmg);
}
};
struct InvinciblePlayer : Player
{
InvinciblePlayer(ISceneNode* n) : Player(n)
{
}
void whatever(WhateverMessage* msg)
{
printf("InvinciblePlayer received whatever msg\n");
}
};
int main(int argc, char* argv[])
{
srand(time(0));
MessageDispatcher dispatcher;
ISceneNode npc_node;
ISceneNode player_node;
ISceneNode iplayer_node;
NPC npc(&npc_node);
Player player(&player_node);
InvinciblePlayer iplayer(&iplayer_node);
dispatcher.bind(&npc, &NPC::onDamage);
dispatcher.bind(&player, &Player::takeDamage);
dispatcher.bind(&iplayer, &InvinciblePlayer::whatever);
printf("Send damage!!\n");
DMGMessage dmg(5, rand()%2 == 0 ? &player_node : rand()%2 == 0 ? &npc_node : &iplayer_node); ///hitting one node randomly, when it chooses the iplayer_node no one is hit actually
dispatcher.sendMessage(&dmg);
printf("Send damage Done\n");
printf("\n\n");
printf("Send WhateverMessage!!\n");
WhateverMessage wtf;
dispatcher.sendMessage(&wtf);
printf("Send WhateverMessage Done\n");
return 0;
}
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Re: Best Object Manager/Handling Practices
Well maybe this should have gone with some kind of explanation.
When you do it like that you are basicly letting your Entities decide wether or not the dmg belongs to them. You could however make every of your entity a Dispatcher itself and create a bigger one which distributes to the correct one so you have some kind of sorting. So like one big Entity Disptacher which somehow decides wether or not a message is ment for some entity or not, maybe a little smarter than just going through a big list^^
Next bonus would be if every entity is a messageDispatcher you could just grap any entity in your game and send a message to it. Then the entity reacts or not which is quite nice.
PS: the implementation i gave you lacks a lot of things. like unregister in case a subscriber is removed before the dispatcher is or a subscriber doesn't want to subscribe anymore
When you do it like that you are basicly letting your Entities decide wether or not the dmg belongs to them. You could however make every of your entity a Dispatcher itself and create a bigger one which distributes to the correct one so you have some kind of sorting. So like one big Entity Disptacher which somehow decides wether or not a message is ment for some entity or not, maybe a little smarter than just going through a big list^^
Next bonus would be if every entity is a messageDispatcher you could just grap any entity in your game and send a message to it. Then the entity reacts or not which is quite nice.
PS: the implementation i gave you lacks a lot of things. like unregister in case a subscriber is removed before the dispatcher is or a subscriber doesn't want to subscribe anymore
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Re: Best Object Manager/Handling Practices
Thank you very much for the ideas and supplied code; It's going to take me a minute to go through it and figure out exactly what is going on then extrapolate it out and use it in my own project; I'll post back in a day or so and let you know how i'm doing! Thank you very much for your help :)
Dream Big Or Go Home.
Help Me Help You.
Help Me Help You.
Re: Best Object Manager/Handling Practices
Thank you thank you thank you SO much; this is an amazing system! eliminates SO many performance hindering issues I usually create throughout my projects; I usually loop through a vector of all my objects to update them each frame; now I only need to send a message to the appropriate object I need updated when it needs updated, you will most definitely receive credit for this in my projects; thank you sir/madam!
Dream Big Or Go Home.
Help Me Help You.
Help Me Help You.
Re: Best Object Manager/Handling Practices
Why do you need such a complicated structure to send data?
I usually make a base class called objectManager, for example, which contains an array of my object type, array <objectType*> object. In the base class it has void Damage( s32 id).
Whenever something wants to damage another thing it calls objectManager->damage(id).
For organizing IDs, each addition to the array has its own scenenode id and id to array number id.
Ezpz
I usually make a base class called objectManager, for example, which contains an array of my object type, array <objectType*> object. In the base class it has void Damage( s32 id).
Whenever something wants to damage another thing it calls objectManager->damage(id).
For organizing IDs, each addition to the array has its own scenenode id and id to array number id.
Ezpz
Re: Best Object Manager/Handling Practices
Well my suggestion is that just more flexible.
My System allows the following:
Imagine an FPS, you through a grenade and its supposed to interact with all dynamic objects. The physics engine gets all simulated objects and applies some force. Then normaly you would have to go to your damage system and pick the correct objects and apply damage there. Now does basicly the same just with the twist you feel like you don't have to design this damage system but it just works.
My System allows the following:
Imagine an FPS, you through a grenade and its supposed to interact with all dynamic objects. The physics engine gets all simulated objects and applies some force. Then normaly you would have to go to your damage system and pick the correct objects and apply damage there. Now does basicly the same just with the twist you feel like you don't have to design this damage system but it just works.
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Re: Best Object Manager/Handling Practices
Now one could argue that designing all systems by hand differently and carefully might be the better option, bc no doubt my system is easily abused in ways it should not be used...but then again when it gets the job done it is a valid solution and the best thing on implementation serves them all^^
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Re: Best Object Manager/Handling Practices
Maybe it depends on how you make your base objects. I always define a class with members like hitpoints, position, and scene node. The scene node contains the id of a unique in game iteration, and the base class has one variable for scene node id, and array position. This way if I'm using scene node ray intersection I do things one way, and world position
methods iterate another way.
Anyhow it really depends on what kind of interaction you need. Also, if you want to code fully OOP or OO/procedural.
Seeing as I always code halfway between the two, my systems need to be flexible
methods iterate another way.
Anyhow it really depends on what kind of interaction you need. Also, if you want to code fully OOP or OO/procedural.
Seeing as I always code halfway between the two, my systems need to be flexible
Re: Best Object Manager/Handling Practices
@sudi Do you have any suggestions on how to add an 'unbind' function? I've tried a few ways without success.
basically I created a message that is sent to all object's it's bound to; If I remove one of these objects that have that specific message bound to it the message handler still tries to call the object which is no longer in memory.
I tried a simple check to see if(!Object) { return; } but that always returns true;
I tried to create an unbind function that did a .erase on the vector after finding the id but thats not working well at all; I'm not familiar with templates and how they work so i'm getting confused
I could just loop through a vector of all these objects i'm sending the message to but that would defeat the entire purpose of using the message handler
Just looking for your input on the matter :)
basically I created a message that is sent to all object's it's bound to; If I remove one of these objects that have that specific message bound to it the message handler still tries to call the object which is no longer in memory.
I tried a simple check to see if(!Object) { return; } but that always returns true;
I tried to create an unbind function that did a .erase on the vector after finding the id but thats not working well at all; I'm not familiar with templates and how they work so i'm getting confused
I could just loop through a vector of all these objects i'm sending the message to but that would defeat the entire purpose of using the message handler
Just looking for your input on the matter :)
Dream Big Or Go Home.
Help Me Help You.
Help Me Help You.
Re: Best Object Manager/Handling Practices
when binding an object a new istance is created. So only the Handlers vector has reference to that no other one can store its reference, that's mean that externally you can't search for it and delete. A possible solution is that the bind function calls a "reference" method on the binded object in order to give it the pointer to the new handler, so that you have a parameter for search and deleting it:
T need to have both "reference" and "dereference". just inerith any event receiver like "Player" from a "ReceiverBase":
simple example with only 1 EventHandler (theorically should have internally a vector of handlers, but keep things simple this is just example)
this is just a fast draft. A better solution exist for sure. just 5 minutes. don't expect too much from this code.
If you use a more complex version and have a vector isntead of "myBase" then you have to search in Handlers every element of "myBase" and remove that from the vector
Code: Select all
struct EventHandlerBase
{
virtual bool check(Message* message) = 0;
virtual void call(Message* message) = 0;
virtual EventHandlerBase * getBase() { return this;}
};
template<class T, class MessageType>
void bind(T* t, void (T::*func)(MessageType* msg))
{
EventHandler<T, MessageType> handler = newEventHandler<T,MessageType>(t,func);
t->reference(handler->getBase());
handlers.push_back(new EventHandler<T, MessageType>(t, func));
}
template < class T >
void unbind(T * item) //maybe item has EventDispatcher as friend and "dereference" is private?.
{
EventHandlerBase * handler = item->dereference();
std::vector<EventHandlerBase*>::iterator handler_it;
handler_it = std::find(handlers.begin(), handlers.end(), handler);
if(handler_it != handlers.end() )
{
delete (*handler_it); //delete handler istance
handlers.erase(handler_it);
return;
}
item->reference( (*handler_it)); //istance not in handlers vector. maybe signal error in some way?.
}
simple example with only 1 EventHandler (theorically should have internally a vector of handlers, but keep things simple this is just example)
Code: Select all
class ReceiverBase
{
ReceiverBase():myBase(0){ } //ctor
EventHandlerBase * myBase; //reference to event handler
friend struct EventDispatcher;
void reference(EventHandlerBase* base) { assert(myBase == 0); myBase = base;}
EventHandlerBase * dereference() { EventHandlerBase* base = myBase; myBase =0; return base;}
};
If you use a more complex version and have a vector isntead of "myBase" then you have to search in Handlers every element of "myBase" and remove that from the vector
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me