Somehow I came over the question of how to build a good entity managment.. (it somewhat keeps me thinkingy -_-)
Idea:
an Entity Manager that got a map/vector/tree of entitys (maybe somewhat organised as a Quadtree or stuff). via manager->register(MyEntity) one can add an (derivated class) Entity to this map. The manager now will call certain events for this all the entitys. (Collision, update, interaktion etc) Those events are virtual Functions one can modify.
Disatvantage: every event will be passed to every Entity -_-
There might be some ways around this (having a list of all entitys that are interested in a special event or something, delegates etc)
(I'd allways would like to have suggestions)
Each entity need to have a way to comunicate with the others entitys propertys -> for example calling members or modifying some variables.
Example: We got a explosion entity that will damage every other entity that will collide with it. So we have the collision callback collided(Centity *other)
now assume this callback is triggered for the spaceship -> whatever
No we need to figure out what kind of collision did happen. The class Centity will simply have some ID (either a String or a Int) now we are able to access this value of the xplosion entity since its part of Centity and thus other->ID works. Now we determin other->ID=="explosion"
*Edit* maybe using RTTI? ->dammit slow??
The next step would be to figure out some internal value (lets say the strength.) So we got a few ways to make this values accessable:
1) We make some public values available in Centity. For example lets say 20 public floats (lets call 'em skills) -> this is the method used by the A6 engine. I guess this is the most retarded way of handeling this.
2) We create some virtual functions in Centity that will take a variable name and return its value. ->suxx since one always would have to build this function and returnvalues have to be a fixed type -_-
3) we have to cast Centity* other to CentityExplosion* to access its internal values. (I think this is the best version.. but still suxx)
4) another better way
which way would you say might be the best?
Everytime I get a new Idea I will find a whole bunch of disatvantages so I was not able to come to some kind of conclusion ^^
Is there any good litrature/papers around regarding entity Managment etc. ??
greetz TGM
Gameengine: design question regarding entitys
-
- Posts: 275
- Joined: Fri May 12, 2006 6:37 pm
- Location: Germany
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
The same answer that I always give:
If you're working to changeable requirements, sure, go hog wild on a flexible architecture.
If you're working to your requirements, then invest your time on requirements and paper design instead, then implement the minimum required to satisfy those requirements and design.
In this case, work out what your most complex game objects need to do, then see if there's anything that would benefit from being generalised and abstracted. Don't start from the point of view of writing an all singing, all dancing generalised entity and then specialising it.
If you're working to changeable requirements, sure, go hog wild on a flexible architecture.
If you're working to your requirements, then invest your time on requirements and paper design instead, then implement the minimum required to satisfy those requirements and design.
In this case, work out what your most complex game objects need to do, then see if there's anything that would benefit from being generalised and abstracted. Don't start from the point of view of writing an all singing, all dancing generalised entity and then specialising it.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
-
- Posts: 275
- Joined: Fri May 12, 2006 6:37 pm
- Location: Germany
well, I do not plan writing an engine... Its just I'm curious how this might be done the best/most elegant way...
So lets assume someone would want to desing that ueber entity-engine, what would be the way to do it.. (wll, I know there are several ways as always, and no one turns out to be the "best", "greatest" etc. But there will be some most flexible)
So lets assume someone would want to desing that ueber entity-engine, what would be the way to do it.. (wll, I know there are several ways as always, and no one turns out to be the "best", "greatest" etc. But there will be some most flexible)
I have always preferred to use a robust messaging system for entity to entity communication. It allows me to do a multitude of things.
1) log all events for debugging
2) time delay the messages (example, guard notices player and I want to simulate delayed reaction. send message to self saying to change states to attack, but delay the deliveryt time.
3) obects dont need to know about each other. this one is important. the fireball spell just sends a message to all affected objects (objects in range) and the objects react acordingly. Paper will burn, a metal sword will do nothing and the fire golem will grow back a few hit points. example at bottom.
I go so far as to use the messages to pump the state manager of the objects. it allows me to log literally everything that gets sent to the objects.
1) log all events for debugging
2) time delay the messages (example, guard notices player and I want to simulate delayed reaction. send message to self saying to change states to attack, but delay the deliveryt time.
3) obects dont need to know about each other. this one is important. the fireball spell just sends a message to all affected objects (objects in range) and the objects react acordingly. Paper will burn, a metal sword will do nothing and the fire golem will grow back a few hit points. example at bottom.
Code: Select all
// a simple message class
class CSObjectMessage
{
public:
ADD_PUBLIC(int,m_Type,Type); // message type
ADD_PUBLIC(int,m_Type2,Type2); // message type
ADD_PUBLIC(int,m_Source,Source); // who initiated this message
ADD_PUBLIC(int,m_Dest,Dest); // who is the message going to
ADD_PUBLIC(float,m_RTime,RTime); // what time was the message sent
ADD_PUBLIC(float,m_DTime,DTime); // what time to deliver the message
char m_Data[255];
char* GetData() { return m_Data; };
void SetData(char* data) { strcpy(m_Data,data); };
CSObjectMessage(); // class constructor
virtual ~CSObjectMessage(); // class destructor
// dual creation allows for better error handling
virtual bool Create(int type, int type2, int source,int dest, float rtime, float dtime, char* data);
};
I go so far as to use the messages to pump the state manager of the objects. it allows me to log literally everything that gets sent to the objects.
Code: Select all
void CSObject::Frame()
{
Debug_Logf("CSObject::Frame()");
if (next_state != state)
{
if (force_state_change)
{
SendObjectMessage(MSG_RESERVED_Exit,0,GetId(),GetId(),0,0,"");
state = next_state;
next_state = state;
force_state_change = false;
SendObjectMessage(MSG_RESERVED_Enter,0,GetId(),GetId(),0,0,"");
}
SendObjectMessage(MSG_RESERVED_Update,0,GetId(),GetId(),0,0,"");
}
}
Code: Select all
bool CSObject::ReceiveObjectMessage(CSObjectMessage* m)
{
Debug_Logf("CSObject::ReceiveMessage(%d %d %d %d %f %f)",m->GetType(),m->GetType2(),m->GetSource(),m->GetDest(),m->GetRTime(),m->GetDTime());
if (m == NULL)
{
Debug_Logf(" message is NULL!!!");
return false;
}
switch (m->GetType())
{
case MSG_NULL :
case MSG_RESERVED_Enter : // Don't send this message - the system sends this when a state is first entered - Use OnInitialize to listen for it
case MSG_RESERVED_Exit : // Don't send this message - the system sends this when a state is exited - Use OnExit to listen for it
case MSG_RESERVED_Update : // Don't send this message - the system sends this when a game tick goes by - Use OnUpdate to listen for it
case MSG_Timeout :
case MSG_ChangeState :
{
Debug_Logf("CSObject:: Receiving message - going to process state machine");
return ProcessStateMachine(m);
} break;
}
return false;
// we didnt want the message
return false;
}
void CSObject::SendObjectMessage(CSObjectMessage* m)
{
Debug_Logf("CSObject::SendObjectMessage(%d %d %d %d %f %f)",m->GetType(),m->GetType2(),m->GetSource(),m->GetDest(),m->GetRTime(),m->GetDTime());
GetFactory()->GetMessageManager()->AddMessage(m->GetType(),m->GetType2(),m->GetSource(),m->GetDest(),m->GetRTime(),m->GetDTime(),m->GetData());
}
void CSObject::SendObjectMessage(int type, int type2, int source,int dest, float rtime, float dtime, char* data)
{
Debug_Logf("CSObject::SendObjectMessage(%d %d %d %d %f %f)",type,type2,source,dest,rtime,dtime);
GetFactory()->GetMessageManager()->AddMessage(type,type2,source,dest,rtime,dtime,data);
}
Code: Select all
bool CSObject_FireGolem::ReceiveObjectMessage(CSObjectMessage* m)
{
Debug_Logf("CSObject::ReceiveMessage(%d %d %d %d %f %f)",m->GetType(),m->GetType2(),m->GetSource(),m->GetDest(),m->GetRTime(),m->GetDTime());
if (m == NULL)
{
Debug_Logf(" message is NULL!!!");
return false;
}
switch (m->GetType())
{
case MSG_DAMAGE :
{
// determine the type of damage
switch (m->GetType2())
{
case DAMAGE_FIRE : /* make the golem stronger */ ; break;
case DAMAGE_WATER : /* no impact to a fire golem */ ; break;
case DAMAGE_COLD : /* make the golem weaker */ ; break;
case DAMAGE_ACID : /* do normal damage */ ; break;
}
} break;
case MSG_COLLISION :
{
// do whatever collision code is done
} break;
case MSG_WHATEVER :
{
// do whatever collision code is done
} break;
}
return false;
// we didnt want the message
return false;
}
-
- Posts: 275
- Joined: Fri May 12, 2006 6:37 pm
- Location: Germany