How to separate code for different parts of a game (title screen, menu, gameplay)?

Started by
8 comments, last by superpig 16 years, 11 months ago
I've made a few little demo projects, but I've always had trouble when it comes time to separate the game into different modes. Start on a title screen, go to a menu or start the level, then show a status screen after the level and start a new level. Most of my games never get past the single-level demo stage because it becomes very difficult to direct the game to do anything else except the gameplay once the game engine is up and running. This pertains specifically to C++, C#, and Java.. but overall its just a general programming question. How do you guys switch from title screen to menu to level to next level?
Advertisement
I would use a variable called 'level' which changes depending on which level you are playing. The 'level' variable can, for example represent the filename that the program is going to load from a file. Separating the gameplay from the menu can be done in a simple way using a switch statement in the game loop like this.

// suppose we have a variable called gameTypeswitch (gameType) {    case 0: {         // draw menu screen     } break;    case 1: {        // status screen, show different things depending on the level    } break;    case 2: {        // gameplay, draw player etc..    } break;}


This is the way I use to do it, hope it helps..
Using a state machine of course [grin]


There are essentially 3 types of state machines: Stack-based, flat (the classical FSM), and hybrid types.

Stack-based machines are usefull when the transitions tend to be of the "go deeper, then back out" variety, because they implicitly record the order of transitions and can be freed when popped from the stack. A good example would be a menu system.

Flat FSMs don't typically preserve any information about the order in which states were visited, although you could write one that did. They're good for more dynamic transitions and when you don't particularly care about traversing back down the series of transitions you came from.

Hybrids are essentially a stack of flat FSMs. Transition order is not recorded within the flat FSMs, only when transitioning between them.


Currently I'm using a stack-based FSM in my application, and its working well. I can push, pop and set the top stack element and I have a parameter stack used for communication between states. There are hooks for managing resources as well: when a state is pushed onto the stack its resources are loaded and the previous state unloads any unnecessary resources. Because resources are reference counted and centrally managed, only resources currently needed will remain in memory and only those resources that are not already loaded will be loaded at this time.

throw table_exception("(? ???)? ? ???");

There are a lot of solutions to it. One of them is to have a main loop where each level gets started and when its done you move to the next one. You could make a script language to assign the game levels.

Ultimatly its a little vague, its important that you use OOP in your case, and that you ensure there is only one loop running in the game, and basically just have that loop start each level and when its done let it return a true and move on to the next level. But its all dependant on what for a game you want to make.

In my case we made a scripting language to do all of this sort of stuff :)
Quote:Original post by chefgon_ign
Most of my games never get past the single-level demo stage because it becomes very difficult to direct the game to do anything else except the gameplay once the game engine is up and running.
Use function pointers or a big switch statement in your game hub. I myself only have a few states, so I use a switch in my game class that calls different functions.

My main loop calls the Update(dt) function of my CGame class, and in there it goes through a switch statement to get to the correct current game mode. All game modes have a menu (I store all my menus in an array, and set the proper gui menu to be the active one when switching modes). Every mode will render it's menu, and do any other background / object rendering as needed.

If the user clicks on a button that causes the mode to change, than I set the new mode, change the active menu, or do any other state changes that need to be done, and that's it.. the next time the CGame.Update(dt) function gets called, it just calls the code for the current game mode.

EASY.
What I did when I was working on some mobile games, was writing a class for every separate menu and gamescreen. The gamescreens would load a specified level and handle the gameplay. All of these screen classes derived from a single class, and a display manager would store a reference to such an object, so you could swap screens whenever you wanted, and the display manager would simply continue displaying the new screen, whether it was a menu or game screen.

What I'm currently doing is loading a level from a script file, and providing some scriptable game entities that can flush the current level data and load a new one. I treat menu's as levels too, in terms of scriptability: when you click on the Start Game button, it activates a levelchange entity, that loads the first level, just like the changelevel entity in level 1 loads the script file of level 2. The only difference between a menu level and a real level is that the first has a 2D background and no player, and the second loads a 3D environment and inserts a controllable player.

I hope this will give you some idea's. :)
Create-ivity - a game development blog Mouseover for more information.
Quote:Original post by Vampyre_Dark
Use function pointers or a big switch statement in your game hub.
Or, if you're actually writing C++, then you use an abstract base class something like the following:

class IGameState{   virtual void render() = 0;   virtual void update(float timestep) = 0;};


and then derive your individual game states from it. The 'dispatcher' (the game loop) then only needs a pointer to the current IGameState that it can call functions on. It's basically identical to the function pointer approach, except that ties all function pointers for a given state together into one table (the vtable for the appropriate state object).

Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse

Quote:

Or, if you're actually writing C++, then you use an abstract base class something like the following:



class IGameState
{
virtual void render() = 0;
virtual void update(float timestep) = 0;
};

This is something like what I am using right now. So far, I love it...it is very easy to handle navigation... (below is the base state class definition).
//ZState.h#ifndef ZSTATE_DEF#define ZSTATE_DEF#include <d3d9.h>class ZStateManager;class ZState{public:	virtual bool update(float x){ return false; };	virtual void render(LPDIRECT3DDEVICE9 pd3dDevice){ };	virtual void init(LPDIRECT3DDEVICE9 pd3dDevice){ };	virtual void close(LPDIRECT3DDEVICE9 pd3dDevice){ };};#endif


I do have a question on this though. I have seen before where someone used static functions, not objects, for a state-machine. I believe that adding a new state also took a void** parameter, (which if I'm not mistaken is a pointer to a pointer, thus could be anything). Is this better than using classes, or is it probably more of a personal preference?
Before everyone gets you off course of what you want to do, I suggest getting an introduction book to Object Oriented Programming. After you have ravenously chewed that book apart (because you are a programmer, right?), check out the Gang of Fours' book on OO pattern designs.

I'm not associated with GoF, I just found their book really useful.
~Argonaut________________________________Why "~Argonaut"? It's all just a mathematical expression denoting a close approximation of "Argonaut", which is irrational and can't be precisely defined.
Indeed - I think this is in GOF as the 'State' pattern.

Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse

This topic is closed to new replies.

Advertisement