Handling objects states properly.

Hello friends,

I’m having troubles with proper management of objects states.

Check out the following:

class PlayerController {
bool canMove = true;
bool canRotate = true;
bool canShoot = true;
bool canCastAbility = true;
}

class PlayerCamera {
bool canLookAround = true;
bool followPlayer = true;
}

class PlayerAbility {
when used over time - PlayerCamera.canLookAround = false;
}

class PauseScreen {
when game is paused - PlayerCamera.canLookAround != PlayerCamera.canLookAround;
}

You might already see what’s the problem here - When we are NOT using our ability and we want to pause the game, “canLookAround” will be properly set to false. Although when we are using our ability and at the same time we want to pause the game, “canLookAround” will be set to true - which is incorrect.

I believe I dont have to add that this way of managing states looks terrible and it’s super easy to get lost around all of these “canDoSomething” booleans. Not only Player have that kind of booleans, a lot of scripts inside the project are affected by this kind of poor states management and it’s causing a lot of frustration and this feeling of being lost.

After all you end up with some kind of abomination like this:

void PauseGame(){
enemy.canMove = false;
enemy.canShoot = false;
player.canMove = false;
player.canShoot = false;
player.canCastAbility = false;
NPCs.canMove = false;
etc…
}

Apart of having enumerator holding current state, what would be a proper way of handling states like these ?

Is there any design pattern that handles this problem well? Is there any principle that has to be followed on the architecture level of the project in order to handle states easily?

Please share your experiences with me, thank you.

Please see the first forum post for code formatting help.

One very popular way to handle states is a state machine. There is a lot that one can say about those, which is why I leave the research to you. There is simply so much to say about them that it would be easier to write a whole tutorial rather than trying to squeeze it into this post.

A good overview and entry point could be State Diagram (Wikipedia). Keywords and articles mentioned there, like Moore machine and Mealy machine, go more into detail. Programming them yourself might be a tad challenging at first, but once you get the hang of them, they are incredibly handy, as you can easily determinate which actions are allowed and which not, based on a global state machine.

Think of a game, for example, players taking turns, each turn has a Start Phase, a Battle Phase and a End Phase. These are your game states. Now think about playing a card or something, which is something that should only be allowed in Battle Phase. How do you check if a player is currently in Battle Phase? You have a global state machine that returns whose turn it is and in which phase they are. If the player tries to play a card, you only have to check in the global state machine if the player of the current turn is equal the card-playing player and if they are in the Battle Phase.

Maybe you already understand how powerful this is. Instead of having to explicitely keeping track of all flags, like you do for your player controller, you can implicitely check for the player state. Is the player casting an ability? If yes, he cannot look around. Something like that.

For the player state itself, you could introduce an enumeration, something like this:

public enum PlayerState {
    Moving,
    Shooting,
    Casting
}

Then, you introduce a field for this state in your player controller and set it accordingly to the player actions. If the player is moving, you set the state to moving, if they are shooting, you set it to shooting and so on. When you know try to do something, like casting an ability, you can check if the state allows that action. If the state is moving, he may cast an ability, but not if he is shooting, something like that.

It gets very complicated once you have multiple states being allowed at the same time, like moving and rotating at the same time. Then, you need to get a bit more tricky and introduce states with transitions between them. Check the Mealy and Moore machines mentioned earlier. In this case, a Mealy machine, because you have an action and a state.

I highly recommend taking a look on State - Design Patterns Revisited - Game Programming Patterns. There are also some decent examples.

1 Like