Storing various game entities.

Started by
23 comments, last by Exomoto 14 years, 3 months ago
This is actually something I've thought about myself, and one approach is a custom categorising container. I'm a Java guy, so I don't know how you'd do it in C++, but basically you need objects implementing an interface that returns an enum that categorises them somehow, and a container containing an array of arraylists (or vectors, in C++), one for each value of the enum.

Then you just have the add method check the value of the enum and put it in the relevant arraylist, write a custom iterator to iterate over each arraylist sequentially, and access each arraylist's iterator to iterate over only a single category.

Basically, it does the organisation work for you with only a minimal expenditure of effort up front and it's no harder to call than using a standard arraylist/vector, all you lose is order-of-entry iteration over elements regardless of type (which probably isn't a benefit). It's only useful if you want to iterate over certain subsets of data regularly, though.
Advertisement
I'm thinking a good option would be to keep a list of all entities in a manager class, along with functionality to modify that list, use a factory pattern to add entities to the list, and give each created entity access to the manager class so they can handle their own collisions/deletion/etc during updates. In this case, would it be a good idea to store an iterator in each entity which can be used to erase/recycle that entity as needed?
Quote:Original post by Exomoto
How do you guys store/segregate your game entities?

The prototype I'm currently working on has multiple lists for things like enemies, inanimate objects, different bullet types, explosions, etc. This has served me well up until now, but having to constantly write template functions to run through a list (updates, collisions, recycling) and then make multiple calls to that function for lots of different lists seems a bit messy.

Is there a tidier way of doing this?


////////////////////////////////////

I use a component based system. All components are separated into ComponentData(const from the pov of the running game,mutable by editor/(de)serializer) and ComponentInst(mutable from the pov of the running game) counterparts. ComponentInst's const-ref ComponentData's (one to one). This separation of const and mutable data allows the game to run in the editor (important for iteration time). Since the running scene cannot change the const ComponentData's, you restart the scene in it's pristine state by destroying all EntityInst's and ComponentInst's and recreating them (compose and link).

My system breaks down like this:

////////////////////////////////////

SceneData (concrete class): editable/(de)serializable but const collection of archetypes, EntityData's and SceneComponentData's

SceneInst (concrete class): mutable collection and manager of EntityInst's, EntityComponentInst's and SceneComponentInst's. Maintains active component lists (per family). handles spawning/despawning. routes updates to individual components in a well defined manner.

SceneComponentData (abstract base class): editable/(de)serializable but const data of a SceneComponent. Examples include "BulletPhysicsWorldComponentData", "AudioManagerData", "LightingManagerData"

SceneComponentInst (abstract base class) : mutable instance portion of a SceneComponent. const-refs instance of paired SceneComponentData subclass. Examples include "BulletPhysicsWorldComponentInst", "AudioManagerInst", "LightingManagerInst"

Archetype (abstract base class) : editable/(de)serializable but const builder /blueprint for an entity. Also a collection of EntityComponentData's. Examples include "BasicModelArchetype", "SkyboxArchetype", "StaticLightArchetype", "CameraArchetype", "GlobalArchetype". Usually a predefined mix of component's, but user supplied component mixes are possible (but more complicated and infrequently needed).

EntityComponentData (abstract base class) : editable/(de)serializable but const data for a given entity component. examples include "BulletPhysicsObjectComponentData", "ShipControllableData", "ModelAnimatableData", "CameraControllableData", "AudibleComponentData", etc..

EntityComponentInst (abstract base class) : mutable instance for a given entity component. examples include "BulletPhysicsObjectComponentInst", "ShipControllableInst", "ModelAnimatableInst", "CameraControllableData", "AudibleComponentData", etc..

EntityData (concrete class) : Spawn Record for an entity - has TransformNode, Name, Archetype and misc entity initialization properties.

EntityInst (concrete class) : mutable instance for an entity - const-refs EntityData. container for EntityComponentInst's

The main difference between a scene component and an entity component in this system is that there will only ever be one of a given scene component. They tend to be used for scene-singleton objects. example: The "BulletPhysicsWorldComponentInst::Update()" method is where the call to bullet's physics tick update would actually be called (once per frame).

////////////////////////////////////

In my system, A requirement was the ability to be data driven (by the designer/artist), and be run within the editor for improved iteration time.

////////////////////////////////////

you can see more info (with pseudocode)here

mtm

[Edited by - tweakoz on December 31, 2009 8:51:53 AM]
I use an Aspect/Component-type system in my latest code. So only entities with Spatial aspects ( and thus a world bounding box ) get put in the hash grid for spatial queries.

Similarly, only entities with a Physics component get put into the physics system at all.

So with this system, there is some automatic filtering when querying for physics or spatial information, because only relevant objects are in the structures to begin with.

There is some waste WRT things like a localized audio object. Do I put the audio range bounding box in the spatial query, and make all entities nearby have to grab that and ignore it? Or do I put it into the physics system and mark it as a phantom object with no collision...

I think I will put it in the spatial query system, but add some flags to each entry, so the spatial query functions can filter out things that are not relevant to your search. You could have an audio flag, one for visuals ( to ignore invisible objects for instance ), etc.

Right now my Aspects are :

default( name )
spatial ( position, orientation, current & last bounding box )
physics ( mass, velocity, box2d info )
visual ( sprite info, visual extents - may differ from spatial extents )
controller ( for player control keys right now )
brain ( for scriptability and/or ai )
editable ( for editor selection info, in-progress property edits, drag info )
audio ( any sounds attached to this entity )
parent ( attached child entities )
child ( which parent am I bound to )
collision ( for non-physics things like triggers, and gameplay pick-ups )
subscribe ( any entities subscribing to my updates )
Thanks for the responses guys, it's appreciated.

When using a single entity list stored in an entity manager class, I want to give each individual entity access to that list so that it can remove/erase itself, search the list for objects colliding with itself, and so on. In this case, would it be best to make the list available to all entities, or give each entity a pointer to the manager class?

Also, slightly unrelated, but should vectors for things like velocity and acceleration for entities be kept private, with accessor/mutator functions being used to reach them from outside the class? Or is it fine to make them public? I don't think it's a huge deal but it would be handy to know if there's a standard approach.
Give entities a way to signal that they want to be removed, and directly hand them the information about whether anything is colliding with them. You don't want entities directly messing with their container.

Re your second question: The basic idea with OO and encapsulation is not to expose data, but actions that modify the data. You might expose vectors and stuff with accessors for read-only access, but who besides the entity itself has any business messing with those values at all? I might expose functions like ApplyForce(vector), which would change the velocity and stuff, but only the entity should be directly modifying those values.
Quote:Original post by theOcelot
Give entities a way to signal that they want to be removed, and directly hand them the information about whether anything is colliding with them. You don't want entities directly messing with their container.

Re your second question: The basic idea with OO and encapsulation is not to expose data, but actions that modify the data. You might expose vectors and stuff with accessors for read-only access, but who besides the entity itself has any business messing with those values at all? I might expose functions like ApplyForce(vector), which would change the velocity and stuff, but only the entity should be directly modifying those values.


So I take it this checking for collisions would be a generic function held in the container class/wrapper, which is called from the game state, and then used to call the appropriate function from the entity class if any collisions have occurred?
An adaptation of the way I do it now would be something like this:
struct Entity{    void Collide(const EntityCollisionInfo& info){        //info contains all the information I can use        //about what I just collided with    }};


Entity is entirely responsible for responding sensibly. The tricky part is sending all the information needed for a response in one package. It helps that my game is heavily data-driven, so its easy to send all the information in a single object without resorting to RTTI. In a game with an entity inheritance hierarchy, you might include a pointer to the original entity, perhaps a const pointer for good measure.

This function is called by the simulation code, that manages all the entities. I think that's what you mean by the "game state".
Thanks a lot for the help so far guys, it's been immense.

theOcelot: In the example in your last post, where would I add Sprites for things like explosions? The most obvious seems to be in the class of the object which was destroyed, but that would require giving the object access to the list of game objects.

Another way of doing it would be to make the object signal to the list it's contained in that it can be removed (a destroyed bool maybe), and create the appropriate explosion object during the cleanup loop. Would this be a good idea?
Quote:Original post by Exomoto
but having to constantly write template functions to run through a list (updates, collisions, recycling) and then make multiple calls to that function for lots of different lists seems a bit messy.


This is, pretty much, the simple way, and you'll get over the sense of apparent "messiness". The upside of keeping each entity type in its own list is that you never have to wonder about the exact type of an entity; it's implied by the container. The list-of-everything really only makes sense so long as you really only need the bit of interface that's common to every entity type. There's dynamic_cast, yes, but it gets even messier.

The basic rule is that inheritance and (classical) polymorphism are for forgetting type information (when it would only get in your way) and templates (used for compile-time polymorphism) are for remembering it (when you really need it). :)

This topic is closed to new replies.

Advertisement