generic way to handle state for entire game engine?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
generic way to handle state for entire game engine?
by on (#55671)
So, at the moment the way I deal with states in my game is sort of a hybrid. It seems like state breaks down into two categories:

Category 1: States are very simple, they really communicate large logical blocks of code. In this case, it probably makes more sense to use indirect jumps rather than cmp/beq and bit logic.

Category 2: States are more complicated. Some bits may be an enumeration, some may be an "on off" state, etc. Here we must use bit logic to discover the state in question and then use cmp/beq to decide what branch to use to handle the state.

I guess what I was wondering is, is there any "generic" way of handling states in your engine, which is flexible enough to support the highest level, overall game state (title screen, transitions, gameplay), and also the most detailed level, such as how your game objects are animated, how they interact with their environment, etc. For now, I'm going for a hybrid of the above two approaches. The higher the level, the easier it is to use indirect jumps, the more detailed the level, the more likely I am to use cmp/beq and constants...bit logic, etc.

Thoughts?

by on (#55672)
I've written game rule engines where an object has a main state in category 1 and several sub-states in category 2. They might do something based on the main state (possibly with an RTS trick) and then do various things based on the sub-states, either inside the handlers for the object's main state or inside the object's master handler.

by on (#55673)
Maybe I should ask a more specific question. I have one main actor in my game, and at the moment he has two state variables, each one byte in size. The first one is his "top level" state, and each bit basically says whether or not the actor is doing a certain thing. Some of these are mutually exclusive and others are not. Then, I have a "sub state" variable, for which I have several constants defined (I have some constants for the main state as well) for using this sub state variable to refine some of the top level states. So, what I end up doing is some bit logic (specifically masks) to get out what part of the state variable I'm itnerested in testing, and then a few cmp/beq's in some cases for the sub states... I was just wondering if there was a way to avoid sequences of cmp/beqs that could work in a straightforward way for an entire game engine. Personally I only see how indirect jumps could work for really simple states where all individual states are mutually exclusive. Like, my game can't be in the title screen and in the game play state at the same time. But when you get down to the actor, you can have some states that are mutually exclusive and others that are not--- I guess I'm not sure I see how one could handle this generically. Maybe there isn't an easy way, I'm not sure. ... not without incurring some overhead, at least. My hope is to just continue doing it as I have been, but try to keep it organized *as though* I were implementing some kind of framework.

by on (#55675)
I thought about making a thread for this recently, actually, it will be interesting to read peoples' ideas.

Like in a side scroller, do you have a "game paused" state, or deal with that as part of the general "gameplay" state, or do you have a state for anytime normal physics calculations are not being done? As a sub-state, would something like pause work fine as a branch-if-flag-set, or is a full state handler necessary?

As Gradualore said, mutual exclusivity does help a lot. One good deciding factor for states might be when most variables are reset, such as level dividers/cutscenes. Those are drastically different parts of the program.

How many states would a typical game have, on a basic level?

by on (#55676)
We could have a thread on the higher level game state, in fact, I think there have been several such threads already. I recall seeing one in the newbie forum a few months ago. To me, this is a pretty simple problem due to the fact that all the higher level states are mutually exclusive. But when you get to the level of game objects, you may have a state variable whose bits can tell you things like: "I am currently attacking. My weapon is extended far enough that I am deadly. I am standing on a platform. I am using weapon 0." all at once. To do this generically, using bit fields, it seems to me would incur rather egregious overhead.

*edit* I guess I was just wondering if anyone has tried to do this a different way or if what I'm describing is fairly common?

by on (#55685)
Back when I chiseled out a platformer engine for myself, I ended up with a couple of differing 'state' mechanisms.

First and foremost, the main state of the game was determined by which loop of code it was running. There weren't any variables in ram to determine what state the game was in, it was all done with JMPs and such. I only had three game states though; load_level, in_game, paused. I did this because all of these states are serial to each other; I don't need the game logic to be executing during the pause state, or the load level state.

Actor states were slightly different though, there was a variable used to keep track of what state the actor was in. This variable acted as an index into a jump table, and to run the actor logic, I'd indirectly JSR to the selected pointer. (as in, copy the pointer from the table to $00-$01, then JSR to a JMP ($00) instruction) The JSR was because I had movement/collision routines executed after the state-specific logic was done, since those routines were common to all states. It worked for my needs, but I need to re-implement actor states at some point to make them behave more efficiently, and when I do, I'll be sure to share my findings. :P

by on (#55690)
Well, when I first coded for the NES I had the main loop just doing a "jump here" and the NMI all based on a state/substate structure (like SMB).

Now that I've switched to a more standard way to handling the code in a linear way, and I can say I liked it MUCH better. So when I initially wrote the game engine for my project Dragon Skill, I had the linear structure for the main code, but I had this state switch formula for various things like objects, player control and drawing sprites.
As I made improvements and tweaking I eventually removed this state switch system everywhere exept in ONE place : the player control routine. I have trought of removing it, but it's working fine and I didn't feel to go trough this useless rewrite.

So in summary I hate the whole state switch idea and will likely never use it again - I do stack tricks instead and make my code linear.
But in the only place where I still use it - that is the player control routine, I use a jump table with the RTS trick (just beacuse it saved me like 2 bytes from a jump indirect).[/code]

by on (#55694)
I treat game states and objects states very differently. Each game state (title screen, menus, gameplay, etc) has its own routine, that usually starts with the necessary initialization steps and eventually reaches a loop. To switch from one game state to the other, a state sets the index of the next state and returns, the main loop will take care of jumping to the initialization of the next state (this is all it does).

This allows for sub-states too. All I have to do is jump to the initialization of a new state without returning from the current one (the new state has to know it's a sub-state in order to not overwrite the variables of the parent state). This could be useful for things like Mega Man's in game weapon selection, for example. When the new state returns we'll be back to the gameplay.

One thing that makes game states complex to program is the NMI handler, because sometimes they need special tasks to be performed there. Well, my NMI routine basically sets a flag to indicate that VBlank started, so if a game state works well by just "waiting for VBlank" they'll use that flag. But if they require more specialized NMI code they can set a pointer to such specialized code and it will be called by the NMI routine (if there is a routine specified, it's called, if there isn't, the VBlank flag is set).

Object states vary according to the objects, for some it might be easier to use a jump table, but I usually go with interpreting the state values.

by on (#55697)
tokumaru wrote:
One thing that makes game states complex to program is the NMI handler, because sometimes they need special tasks to be performed there. Well, my NMI routine basically sets a flag to indicate that VBlank started, so if a game state works well by just "waiting for VBlank" they'll use that flag. But if they require more specialized NMI code they can set a pointer to such specialized code and it will be called by the NMI routine (if there is a routine specified, it's called, if there isn't, the VBlank flag is set).

Just out of curiosity, what is your main loop doing that it needs specialized NMI code for? Is it just the data stream to the PPU/sprite dma?

by on (#55699)
Drag wrote:
Just out of curiosity, what is your main loop doing that it needs specialized NMI code for? Is it just the data stream to the PPU/sprite dma?

So far I've only needed a specialized NMI for the main gameplay, because frame calculations might go past the start of VBlank (like when there are many objects active at once), so if I used the regular "wait for VBlank" I'd miss a VBlank.

I don't want to miss VBlanks because I don't want the audio to lag and because I mask off a few scanlines at the top of the screen for extra VBlank time and for hiding scrolling glitches, and that border requires very precise timing.

The other game modes are very unlikely to need more than a frame to compute their state, so they will probably work with the regular VBlank waiting just fine.

by on (#55717)
There are some good ideas here. It seems like most people think of overall "game state" when state is mentioned. Brief mentioning of varying object states suggests to me that most people just assume that when you get down to the level of the "intelligence routine" for any given object, that the use of state variables/bits may vary so much that there is no reasonable way to "abstract" that. In fact, even in a higher level language there may not be. When you get down to this level, this is when you may be writing a "script" for a game object, which should be able to vary and do lots of weird, messy tricks to get the job done =) It is just too complicated to distill into an abstraction.