entity manager

Started by
8 comments, last by iliak 19 years, 6 months ago
I'm programming an RTS, and I want my entities to be able to communicate through a third part, an entity manager. This seems to require giving every entity a unique id number. How is this normally done in an RTS?
Advertisement
Yes, you could do it like that. One of the Game Programming Gems books features a similar method in which there's a global Entity Manager and each entity has a message handler. The entity manager will route messages to each entity and the handlers will handle the message by acting on it or letting it cascade down the entity chain until there's none left. Seems like an entirely reasonable method to me.
Should ID numbers be recycled? If an object has been dead for a long time maybe you could give it's number to a new object. You could use an unsigned short for the number and then you could have more than 65535 entities over the lifetime of the game. It's not likely you would need that, but if you ever did it would be nice if the program didn't choke on it.
Quote:Original post by EvilProgrammer
Should ID numbers be recycled? If an object has been dead for a long time maybe you could give it's number to a new object. You could use an unsigned short for the number and then you could have more than 65535 entities over the lifetime of the game. It's not likely you would need that, but if you ever did it would be nice if the program didn't choke on it.


Yes, definately recycle. Use a static array of Entity pointers. This allows a much faster retrieval of entities by ID.

Entity* getEntityByID(unsigned int ID){  if (ID < MAX_ENTITIES)    return entities[ID];  return NULL;}


If you start to remove entities your array will start to have gaps. That would slow down adding new entities because you'd need to search for an empty spot.
One option of speeding this up is keeping a linked list of empty spots and fetch the first in the list and pop the first off.

int addEntity(Entity* e){  int newID;  std::list<Entity*>::iterator it = availableIDs.begin();  newID = (*it);  availableIDs.pop_first();  return newID;}


void removeEntity(int ID){  if (ID < MAX_ENTITIES)  {    entities[ID] = NULL;    availableIDs.push_back(ID);  }}


That's how I'd do it... in fact... that's how I do it in my resource manager. Except for the listing of available ID's which is something I still need to implement/test.
STOP THE PLANET!! I WANT TO GET OFF!!
Ah that's good thanks! I thought of another idea. In some games, it says "cannot create more units" sometimes when you put a lot of stuff on the map, I guess that's when they hit max entities. In StarCraft this was particularly annoying because any unit that fired missiles for it's attack could no longer attack. So what about having a separate section reserved for missiles?
If you use a high enough number for MAX_ENTITIES it shouldn't matter (but why not be safe :). To keep it really safe you should maintain seperate sections for each side so that creating a ridiculous number of units to prevent the enemy from producing any more is not a valid tactic (although you're probably doing this already...).
A nice little trick to remember is this: A pointer to any object is a unique identifier. You can't have two entity objects allocated at the same address obviously, so use the pointer to the object as the means of identifying the object. In essence, just pass around the pointer. That way, you don't have to worry about allocating an ID, and you don't have to do a lookup to retrieve the pointer.
Well, the idea is entities are dying all the time. So in order to make sure that one entity doesn't have a pointer to an entity that no longer exists, I have them communicate to a third party that knows which pointers are valid. So instead of each entity actually having a pointer to whatever entity it's trying to communicate with, it has this id number.
yes, but you can have the ID number as the pointer. The entity manager can do a lookup on the pointer to see if it's actually valid.

But it's not a good idea if you are networking.

I personnaly prefer an ID based on indices (if you have a fixed maximum allocations of a particualr type of entites) or a global counter, coupled with other information, like the class ID of the object, and if it's a game-created object or an object created from an editor, and stuff like that.

The entity-allocator could be a bit of a pain, but not too hard if you have something similar to a simple memory manager, which maintains a list of free blocks (and consecuently, free guids).

Everything is better with Metal.

DON'T use pointer !!! Use ID instead, because if you are using a network mode you'll just need to send ID of entities, if you use pointers you'll be stucked. It's easier to say "unit 32 is moving to <10,23>" thant "unit at 0x157842 is moving to <10,23>".
- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]

This topic is closed to new replies.

Advertisement