Navigatgame dev field notes
IntermediateBuild

Game States and Screens

游戏状态与画面

Updated October 10, 2026

01What this concept is really about

Game states and screens are the answer to a simple but powerful question: what is the game doing right now? At any moment, your game is in exactly one high-level mode. It might be showing a title screen, running the main menu, loading a level, playing the game, pausing, showing a game-over screen, or sitting in an options menu. Each of these modes is a state. A screen is the visible part of a state, the thing the player sees and interacts with. The concept is really about naming those modes clearly and deciding what each one is allowed to do.

When you make states explicit, you give each one a clear job. The playing state reads gameplay input and updates the world. The paused state stops world updates and listens for a resume command. The menu state moves a selection cursor and waits for a confirm command. Because each state has a defined boundary, you always know where a piece of logic belongs. This is the opposite of letting every system check a pile of boolean flags like isPaused, isInMenu, or isLoading. Those flags multiply and start contradicting each other.

Think of states as rooms in a building. You can only stand in one room at a time, and each room has its own furniture and rules. Moving between rooms is a transition, and transitions are where most bugs hide. If you design states and transitions deliberately, your game becomes easier to reason about, easier to test, and easier to extend with new screens later.

02Why it matters for your game

Without organized states, your game loop turns into a tangle of conditionals. You check whether the menu is open before updating enemies, whether a dialog box is active before reading movement input, and whether the game is paused before advancing timers. Every new feature adds another check in another place. Soon a small change in one screen breaks behavior in a completely unrelated one. This is the spaghetti state problem, and it gets worse as the project grows.

Explicit states matter because they give you a single source of truth. When the game knows it is in the playing state, the update code for that state can assume gameplay rules apply. When it is in the paused state, you can skip world updates entirely instead of guarding every system with a flag. This reduces the number of places you must remember to change, which directly reduces bugs. It also makes input handling cleaner, because each state can interpret the same button differently. Confirm means start game in a menu, but it might mean interact in the playing state.

States also help with save systems and transitions. If you know exactly which state the player is in, you can decide what needs to be persisted and what can be rebuilt. Loading a saved game becomes a transition into a known state rather than a scramble to restore scattered flags. Finally, organized states make your code readable to future you. A new contributor can open the state list and understand the whole flow of the game at a glance, which is a huge advantage for any project that lives longer than a weekend.

03The mistake beginners often make

The most common mistake is representing game modes with scattered booleans. A beginner adds isPaused, then isInMenu, then isLoading, then isGameOver. Each one seems harmless on its own. But combinations appear that should never exist, such as paused and loading at the same time, or in-menu and playing together. The code then needs extra checks to resolve these impossible situations, and those checks become new sources of bugs. This is how spaghetti state begins.

Another frequent mistake is putting state logic inside the wrong place. Beginners often let the rendering code decide whether the game should update, or let an input handler directly change gameplay variables. That mixes concerns and makes the flow hard to follow. A related error is treating a screen as only a visual layer while the real mode lives somewhere else. Then the visuals and the logic drift apart, and the player sees a menu while the game world keeps running underneath.

Beginners also tend to handle transitions ad hoc. They write one-off code to go from menu to game, then copy and paste it for game to game-over, then tweak it again for pause. Each transition ends up slightly different, with its own cleanup and setup steps. Over time these differences cause subtle bugs, like music that keeps playing after a screen closes, or input that stays locked after returning to the menu. The fix is not more patches. The fix is to make states explicit and route every transition through the same clear mechanism.

04A simple way to learn it

Start with a tiny practice project, not your main game. Write down every mode your game can be in as a short list of names, such as Title, Menu, Playing, Paused, and GameOver. Then build a single state variable that can hold exactly one of those names. This variable is your source of truth. Every part of your code that needs to know the current mode reads this one variable instead of checking separate flags. That single change already removes a large class of contradictions.

Next, give each state three small responsibilities: enter, update, and exit. Enter runs once when you switch into the state, and it sets up what that state needs. Update runs every frame while the state is active, and it handles that state's logic and input. Exit runs once when you leave, and it cleans up. For example, the Playing state's enter could start the level timer, its update could move the player, and its exit could stop the timer. The Paused state's update might only listen for a resume command. Keep each function short and focused.

Finally, write one transition function that changes the state safely. It should call the current state's exit, set the new state, then call the new state's enter. Route every switch through this function so cleanup and setup always happen in the same order. Practice by adding a new screen, such as Options, and wiring it in without touching the logic of other states. If you can do that cleanly, you have learned the core skill. Repeat this exercise until the pattern feels natural, then apply it to a real project.

05What to pair it with

States work best when paired with a clear game loop. The loop decides when to read input, when to update, and when to draw. Your state system then decides what each of those steps means for the current mode. For instance, the loop always runs, but the Playing state updates the world while the Paused state does not. Keeping the loop simple and letting states own the behavior is a clean division of labor. If your loop is already tangled, fix that first, because states sit on top of it.

Pair states with a thoughtful input layer. Input should be collected once per frame and then interpreted by the active state. The same confirm button can mean start in a menu, interact in play, and resume in pause. This keeps input mapping in one place and avoids scattering button checks across the codebase. It also makes rebinding and accessibility easier later, because the state asks for an action rather than a raw key.

Pair states with your save system as well. Decide which states can be saved and what data each one needs. A Playing state might save world progress, while a Menu state usually needs nothing. When loading, transition into a known state after restoring data, rather than trying to reconstruct flags. This makes save and load predictable. Together, the loop, input, and save system form a stable frame around your states, and each one becomes easier to reason about because the others are doing their own job.

06When to keep it simple

Not every project needs a full state machine with enter, update, and exit hooks for dozens of modes. If you are prototyping a single-screen game with no menus, a pause, or a game-over flow, a single mode variable may be all you need. The goal is organized states, not ceremony. Adding structure before you have a second mode is wasted effort and can slow down early experimentation. Start with the smallest thing that removes contradictions, and grow it only when a real need appears.

A good rule is to add a new state when you find yourself writing a conditional that changes broad behavior across many systems. If you catch yourself checking a flag in five different places, that is a signal to promote it to a proper state. On the other hand, if a condition affects only one small function, a local check is fine. Keep the state list short and meaningful. Five to eight states cover most small and medium games comfortably.

Also keep transitions simple at first. You do not need a complex graph or a data-driven table when you have three states. A direct function call from one state to another is perfectly readable. Complexity should be earned by real problems, not added in advance. If your state code is longer than the behavior it manages, you have probably overbuilt it. Step back, remove layers, and keep the explicit states that actually prevent spaghetti. Simplicity now leaves room for structure later when the game genuinely needs it.

07Questions beginners ask

Q: Can a game be in two states at once, like paused while in a menu? A: Usually no, and that is the point. Pick one active state and let it own the behavior. If you truly need layered behavior, such as a pause overlay on top of play, model it as a stack or as one state that knows about the overlay. Avoid two independent flags that can disagree.

Q: Where should state logic live, in the game loop or in the state itself? A: Put the behavior in the state and keep the loop generic. The loop should call the active state's update and draw, not decide what each mode does. This keeps the loop stable and lets you add states without editing it.

Q: How do I know when to add a new state? A: Add one when a mode changes behavior across several systems and you keep guarding it with flags. If the condition is local to one function, a simple check is fine. Let real friction, not anticipation, drive the decision, and keep the list short and clear.