I’ve been struggling with Game States for a few months between different projects and thought of asking here. I seem to always overcomplicate this, but at the same time if I try doing it in a simple way I feel like I won’t have much control and it get messy very soon.
How do you deal with it? I know it’s a very broad question, so I’ll try to explain my difficulties and what I tried.
Sometimes, specially during game jams, I use enums for each State in a GameManager script and it gets the job done. I write a ChangeState method, which receives newState as a parameter, calls an ExitState method, updates the currentState variable to the newState, then calls an EnterState method. ExitState and EnterState both have a switch(currentState) and a case for each GameState with the code I want to execute. The problem I have with this is that for a larger game (not big, but larger than a game jam one) it will become a mess to have a switch case for each state, specially since I keep trying to make EVERYTHING a state and will probably add more as the development progresses - SplashScreen, LoadingMenu, MainMenu, OptionsMenu, ConfirmQuitGame, LoadingMatch, MatchSetup, Match, EndMatch, GameOver, Results, and so on…
I tried applying what I learned from the PluggableAI tutorial, but instead of using the States for AI, I used for the Game States. So, each State was a ScriptableObject and they each had their own actions (like LoadLevelGeometry, SpawnPlayers, FadeOut, …) that I could rearrange. THe problems I had with this were mainly due to programming inexperience - it was extremely hard for me to give the actions the parameters and references they needed to work with and also some actions needed to happen over time or wait for them to be finished before going to the next action, which I couldn’t do with the ScriptableObjects.
Now, I’m trying to make a GameManager GO with a GameManager script that has references to individual scripts that inherit from GameStateBase. There will be a script for each GameState and all of them will be components in the GameManager GO. GameStateBase has EnterState, ExitState and ExecuteState methods. GameManager will have a currentState variable with refeference one of the GameState scripts and will call the methods inside them, overridden from the GameStateBase. My problem with this is - where do I write the “actions”, the steps that each state needs to go through, their routines? In the GameManager class and the GameStates will call them? Or inside each state, which can be a problem, because the same step might need to happen in different states?
I’d like to know if someone can point me to a better way, suggest someting to improve what I tried or explain a different way that was used for a finished project, please. Every time I try to start a game, I get stuck trying to make a better, I don’t know, architecture (?).
I can show codes of my approaches if it is of any help! Thanks!
For my current project the main state machine in a scene is only responsible for enabling/disabling managers for each state. From there the manager either has its own state machine or something far simpler that handles just that state.
Personally, my game state controllers are never responsible for invoking logic outside of changing states. Basically they’re just a Dictionary<State, List> where the values are the allowed transitions for a given key.
When the state is changed, the state controller emits events and the other objects just handle whatever they’re responsible for handling accordingly.
So, you have a manager for each state that are activated/deactivated by a main state machine. What do you do with code that might happen in more than one state, like fading between scenes? Would you mind giving some examples of some of the states your games usually have? As I said in the thread, I tend to create A LOT of states for every little thing, which might not be so useful, so it’d helpful to see how deep the rabbit hole goes for others.
Yeah, I can understand it! I got used to switch, even though I dislike having to write “break” between each case. It would be better if the compiler understood that when a new case starts, the previous case ends. (I might be using the wrong words because I’m not exaclty a programmer, I’m just trying to make a game :P)
Hey, AntoineDesbiens, thanks for explaining me your method! I never used Dictionary for states (in truth, I’m fairly new to them). Could you please elaborate more on how you make a Game State Controller with it and what exactly are those transitions? If I understood you correctly, each state knows to which states it can change to and when?
I can’t seem to figure how to do it that way. My GameManager is usually a Singleton and when something happens outside that should change the GameState (like clicking the “Start Game” button on the main menu or when the “EnemyManager” identifies that the player killed every enemy), it calls the ChangeState() method in GameManager.
Also, I’ve tried using events to run each state routine, but I couldn’t sequence things correctly, specially when i needed to wait before going to the next step - like waiting for the fade to complete or the camera to finish zooming in, for example. With this, i mean that GameManager triggered every event needed for each state, which sounds wrong now typing it. In your approach, the GameManager triggers some event like “StartMatchState”, “StartMainMenuState” and each respective controller listens for it and runs its own routines?
Sorry for so many questions, it’s just that I’m starting to make my first game as a product after a few years making experiments, prototypes and jam games and I’m a little tired of knocking my head with this. I’ve read game programming patterns books, watched many youtube videos, but couldn’t find anything that I, in a below intermediate level, could understand fully and apply that gives me control and flexibility.
Our game is a multiplayer game and we have a gamemode base class. Each game mode subclass is just a scriptable object with some special methods and behaviors on it. THis class handles everything from spawning players to game flow. Most basic game modes dont have that much flow. Like team deathmath, it dosnt mutate during its life. If they have flow its handleded by modules rather than from one god object. For example on search & destroy. The C4 system handles its state itself. AI is an entire behavior tree using its own system, etc, etc
I think your concept of “game state” is far too fine grained, which is making this a fiddlier problem than it needs to be. In fact, rather than game states it sounds to me like you’re just listing screens. Do splash, loading menu, menu, options menu and your quit dialog all really need their own state tracking? To me that’s all just the main menu, which has a few screens it can display.
My game states are things like Playing, Paused, Upgrading, Loading. Each of those might have a bunch of internal states that they can be in, but not all of that stuff has to be handled by one monolothic state manager. Furthermore, it’s far easier to manage if each state manages its own relevant substates.
My current project doesn’t even have a state manager. Everything is just handled by events being emitted. Anything that cares about the game being paused or not just listens for that event… and so on for everything. I thought it was going to be a mess and a pain because I’m used to that kind of thing being rigidly and centrally controlled, but I experimented with it on a small project and everything just worked, and so far that has borne out on a much larger project, too.
So, the game mode subclasses run their specific code at the beggining of the match and then each module has its own behavior and states. Sounds very simple and easy to add/edit/remove modes, which is awesome for a multiplayer game!
Thanks for your input! Like angrypenguin said, I might be complicating things in my mind, so it’s great for me to know about different (and better) approaches.
What you said about having less and broader states and each one having substates might be exactly what I need. Since this will be my biggest project yet, I keep trying to break things in smaller parts, which sounds great on paper, but since I’m not very experienced it’s only making it harder to work it through my mind.
To give it some context, here’s my game’s gameplay loop: there is a farming phase, a writing phase and a defense phase.
They’re not complex, so the farming isn’t like Stardew Valley or something like that. During this phase, you control your character with point and click controls through a farm “two screens wide” with fixed structures. You have action points (the only resource) to spend on the farm structures.
The writing phase will be about selecting pre-written texts to build a diary for the character. The options will be selected randomly based on the actions you performed during the farm phase, among other sources.
The defense phase will kind of like a card game, but without turns - the player sees the available cards that the enemy has, but doesn’t know which one he’s gonna choose and needs to select cards that give the best defense against the enemy ones. Then, it plays automatically - the enemy advances through the player cards and tries to overcome it.
Following your suggestion, I think I can have one state for each phase and inside these states I can have substates. And maybe try to reduce the amount of states for menu and other stuff outside the game. You also said in your answer below that you only use events, I’d like to know more about that, if possible. I’m not sure if I should use this thread or DM or e-mail you, if you don’t mind, of course!
My project is several years old at this point. I am running a StateManager that I modelled after a book I read. The StateManager is attached to a game object that is set to don’t destroy on load. Each state is just a script. The state manager calls the appropriate part of the state with code such as:
void Update()
{
if (activeState != null)
activeState.StateUpdate();
}
And state can be switched with:
public void SwitchState(IStateBase newState)
{
var oldState = activeState;
activeState = newState;
oldState.OnDisable();
}
Check out the documentation for UnityEvent and look up event based programming in general. I’ve also written about it here a few times before, so searching the forums for my username + UnityEvent might get what you’re after.
But… walk before you run. The manager based approach can get great results and is much more approachable to begin with.
I don’t know if it’s a better way, but I use coroutines as states, e.g. here’s the state machine for a bowling game in my Unity book (scroll down to the Start function, all the states are implemented after it).
I use coroutines as micro state machines all the time. Though I dont see the need for a state variable like you have when you are dealing with coroutines. I let the routine itself be the state handler.
I have created some helper methods though, for example, you can execute a sequene of routines like
And then from within a routine you can restart it etc
private IEnumerator WaitForAttachmentHoveringOverRail()
{
var firearm = Get<Firearm>();
railSystem = firearm.GetComponent<RailSystemContainer>().RailSystems[RailIndex];
attachment = topItem.GetComponent<RailSystemAttachment>();
ShowPopup(railSystem.transform, "Hover over the rail with the attachment.");
while (attachment.AttachedSystem != railSystem)
{
if (attachment.IsCompletelyAttached)
{
yield return Execute<DetachAttachmentStep>(step => { step.Attachment = attachment; step.CorrectAttachmentPlacement = true; });
yield return SequenceState.RestartCurrent;
}
else
yield return null;
}
}
private IEnumerator WaitForPlacementOnRail()
{
ShowPopup(railSystem.transform, "Slide the attachment over the rail until you find a good position and let go.");
while (!attachment.IsCompletelyAttached)
{
if (attachment.AttachedSystem != railSystem)
yield return SequenceState.Previous;
else
yield return null;
}
}
Generally: don’t over-engineer. If this is your first time dealing with game states, or your last time dealing with game states, it’s likely better to KISS and use a switch, right up front, no frills. Use an enum to control the switch so it all makes nice sense.
So you can merely change the state at any point by writing state = State.MainMenu or state = State.Attack and so on. The switch takes care of it.
TLDR: If you haven’t done states before, use switch + enum for legibility. It seems like a special state machine is the best thing ever but it’s not. You’re just making it bloated when it doesn’t need to be.
Writing a bit more code that says exactly what it does on the tin is always preferable for finishing a project. Your bugs are less, your code is easier and cleaner to change. You end up coding the game and not the libraries for a mythical what-if scenario.
Mythical what-ifs are for game engines and middleware like Unity. Our job is to keep it simple and ship.