Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
80 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

 Game States
 Events and Scripts

 Printable version
 Discuss this article
 in the forums

The Series
 Beginning Windows

 Using Resources
 in Win32 Programs

 Tracking Your
 Window/Using GDI

 to DirectX

 Palettes and Pixels
 in DirectDraw

 Bitmapped Graphics
 in DirectDraw

 Developing the
 Game Structure

 Basic Tile Engines
 Adding Characters
 Tips and Tricks


An effect as I define it for my game is anything you can see happening on the screen. Fades, particle systems, displaying text, etc. all fall into this category. I store an effect in a structure that looks like this:

typedef struct GAMEFX_type
  DWORD dwID;         // effect ID number
  DWORD dwFlags;      // control flags
  int nCurrent;       // for FOR loops
  int nTarget;        // ''
  int nStep;          // '' 
  int nLinkedScript;  // ID of script this is linked to (or -1 for none)
  int x, y;           // a screen location
  void *buffer;       // optional data table

Let me run through the parameters and explain what I'm using all this stuff for.

DWORD dwID: This is the effect identifier. It takes a value from one of a number of FX_ constants I have defined, such as FX_FADE, FX_TEXTIN, or FX_PARTICLESYSTEM.

DWORD dwFlags: This can be used to store miscellaneous flags for each effect, and so its use varies from one effect to another.

int nCurrent, nTarget, nStep: These are used to define for-style loops, or incremental effects. For example, I have a script command called FadeDown. An example call would be:

FadeDown 34, 11

This means, "Fade down to 34% by increments of 11%." The way the GAMEFX structure is set up for this, nCurrent is set to the current fade percentage, whatever that happens to be, nTarget is set to 34, and nStep is set to -11. In each iteration of the main loop, nCurrent is decreased by 11, and that percentage of fade is applied to the frame. Once nCurrent is less than or equal to nTarget, the effect terminates.

int nLinkedScript: This is the important one. If this is -1, the effect executes side-by-side with any scripts that are running. But if this value is nonnegative, then the script with that index cannot continue execution until the effect finishes. This is important! Let's go back to our earlier example.

ShowText 12, 133

Suppose these commands were found in the script in slot #1. Then when the effect generated by DoSomeAnimation was set up, it would be linked to script #1, and thus the script would halt execution until the effect was done, at which point the text would be displayed, like we wanted! This adds one more step to our script handler: if the script is linked to any effects, don't execute it. Also note that any script command which will link the script to an effect must be terminal, so script execution stops right away.

int x, y: Many effects, like displaying text, require a location on the screen, so I provide one here. If you need multiple locations for an effect, well, that's what the final parameter is for...

void *buffer: Many effects can easily be specified by using only the above parameters. But what if you want to create a blizzard by sweeping 800 particles across the screen on increasing-amplitude sine waves? You don't want to be calculating that stuff as you go! The solution is to take this pointer, malloc() yourself some memory, and you've got a lookup table. My philosophy is to precalculate everything that can be precalculated. Just remember to free() the memory when the effect is done.

So is this all starting to fall into place? With the above specifications laid out, you can easily make your effects such that they can be executed one frame at a time. The only question that remains is how to store the effects in memory. Well, effects aren't something I like to have a limit on, and since you're going to be accessing them in sequential order all the time, this is a great candidate for a linked list. When you want a new effect, just stick a structure on the end of the list. When an effect is finished, just cut the links. It's as simple as that! If you're not familiar with linked lists, find a tutorial, because I use them a lot. :)

One other thing I'll do with effects is to give them an extra parameter in their corresponding script commands that flags whether or not they should link the script that calls them. For instance, if I wanted to fade the screen down, and only then display some text, I could put this in my script:

FadeDown 50, 5, TRUE
ShowText 4, 230

This says that the call to FadeDown should link the script, and thus the text should be shown only after the fade is complete. But change the TRUE to FALSE, and the text will show while the screen is fading. This is a very simple, yet very effective way to either run several effects one after the other or simultaneously, with very little effort on your part.


All right, that about wraps up this long-overdue article. We covered splitting a program into multiple components which can be developed independently of one another, and I think you've got all the basics now for designing a scheme that will let you run scripts and graphical effects that make Windows happy. In other words, they don't hog the processor for too long at once. You should be able to implement all these things and still maintain a good frame rate.

One thing to notice from this article is just how much of the game can be controlled with scripts. I use them for everything -- initialization, image loads, map loads, NPC setup, battle effects, fading, enemy AI, menu setup, etc. And as we'll see in a future article, probably #9, this can all be achieved with a scripting language that is very straightforward and easy to implement, with no need for any black magic on the programmer's part.

Now that I've gone over the basics of how you structure a Windows game program, the next article will finally be the long-awaited tile engine. I promise this time. :) I'm not sure how long it will be until I get around to it, but it's coming. In the meantime, if you've got any questions, go ahead and hit me with them:

E-mail: ironblayde@aeon-software.com
ICQ: UIN #53210499

Happy coding, until we meet again...

Copyright © 2000 by Joseph D. Farrell. All rights reserved.