Where to store container of all objects/actors/collision models/etc

Started by
14 comments, last by crancran 9 years, 8 months ago

I'm in the fairly early stages of coding a game, and I've come across this problem a few times now.

Essentially, I run into situations where some object needs to access a container of all other objects of the same type (or of some other type!). For example, a Collider object needs to be able to check if it has run into any other Collider objects. Or a Unit needs to get a list of nearby enemy Units to be able to pick a target.

My question is where to keep these containers?

  • Global? Globals are (almost) always bad in my experience, and I'm sure there's a better way than just having a global list of everything that anyone can access.
  • Static member variable? This lets objects of one type access all of the same type, but it doesn't cover cases where one type needs access to other types (for example a Pathfinding object needing access to Colliders, or an AI needing a list of all Units)
  • Manager classes? These would essentially be singletons then, and although I have very little experience with the SIngleton pattern I've heard nothing but bad things

I'm not sure of the best way forward. Every solution seems to have some serious holes and none of them seem particularly good.

Advertisement

Take this with a large grain of salt as I'm rather new myself (I'm certain someone will come along to correct me if I'm leading you wrong). But, to avoid these sorts of problems, I keep most of these objects in my main run-time class(or really, whichever class is going to need them. Just make sure you're organizing things correctly), which contains most of the functions and everything. So, my main class will have some objects of different classes, vectors of different class objects, etc. They can all interact with each other without any problem in any function in this class and I can pass anything I need into any class functions of other classes. For a more complicated program, you probably don't want all the objects being created at once, but in that case, just have them created in whatever sub-class they'll be necessary in and basically follow the same procedure. I'm simplifying things to some extent, but the basic premise remains the same.

I find that when I run into problems of circular dependencies, or classes needing things from other classes that they don't have easy access to, I've probably designed things wrong and need to look into organizing the classes and functions better. Often, I've made unnecessary classes, or haven't made some probably necessary ones. Often, I'm trying to do something within a class that should probably be a function outside of the class.

As far as your collider object needing to check against another collider object, this shouldn't be a problem as long as the function that checks that isn't called from inside your collider object class but wherever those objects are existing in scope. But, it should be easy to call a function that checks that from outside the collider class, say, wherever else you may want to check that, make a function there that passes in your collider objects to check. So, for simplicity, let's say your main class has a function:


bool Main::CollisionCheck()
{
if(//whatever conditions for collision are met)
    return true;
else
    return false;
}

You shouldn't run into any problems or dependency issues as long as the collider objects exist in this scope(sorry for the hobo-code, I'm not sure what language you're using, the original post sounds like c++ maybe, but something object oriented anyhow, so the methods should be slightly similar). If you don't want to do this in your main class, you can consider an object manager class, and then pass in the objects to check collision on, so a function like:


bool ObjectManager::CollisionCheck(ColliderObject &co1, ColliderObject &co2)//pass in references to the objects/vectors to check
{
if(//whatever conditions for collision are met)
    return true;
else
    return false;
}

So, in a nutshell, if your object needs to access another instance of the same class or even some other class, you should probably consider making that function elsewhere. Likely, wherever you created the instances of the object. So, instead of a "ColliderObject.CollisionCheck()" function, consider making a function in the class that you created the instances of the collider objects to begin with and calling the function there. This may be your main class, or perhaps some other manager class. But, if you try to have all those functions as part of your collider object class, you're likely going to run in to some circular dependency issues.

Perhaps this isn't the optimal way to do things, though, so I'm likely going to just watch this thread with you and see if better advice comes along tongue.png

Beginner here <- please take any opinions with grain of salt

Yeah, I'm using c++. I was hoping to be able to check for collisions inside of my collider object, since the collision check is part of the process of moving and I wanted to be able to do things like bouncing off of the other object or sliding along it, and in both cases I need to know how much movement I have left after colliding.

My goal was to be able to have a really simple "main" object/function that just does a simple call like actor.update() and then the Actor figures out where he should be using his own internal stuff (PhysicsModel, Collider, Pathfinder, etc.). I'm also trying to make my objects as generic as possible, more as a learning exercise than anything, so I can add and remove functionality more easily. So hypothetically if I wanted an object to not collide with other guys, I just don't give it a Collider, or give it a dummy collider that always returns false.

Outside of the location of my containers I've got it mostly figured out and working properly, and I could probably take any approach I listed and hack it together and make it work, but I'm mostly curious what some best practices are in this case.

Well, having the collision check as a requisite to moving can still occur. Just run the function in your other class where the instance of the object resides in, then pass in the bool as a parameter to your move function.

So, a simple version, In main, you create your objects, check for collision to generate a bool, then to move your object use a function like:


CollideObject::Move(bool collision)
{
if(collision != true)
    //move your object
else
    //don't move your object
}

passing in the collision bool as a parameter.

Or, still have an Actor.Update() function internal to your Actor Class, but pass in the other objects as parameters. This seems to be what you're trying to do. If you need a reference to other objects, you'll need to pass them in as references to the function. So, in this case, for your actor.update scenario. If you have a vector of tiles, let's say, and want to check them for collisions internally in the class, you'll want to make your Actor.Collision() function take in the vector as a parameter. So:


Actor::Collision(std::vector<Tiles> &tiles)
{
for(int i = 0; i < tiles.size(); i++)
    {
    if(tiles[i].pos.x < actor.pos.x)//or whatever. check for collision)
       actor.move();
    else
       actor.collide();
    }
}

This way you can reference the tiles, other players, whatever you need, as long as you pass in a reference to it. This method raises dependency issues though, that I don't quite feel qualified to dispense advice on. On the surface, you'd need to include headers for each type of class you may want to reference, though that's typically not recommended as I understand it(there are other methods), and you can end up with various dependency issues pretty quickly.

But, personally, I understand how you'd like that all to be internal to the class, but that feels like it's bloating the class unnecessarily. You're treating the object like an object manager. It would just be easier to make an object manager class(even though you said you didn't want something like that), and handle the things internally there. Have the objects created in the object manager class and run collision checks, gravity, movement, etc within that class. It doesn't have to be a singleton. You could still call everything in one function, but then the object doesn't have to reference other instances of itself or of other classes. You won't have to repeat the same code for every type of object (for, say like gravity. Each different class of objects you have, won't have to include the gravity functions within those classes as well). And then just call one function in main like ObjectManager.UpdateObjects(), and within UpdateObjects, run your movement,gravity, etc functions for your character, enemies, gravity, etc.. All the other advice I've given, just swap into your object manager class rather than main.

But, that way, your Actor class is simple and isolated and not entangled with other classes, other dependencies, other states, etc. You can still have an Actor.Update() function, but, if it's dependent on other classes or conditions, call the Actor.Update function higher up on the class hierarchy under those conditions and pass in whatever information you need, if that makes sense.

In other words. If you have two objects, and one needs to know about the state of the other. Run a check function on that outside of those classes, and depending on the outcome, alter your Actor.Update() parameters accordingly. You can think of it as a web of dependencies. But, the more you make each class dependent on another class the more complicated and messy it gets. I try to make it a cleaner hierarchy where the objects are as isolated as possible, and the managers of those objects are the only ones that interact with them. The objects themselves don't really interact with each other, per se. Well, they do, they just don't know it tongue.png

And, again, I'm rather new myself, so I'm really hoping someone comes in to either validate or correct me here before I rot your mind with poor advice tongue.png I'll exit the thread here, because you're asking for best practices, and I have no idea if what I've explained qualifies as that(I'm guessing probably not. If it is, it's incidental and just stumbled upon out of trial and error).

Beginner here <- please take any opinions with grain of salt

It's much easier to operate on your game objects from the outside then it is on the inside, because it lowers dependencies. If you try putting all of your object interactions into your object class, it's going to grow too large, break the single responsibility principle and become a giant spaghetti monster of dependencies.

If you want a simple and flexible way of doing it, put any and every meaningful logic operation into it's own free function (or a class if it requires some state from frame to frame). Ideally, the operations you do on the game objects are unit operations (like moving all objects by their velocity), are done to all objects in bulk ( void moveObjects(std::vector<Object*>& objs); ), and receives only the data it is interested in ( void moveObjects(std::vector<Vec2*>& velocities, std::vector<Vec2*>& positions); ). Add caching techniques where neccessary to avoid creating temporary vectors all the time tongue.png

When you start thinking that way, you'll see that game objects are just dumb containers of data, and the real meat are the operations that define the transformations of that data. Because that's what actually happens, every frame you just apply a transformation function on game object data.

As far as your collision example goes, you should first find all collisions between all objects, and for each collision save a manifest of that collision (the objects/bodies in question, penetration vector etc). Then, loop over all manifests and resolve collisions, noting that resolving one collision might introduce another, so the whole process is iterative. Look at some popular physics libraries (Box2D for 2d, Bullet for 3d) how they do it.

devstropo.blogspot.com - Random stuff about my gamedev hobby

Ok, that makes sense. How would you handle having objects that have very different properties in that case? For example, some objects might not collide with others (say a flying unit in an rts), or might move in different ways (or not at all)? If an object is just a dumb data container, does he have to keep track of all of that data in case it gets used? So my Actor class would still need to have a member for a collision box in case an Actor needs one, and would still need to have a velocity, acceleration, and mass in case an Actor needs to do Physics stuff. And then my processing logic in my main object also needs to know which operations to apply to which actors.

EDIT: After some thought, it shouldn't be too hard to keep track of which data is needed using different Actor subclasses, and then the main object can just dynamic_cast and check for NULL to figure out if it needs to be processed.

This seems to solve my problems in the simple cases but open up a whole bunch of different ones if I want to add any complex functionality. Maybe I'm not quite fulling grasping how an Actor should hold data and how the main class should process it.

EDIT: After some thought, it shouldn't be too hard to keep track of which data is needed using different Actor subclasses, and then the main object can just dynamic_cast and check for NULL to figure out if it needs to be processed.

This is for sure a solution, but it is flawed due to 2 reasons: 1st it works by inheritance (at least it sounds so to me), possibly leading to the god class issue. And 2nd it wastes performance by using a dynamic_cast.

Assume instead that your objects are build using composition (notice that this does not necessarily mean a CES). If it has a Placement and a Collider component then it is tagged to participate on collision detection. If the Placement is marked as static then it is, well, static. On object instantiation, the existence of those components causes the object to be installed in the collision sub-system. The sub-system can internally manage several sets of objects, e.g. one for static and one for dynamic colliders, so it is able to avoid unneeded checks e.g. between two static colliders.

The important part is this: Having sub-systems to deal with the aspects of interaction (see also Strewya's answer above), and attach components to the game objects to mark and parametrize them as candidates of selected sub-systems. So the sub-systems are able to deal with the respective aspects in an more or less optimal manner, especially by a-priori restriction to meaningful subsets of objects and the use of suitable structures.

  • Manager classes? These would essentially be singletons then, and although I have very little experience with the SIngleton pattern I've heard nothing but bad things

Just to touch on this, Singletons aren't bad simply misused/overused. People often discover design patterns read about the Singleton pattern and then decide all classes where it makes sense to have only one instance during the application lifetime should be a Singleton, when the rather plain solution is to simply only make one.

EDIT: After some thought, it shouldn't be too hard to keep track of which data is needed using different Actor subclasses, and then the main object can just dynamic_cast and check for NULL to figure out if it needs to be processed.

This is for sure a solution, but it is flawed due to 2 reasons: 1st it works by inheritance (at least it sounds so to me), possibly leading to the god class issue. And 2nd it wastes performance by using a dynamic_cast.

Assume instead that your objects are build using composition (notice that this does not necessarily mean a CES). If it has a Placement and a Collider component then it is tagged to participate on collision detection. If the Placement is marked as static then it is, well, static. On object instantiation, the existence of those components causes the object to be installed in the collision sub-system. The sub-system can internally manage several sets of objects, e.g. one for static and one for dynamic colliders, so it is able to avoid unneeded checks e.g. between two static colliders.

The important part is this: Having sub-systems to deal with the aspects of interaction (see also Strewya's answer above), and attach components to the game objects to mark and parametrize them as candidates of selected sub-systems. So the sub-systems are able to deal with the respective aspects in an more or less optimal manner, especially by a-priori restriction to meaningful subsets of objects and the use of suitable structures.

So when you say I should build my objects using composition, wouldn't I end up having a fairly bulky Actor class that holds a bunch of data that's only sometimes useful? For example:


class Actor
{
...
private:
    Placement* _placement;
    Collider* _collider;
    PhysicsModel* _physics;
    ...
}

with a bunch of these objects that are only used by some actors? Wouldn't it be preferable to use inheritance to have, for example, a StaticActor that only has a Placement and a Collider, and DynamicActor that also has a PhysicsModel, etc. Unless it's better to just have a base class with a large amount of data, and just check if any of those are NULL when determining what to do with it.

  • Manager classes? These would essentially be singletons then, and although I have very little experience with the SIngleton pattern I've heard nothing but bad things

Just to touch on this, Singletons aren't bad simply misused/overused. People often discover design patterns read about the Singleton pattern and then decide all classes where it makes sense to have only one instance during the application lifetime should be a Singleton, when the rather plain solution is to simply only make one.

Ok, that's what I thought. I see it in code all the time, but whenever I try to research it I just get a million results saying "singleton bad." It does seem to be the best solution here.

So when you say I should build my objects using composition, wouldn't I end up having a fairly bulky Actor class that holds a bunch of data that's only sometimes useful? For example:


class Actor
{
...
private:
    Placement* _placement;
    Collider* _collider;
    PhysicsModel* _physics;
    ...
}
with a bunch of these objects that are only used by some actors? Wouldn't it be preferable to use inheritance to have, for example, a StaticActor that only has a Placement and a Collider, and DynamicActor that also has a PhysicsModel, etc. Unless it's better to just have a base class with a large amount of data, and just check if any of those are NULL when determining what to do with it.

There are a lot of ways to do this without needing inheritance at all. One is to stop thinking all objects in your world are an instance of the same class. They're not. A missile is completely different from a tree. Terrain is different from a tree. Items are different from NPCs.

Move away from having an Actor class that contains everything in the entire game and can be morphed into anything. Instead, have multiple types of objects each composing only the data it needs, store it in an ObjectPool of its own, and when it is created, register its data parts to the systems that are in charge of applying transformations to that data or just need to read from the data.

A different way is to not have classes an all, but pools of data that are indexed by an id which, for all intents and purposes, acts as an object, it's just that its parts are spread all over the place (well, in pools which you get to decide where they are).

devstropo.blogspot.com - Random stuff about my gamedev hobby

This topic is closed to new replies.

Advertisement