Managing objects in different game states

Started by
6 comments, last by Khatharr 10 years, 9 months ago

Hey guys.

So I was wondering how should entities or objects be handled in different states of the game. I have an obvious Object_Manager class but

it is not a god class. It only contains a list of all the objects that are needed in the current situation and an interface for adding, updating and removing objects.

But so far, because I only worked on very small projects (I won't even call them games) I never worried about main menus or more than one

level to be honest. Now that I have different states I have no idea what the best practice is regarding the handling of these entities.

There are two solutions that I can think of. The one is to have only one instance of Object_Manager and then just remove and add entities as the states switch. OR Each state has a instance of Object_Manager and then the state itself worries about the cleanup.

I have no idea if I am even heading in the right direction here so any help would be appreciated. Also just a little off-topic question here:

Should entities that are "dead" be removed from the list in Object_Manager or should entities have a variable containing an "alive" variable and the updating just gets skipped if the object is not alive.

Thank you.

PS: Just to clarify my "states" are classes on their own. So it's MainMenu, Intro, Level etc...

Advertisement

I think it is simpler to have a single ObjectManager class that manages all objects, and every state adds it's objects to that manager.

Each state should be, however, responsible for adding it's objects to the manager when it is created, and removing then when it is destroyed. In other words the global ObjectManager doesn't have to keep checking which objects are no longer needed.

L. Spiro has a very good article about managing game state (among other things), if you're interested: http://lspiroengine.com/?p=351

About your off-topic question:

If, when you say the entity is "dead", you're referring to something like, an enemy entity was just killed and has no purpose left in the game, then i'd say removing it from the ObjectManager is a good option, simply because it's one less update call the ObjectManager must make.

However, if the ObjectManager has to check for a variable to know if the object needs to be updated, then, on top of doing the same thing the above option does (issuing update calls), it will still have to execute a branching instruction for every entity (including the ones that are not updated), so it would be slower.

Note that this, however, probably won't even be noticed, with the speed of processors nowadays.

Hope it helps, and sorry if i misunderstood the question(s).


I think it is simpler to have a single ObjectManager class that manages all objects, and every state adds it's objects to that manager.

Each state should be, however, responsible for adding it's objects to the manager when it is created, and removing then when it is destroyed. In other words the global ObjectManager doesn't have to keep checking which objects are no longer needed.

I actually think the opposite would be true. Especially since your projects are growing nlmore complex. If your design only has one instance of the class, and every state needs access to it, then there will be a tendency to write the class under the assumption that there will never be multiple instances, and to make your instance global, and possibly even to enforce that using the singleton (anti-)pattern.

My recommendation is don't do it. There are lots of discussions on this forum debating whether or not singletons should ever be used, and the morality of global. Intelligent people can be found in each camp. But from my personal experience, my code became cleaner and easier to follow when I stopped using singletons and global. And the forum members whose opinions i respect most, and who definitely know more about coding than i do, tend to share my viewpoint.

If all states share a global object manager, then either the state will have to do some management on its own, or the object manager will have to become needlessly complex. Sure, if each state has its own object manager you'll have more instances to deal with, but both the manager class and the state class will both be simpler, which means easier to follow and less prone to bugs.

So, yeah, do what you want. Or if this is for experience and self education, fork your project and try it both ways. I firmly believe that not having a global object manager would prove to be the better solution.

In the spirit of "there's no single 'right way' to do things", I'll say the following:

-How similar are your states?

It seems unlikely to me that the start menu state, intro state, and level state have enough in common for them to use the same ObjectManager without the ObjectManager class becoming overly generalized. Obviously you know your code design better than I do, but a single ObjectManager for such different contexts sounds less than ideal to me.

-What types of objects exist in each state?

Similar to the above, deciding how to handle objects in each state will help you figure out the pros and cons of a given design approach. A start menu state may be simple, just keeping track of a GUI-style menu, while a level state would probably have more complicated needs.

-What sorts of behaviors do your objects have in each state?

In my own code, I try as much as possible to avoid having classes act upon each other, especially for game objects. What would your ObjectManager class do to the objects it's managing, and would those operations be better organized as behaviors of the objects being tracked?

-What happens to objects not in the current state?

I assume that some things need to persist between states. If the player pulls up a menu, that may prompt a state change, but all of the level-state objects would still be stored somehow so that they can be restored when the player is done with the menu.

Relatedly, do objects not in the current state ever need updating in this game?


These are some questions that might help you nail down what exactly you need, and that will help you weigh between approaches much more than trying to judge abstract ideas for canonical "rightness".

in general I suggest avoiding globals unless you can explain why you need one. In this case I think you probably don't need one. I also suggest avoiding overly general classes, and from the information provided I think your ObjectManager may be such a class. Manager classes seem prone to both globality and generality, so if you want to use one we should favor getting as much information on your intended implementation as possible.

-------R.I.P.-------

Selective Quote

~Too Late - Too Soon~

Thank you for the replies guys. I think what I like most about programming is the fact that there are so many solutions to the same problem. And I don't think I've named my Object Manager class correctly.. It's basically just a protected list with an interface for adding, removing and requesting entities. The "big picture architecture" is still quite new to me if you can call it that, so I might be approaching this the wrong way.


In my own code, I try as much as possible to avoid having classes act upon each other, especially for game objects. What would your ObjectManager class do to the objects it's managing, and would those operations be better organized as behaviors of the objects being tracked?

The fact that your entities don't act upon each other has just ruined everything I thought I knew regarding the game logic... I thought that in the update() of the player I could do something like this (this is purely pseudo, I am actually trying to make pong...):

if self.collidesWith(Game::curState.ObjectManager.find("apple")) {player.increaseHP}

This happens all the time.. I think I finally manage to do something right then I realize that it's all wrong. My idea was to make the Game class a singleton because there can only be one game.. and somehow the entities must know about each other, so the entities can just include the Game header... Then I thought the Game class would hold a reference to the current state the game is in. And the state

has an objectManager that holds all the objects in the current state.

The fact that your entities don't act upon each other has just ruined everything I thought I knew regarding the game logic... I thought that in the update() of the player I could do something like this (this is purely pseudo, I am actually trying to make pong...):

Before I go on I want to reiterate: just because one person does something one particular way shouldn't undo some foundational ideas you've got, and it definitely shouldn't make you switch from an approach you like. If an approach you're using works for you, go for it. In the case of object managers I personally found that the more I used them the more problems I had, so I scaled them back.

To clarify, what I try to avoid most of all is having classes impose effects on each other indirectly. I don't like having an overclass, like a manager, involved in the action-- at most, what I use in place of managers are little more than lists. It sounds like that's your approach too. In such a case, it would be complicated an unwieldy to have a single Manager object to handle objects for both a menu and a gameplay state. I think that this is a strong argument against the Manager being a global class intended for use by any and all states.

In your pseudocode example:

if self.collidesWith(Game::curState.ObjectManager.find("apple")) {player.increaseHP}

my preference would be to define the effect of Apple objects inside of the Apple class itself and then handle a collision when it takes place, instead of a big if-else chain in an Update() function which would require the game to check for every possible game event each update cycle. I would define a function in the Player class to serve as an interface for interacting with Apple or Apple-esque objects. So when a collision takes place you might have something like player.CollidesWith([instance of Apple class]). Then the player object would handle the Apple-collision, with something like this.IncreaseHP([instance of Apple class]), where the IncreaseHP function accepts the Apple object as an argument to determine how much of an HP increase the player will get. It's really the same as what you wrote above, except that it doesn't query the ObjectManager.

Involving an object manager class in the interaction doesn't seem necessary to me, and using one (to my mind) makes the intended interactions between Player and Apple less clear while encouraging a less flexible interface through which Player objects interact with other objects. This (again, for me) makes the code less intuitive and therefore harder for me to work with. The object manager style classes, in my projects, exist more or less so that I can iterate through all of the objects in a scene to update them. They don't reach into the objects they manage for any purpose, and those objects usually only reach back to the manager to remove themselves when appropriate.

This happens all the time.. I think I finally manage to do something right then I realize that it's all wrong. My idea was to make the Game class a singleton because there can only be one game.. and somehow the entities must know about each other, so the entities can just include the Game header... Then I thought the Game class would hold a reference to the current state the game is in. And the state
has an objectManager that holds all the objects in the current state.

There's not a "right" way to do things, in the sense this quote suggests. You're not wrong, and all of this seems standard enough. For Pong, a singleton-style Game class should be fine, and it's very common for the game's current state to be stored as a reference in another class (including Game, if that fits your design). And a state can definitely have an object manager if that's what you decide to do. The biggest question that you should ask yourself when deciding on an approach to use is: does this approach do what I need? If so, it's not going to be "wrong". It might be less than ideal from a maintainablity standpoint, a programming theory standpoint, a performance standpoint, or any number of other considerations.

Ultimately though these considerations are secondary to the "does it work?" criterion. If it works, it's "right" enough. All the rest is asking a question like "could it work better?".

-------R.I.P.-------

Selective Quote

~Too Late - Too Soon~


My idea was to make the Game class a singleton because there can only be one game..

You only need a singleton if you truly need global access to the instance, which you shouldn't. Just create one instance in your main() and pass a reference to classes that need it. Which shouldn't be that many.

You may want to consider using your game states as distinct interfaces to an underlying model of your simulated world. In the case of data that needs to be persistent throughout, you can have a class at the game level which contains that data set. For sets of data that are only expressed through a single state, but need to persist if you switch away from that state temporarily, you can have a dual-class state, where one class holds the data and the other class interacts with it. For instance, in a JRPG, your overarching game state can hold things like your party member objects, the amount of gold you have, etc. Meanwhile, the 'map' data state will hold the objects required for the map, where the actual 'map' game state will be responsible for rendering everything, playing the audio and reacting to player input.

It sounds like this is the model that you're approaching. I've seen it used to good effect in the past.

Don't use singletons or the skeleton man will eat you.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement