How to manage game actors vs scene graph

Started by
4 comments, last by Hodgman 10 years, 5 months ago

Hi all,

I've just started implementing a component-based game actor class, but was wondering how best to keep track of my game actors in my gamestate.

For rendering, I already have a SceneGraph with a quadtree that chops my terrain into chunks, as well as stores "meshInstanceNodes" in its leaf nodes. I would basically like to have something similar for my game actors, however I'd like to keep the rendering quadtree encapsulated for purely rendering.

Should I make another quadtree to store my game actors in the current gameState? Or is it also acceptable to store gameactors as a Node in the sceneGraph (even though the sceneGraph was created for rendering things only)? What is generally speaking a good practise for storing game actors as opposed to their sceneGraph rendering representatives?

Thanks!

Advertisement

The sense of components is (besides other) that different things are separated. E.g. a Placement defines a position and orientation in the world, a Renderable (or whatever) defines the mesh and texture mapping suitable at rendering time, a RestPose defines a mesh in, well, its rest pose, a Skeleton defines the current pose, a Collider defines how collision is to be checked, etc.

W.r.t. the separation above, for what purpose do you need the 2nd quadtree to store game actors in? Think task oriented. Let's assume to speed up collision / proximity detection. So what you need is a sub-system that knows about the Placement and the Collider for not only this but all entities that may collide. Its internal storage structure may be a quadtree, yes. If, on the other hand, you are asking for a structure to remind of all the entities in the world ... then a quadtree isn't suitable, because a quadtree is a space partitioning scheme while an entity in the world is there regardless of any quadrant or so.

Just my 2 €-Cent.

Don't put them in the rendering scene graph. A "meshInstanceNodes" is now a component that can be owned by an Actor (but is allocated in your renderer's tree).

I assume that the renderer quad-tree solves the frustrum culling problem for the renderer -- what problem does the actor-quad-tree solve? Don't create structure without first knowing what it's a solution to wink.png

The scenegraph quadtree is indeed there for frustum culling.
I was, I guess, just thinking general purpose here. What if I add new components in the future, that will need to have an efficient partitioning?

For example, say I add a physics component with a collision mesh. How/where would I spatially partition these physics components? Would I create a new quadtree purely for the physics components, would I add these physics components to the (rendering) sceneGraph, or would it not be more efficient to just have a quadtree for the game actors in its entirety, should some other component in the future also need a spatial partitioning (can't think of another example than physics at the moment though)?

Also, if I'm understanding this correctly, there's no real need to store game actors through a special spatial partitioning, rather a simple std::map<ID, GameActor*> would suffice?

Cheers

See, the traditional scene graph was a beast for many different purposes. Nowadays the recommendation in general is to use as many distinct (and decoupled, if possible) structures as needed, where the particular structure should be task oriented instead of being made matching a omni-potent scene graph. There're many ways to go, of course. The following is just one:

IMHO frustum culling is a task similar to zone containment, collision detection, proximity calculations, and similar things. They all compute the spatial distance of a more or less simple volume against a couple of other simple volumes. Think of a SpatialServices sub-system that allows to send appropriate queries to it. When, for example, rendering is about to be invoked, compute the frustum volume from the current camera set-up and query the SpatialServices for the "list of all object IDs that collide with the given volume". Notice that although frustum culling as a task is still existent as usual, its main work is externalized to a more general sub-system, and the sub-system is not aware of what frustum culling is.

Of course, it may happen that unforeseen requirements occur in a later development phase. Either the then existing services are suitable to fulfill them, or else you need to either extend / re-factor them or create new services. If a second (i.e. different) partitioning scheme is required, then ... so it is.


Also, if I'm understanding this correctly, there's no real need to store game actors through a special spatial partitioning, rather a simple std::map<ID, GameActor*> would suffice?

You need a kind of database where all existing game actors (or more general, entities) are stored in. A map would be sufficient for this, that's correct (letting aside any eventual performance issues). This structure allows you to retrieve an entity by its ID, and it can be iterated to touch all entities. That is its point. It doesn't mean that the entity cannot be found in a spatial partitioning, too. But it should be stored there as a bounding volume with an ID, and not as a game actor or some other high level thing.

It's common to implement physics using an existing library, like Bullet or PhysX. In that case, you don't have a choice; the library will create its own acceleration structures internally to speed up collision detection, and this is largely transparent to you the user. The user of the library just has pointers to physics objects, without having to know/care how they're allocated/accelerated.

This topic is closed to new replies.

Advertisement