Control Structure For Games

Started by
2 comments, last by Kris Schnee 16 years, 4 months ago
I've hit a snag while working on a simple project to improve my skill. In a more complex project I was trying to coordinate among the various "screens" of the game such as the Title Screen, Wandering Screen (the main gameplay part), and Sailing Screen (quick travel mode). To do that, I had a central game object with a stack of states, given as strings, and a central message stack full of Python "dictionary" objects eg. {"headline":"Got Item","item":"Cookie"}. Each game screen was a function of the main object, containing a control loop of some kind. The screens passed messages back and forth to each other. That system got confusing when I dealt with these situations: -Events generated by interface objects, eg. "player hit Button X" -Screens that needed to be run without ending the function that called them -Events being handled by one of those sub-screens when they should've been handled by the calling function, or the wrong screen clearing the event stack at the same time I tried variations on the state-switching idea like having a separate message stack within each function, but nothing seemed to be a perfect solution for getting information about the state of the game where it needed to go. So, I'm trying to develop a control structure for a simple game, that I can then extend. The last advice I got was to treat all the various screens as objects, applying Model/View/Control architecture so that the main game object has all the info on the world's state and the screen-objects store whatever data is needed by them. Messages would be passed up a chain of command to objects' owners/parents, with only ones that affect the world's state making it to the master object. To make things clearer, I need to deal with at least the following situations in different projects I want to work on: -In a tactical combat game, calling up a menu to have the player input a multi-part command (action type, target) -In a strategy game, going to a mission planning screen, then opening subparts of that to input details like the mission destination -In an action RPG, opening a save-game screen or the quick-travel screen Am I overthinking this? I understand the basic MVC concept but am having trouble making it practical. I'm working in Python with a home-made UI, so it can work pretty much any way I want it to.
Advertisement
I think you are confused about the purpose of state stacks. They are, basically, for "emulating" function calls. People want to emulate them because the game control logic very much looks like nested function calls.
The problem is that for every part of the game, you need things like timing and framerate control. Unless one wants to duplicate these things in every game state, like it seems you're doing, one will centralize them in a "main loop" function. Then this main loop delegates everything else to the current state, calling methods like "drawToScreen" or "runLogic", and the state objects won't have to care about framerate etc.
The state stack is then a replacement for the function-call-like notion of doing something, but returning to what we were previously doing after we are finished.

The correspondence is
call <=> push state
return <=> pop state
goto <=> set state

and each state on the stack roughly corresponds to a function call frame.

Your "message stack" also seems a bit convoluted. Why not use normal method calls or constructors?
A rough example:
class Wandering:    # def __init__(...)    # def drawToScreen(...)    def runLogic(self, states, ...):        # ...        if collideWithCookie:            # the following does not display anything immediately, it only constructs a             # state object            states.append(PlayerMessage("You got an item", "Cookie"))        # ...        if hitpoints <= 0:            states.pop()            states.append(GameOver())        # ...        if playerWantsToSave:            states.append(Saving(self.player.items, whateverelseneedstobesaved)) 

where GameOver, Saving and PlayerMessage are other game states.




Quote:Original post by Kris Schnee
I've hit a snag while working on a simple project to improve my skill.

In a more complex project I was trying to coordinate among the various "screens" of the game such as the Title Screen, Wandering Screen (the main gameplay part), and Sailing Screen (quick travel mode). To do that, I had a central game object with a stack of states, given as strings, and a central message stack full of Python "dictionary" objects eg. {"headline":"Got Item","item":"Cookie"}. Each game screen was a function of the main object, containing a control loop of some kind. The screens passed messages back and forth to each other.

Here yo mix up the model, view and controller of your game. UI states are usually dependent on game states, but by no means the same; for example, the game can be paused in the same way for the different setup menus (and for any dialog box), and the same game events could take place with different user interfaces.

Your wandering and sailing "screens" are not genuine game states, only a particular modal user interface that produces both tactical and quick movement commands; the same quick travel might be ordered un the main map and/or by other means.

Rather than communicating with each other and storing poorly encapsulated random data, your "screens" (i.e. MVC views) should communicate only with a controller which in turn manages actual game events and state (the model).
Quote:
So, I'm trying to develop a control structure for a simple game, that I can then extend.
...
To make things clearer, I need to deal with at least the following situations in different projects I want to work on:
...

Deal with those situations if and when you work on them; recycling and adapting the working solutions of your first game will be more productive that making a generic mess in advance.

Omae Wa Mou Shindeiru

Thanks, both of you. I wrote up this code to try to implement a central "main loop" that does routine events and that calls drawing and logic functions. Each "state" now is really just a pair of those functions, *Logic and *Draw. As written, there's no messaging system, so I'm assuming that a logic function would reach directly into the World object (self.world) to change things, in this case incrementing a timer. (The demo just displays a flickering blue square.)

Basically this code has a stack of strings, with push/pop/jump functions, and when a new state is added/removed a new pair of logic and drawing functions is "installed" in the place where the main loop calls them. There's no messaging at all between functions. In my tactics game I would have to store certain things in the World as a surrogate for that. For instance while entering a command, which requires multiple pieces of data like a move destination, action and action target, I'd probably store the half-formed command somewhere in the World object. Is that bad?

A possible improvement might be to have logic functions access a function of the World object instead of modifying its code directly. That'd probably mean having specialized functions like "AdvanceTimer" rather than one general "Notify" event that'd give me the "poorly-encapsulated random data" problem again. Another possibility is to make the World object part of the Game object directly by subclassing.

This topic is closed to new replies.

Advertisement