• ### Popular Now

• 13
• 16
• 27
• 9
• 9

#### Archived

This topic is now archived and is closed to further replies.

# 04.09 - Game States and Variable Scope

This topic is 6080 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

From Demos to Games Throughout the last eight articles, we''ve taken a tour of different game elements, each an integral part of game development. Of course, what we''ve written thus far could hardly be considered games. But let''s face it -- you can''t write games unless you can display/animate images, control timing, understand resolutions and colors, and harness DirectX to make all of these work together. Now that we have some skill in these departments, what''s missing? Continuity. That''s what we''re missing. Games don''t just start with players running around and shooting. There''s intro screens, menus, multiple levels, intros/outros and cutscenes, etc. In other words, a game consists of many different components, and all we''ve got so far is our single entry point, Game_Main(). Obviously if we want to write anything robust, we''re going to need a little help. Life in Game_Main() We know that Game_Main() is executed continually, and the approach we''re taking is to render a single frame of animation each time. We also know that the only way to remind ourselves in Game_Main() of what we''re supposed to be doing each frame is by keeping track of everything with static/global variables and other data structures. All that we need to do is add an additional level of organization so that our game not only knows ''how'' to do things, but ''when'' to do things. As an example, say our game consists of an intro screen (something that says, "Press SPACE to begin"), and the actual game where our sprites are moving around, etc. We''d start by thinking of these two components as separate, and assign a new global variable to keep track of where the user is:

enum GameState {GS_INTRO, GS_GAME};

// Our G structure in GLOBALS.H
struct
{
...
GameState gameState;
...
} G;

Somewhere in Game_Initialize() we would initialize this variable like so:

G.gameState = GS_INTRO;

...and in Game_Main(), we could branch-off depending on the game state:

void Game_Main()
{
if (G.gameState == GS_INTRO)
{
// Show the intro screen
}
else
{
// The game -- move sprites
}
}

This is about the simplist mechanism for game states that I could think of. Of course, for this particular example it works fine, so there would be no need to go further. In reality though, we''ll have more than two game states, and this if/else structure could quickly become large and unweildy. How else could we implement this type of ''filter''? How about this:

void Game_Main()
{
switch (G.gameState)
{
case GS_INTRO: GS_Intro(); break;
case GS_GAME:  GS_Game();  break;
}
}

This approach definitely seems a lot smarter, as it calls a corresponding game function for each possible game state. And, let me tell you, you will not want to be writing entire games in Game_Main() unless they''re very small... Sometimes you might want to use a combination of the two -- a main game state that determines which function gets called, and a secondary, or sub-state variable to act as a filter once in the proper game function. Here''s an example of what I mean:

enum MainGS {MGS_INTRO, MGS_GAME};
enum SubGS  {SGS_MOVING, SGS_SHOOTING, SGS_DYING};

// Our G structure in GLOBALS.H
struct
{
...
MainGS gameState;
SubGS  gameSubState;
...
} G;

Here, we could use gameState to call the appropriate game function (e.g. using the switch construct), and we could use gameSubState from within the chosen game function as a helper. What you get is two levels of indirection that can help you better organize what code needs to be executed when in order for your game to work properly. Another technique involves using function pointers, which is a powerful programming technique that''s covered in Tricks and Techniques. Sufficive to say, we don''t need anything of these calibre for our immediate purposes. Tracing Your Footsteps The use of enumerated game states is definitely going to help us organize a simple game, and there''s one more game state that we should be keeping track of to make life a little easier on us. It turns out that it''s often important to know not only what state we''re currently in, but what state we''re coming from. To validate this need, take a look at the following:

...
{
// Code to animate player''s death
}
...

Let''s assume that the code for this block is responsible for an animation spanning multiple sprite frames controlled by a timer. You see, this block of code is going to be executed repeatedly because the game state GS_DEAD will be the current game state for the whole time the player is seen crouching over and dying, and this means that there will be variables that need to be initialized. One way to accomplish this is to add a little logic like so:

...
{
{
// Initialize local variables
// ...
}

// Code to animate player''s death
}
...

The first time this code is executed, it knows that it''s the first time and therefore can initialize any local variables it needs to render the player''s death properly. Once this code has completed the sequence, it will change the current game state to something other than GS_DEAD. The new game state can then in turn utilize this initialization technique as well. Of course, there are other ways to do this:

...
{
static bool bInit = FALSE;

if (bInit == FALSE)
{
// Initialize local variables
// ...
bInit = TRUE;
}

// Code to animate player''s death

// Are we done with this game state?
if (bDeathSequenceComplete == TRUE)
{
bInit = FALSE;
G.gameState = GS_SOMETHINGELSE;
}
}
...

Here we''re using a static variable, just like we did with Game_Main() in earlier articles. When this game state is complete, it''s important to reset the bInit flag so that later on in the game if GS_DEAD starts again, it will once again be initialized properly. Variable Scope When talking about game states, I alluded to the fact that large games need more than one main function. By the same token, large games should use more than one source code file for their game code as well. Luckily for us, our global G structure is designed so that any source file (module) can automatically ''see'' these global variables. All that you have to do is create a new source file and make sure this is the top:

#include "Globals.h"

You can then start writing functions inside of this new source file that work with your global variables, thereby contributing to the game. When working with multiple modules, it sometimes becomes important to further organize variables, as games can end up with a lot of them. Consider this example source file:

// EXAMPLE.CPP

#include "Globals.h"

static struct
{
int xpos, ypos;
int spriteState;
} L;

void Function1()
{
int local1;
// ...
}

void Function2()
{
bool bLocal;
// ...
}

Bacause of the #include at the top of the file, this file can freely make use of our G structure. At the top of this file is another structure called L, which stands for LOCAL, and holds some variables that only functions in this file can use. There are two reasons for grouping variables in this way:
• Using L gives us the look and feel of C++ classes, where all variables that belong to the module exist. If we combine all of the functions with a common purpose together with the variables they share, we have a clean and intuitive source code arrangement to work with.
• When reading the source code, one can easily distinguish which variables are local to the function, and which are also used by other functions in the module (i.e. there''s an ''L.'' before them).
Putting everything together, we get a template like this:

G
{
FILE1
{
L
{
Function1
{
local (stack) variables
}
Function2
{
local (stack) variables
}
...
}
}
FILE2
{
L
{
Function10
{
local (stack) variables
}
...
}
}
...
}

This illustration shows that G is visible by everything, and L is visible to the file in which it resides. In order to realize the benefits of this system of data organization, you have to be sure to properly organize your variables:
• If a variable is only needed by a single function, create it within the function
• If a variable is needed by more than one function,
1. if the functions seem like they belong to a group, group them to a file and place the variable in an L structure (i.e. file scope)
2. if the functions are in different files and shouldn''t be moved, place the variable in G

##### Share on other sites
I''m not trying to bother everyone by posting this here, but maybe since it''s at the top I''ll get a responce. My problem is that I don''t have VC++ or the money to buy it, although I do have Dev C++ and Borland 5.5. If you have used either of these to compile to sample project successfully please e-mail me and tell me how you did it. I hope to eventually get VC++, but at the moment I don''t have the money.

##### Share on other sites
Help!!!! Teej''s website with needed materials won''t pull up. It''s not just me because I tried it at work also. Anyone know what the deal is? Teej, if you see this then you, of course, would be able to provide the best answer. Hopefully you''ll check back today since this is a new topic. Any help at all would be accepted with open arms, though.

##### Share on other sites
The anonymous was me.

"Those who are skilled in combat do not become angered, those who are skilled at winning do not become afraid. Thus the wise win before they fight, while the ignorant fight to win."

##### Share on other sites
Anon,

I''ve got the same problem as you: I haven''t been able to pull up Teej''s website. I always get a "Page Not Found" screen. Like yourself, I need to get the source files off the site. I hope Teej fixes that link.

Carlos

##### Share on other sites
For those having trouble accessing his site, I believe Teej has moved to a new location:

http://www.angelfire.com/home/gamedev

Edited by - DTM on June 26, 2001 10:28:07 PM

##### Share on other sites
Thanks a lot! I''ve got the files now.

"Those who are skilled in combat do not become angered, those who are skilled at winning do not become afraid. Thus the wise win before they fight, while the ignorant fight to win."

##### Share on other sites
good job so far Teej. I really am enjoying playing around with the information I''ve gained through this tutorial along with a few other resources. I think you''re right about not starting out with a grandiose 3D project, though I think there is something to be said for finding your own methods and/or finding time-tested methods through your own hard work, patience and/or logic. Anyway, I just wanted to reiterate that you''re doing a great job.

##### Share on other sites
What is the deal with using non bmp files as our image files? I have a background (contains 296 colours) I would like to use for a program I am working on, and if I make a gif with it is around 150kbs, and if it is a bmp it is around 400 kbs, quite a difference really.

So are we really confined to using bmps or can we use any image files for our sources on DirectX.