Program Your Own Video Games

Note: hexadecimal values are marked 0x.

Introduction

Playing computer games is one thing but to be able to make your own is something special. It's no easy task whatever platform you program for but on this page I present to you my own ideas that I've used for my games. I prefer to use C++ so examples will be shown using that language but a lot of what is on this page you should be able to convert to other programming languages.

Let me remind you one important thing and that's even the so-called experts make mistakes, some of them major. For example, collision testing can be very difficult and certainly most games lack perfect collision testing, if that can ever be done. Even the most advanced games can be glitchy and be plagued with common video game flaws.

It can be frustrating at times trying to squash bugs but keep at it as it's well worth the effort. Often the most simple mistakes can cause serious errors; once I got over 100 errors (one of the errors was that there were over 100 errors!) because I had forgotten a single brace in my program.

One final note and that's although I've probably had the same ideas as many people and so they can't be copyrighted, I will only be mentioning highlights from my game engines as they are my own work. Also, I deal with concepts of both 2D and 3D games.


You can email me at james.boshikoopa@gmail.com

Why not have a look at my video game MyDream.

New: Player Object (25/12/19)

Dreamcast Game Programming (6/1/19)

Collision testing: Player to object interaction (8/10/18)

Reflections (11/6/17)

Traffic Lights (5/1/17)

Using collision meshes (4/1/17)

Wander Behaviour (1/1/17)

Level editing (8/5/16)

Climbing (28/8/15)

Update: Animation (26/8/15)

Collision testing (17/7/15)

Update: AI (15/7/15)

Update: Animation (9/5/15)

Collision testing (16/4/15)

Update: AI (14/04/15)

Update: Graphics (13/03/15)

Update: Collision testing (21/1/15)

Game saves (22/12/14)

Command line options (7/12/14)

Input (8/11/13)

Player Variables (19/9/13)

Update: Water boxes and other boxes (15/9/13)

3D Models (25/8/13)

Picking up and carrying objects (8/1/13)

Particle System

Update: Collision Testing

Water Boxes

Update: Level editing

Update: Graphics.

Input.

Conversations.

Animation.

Objects.

Collision Testing

3D Models

Please go to 3D Modelling.

Artificial Intelligence (AI)

In a typical video game a human will control the lead character and there will be a number of computer controlled baddies or even helpers. These Artificially Intelligent (AI) objects are also known as bots, CPU , drones and NPC (Non-Playable Character) and mean pretty much the same thing.

AI has advanced considerably over the years to better match a human (and other creatures) but there have been some bad attempts which tends to result in AI that's almost impossible to defeat, which is just unfair. A computer program can respond much faster than a human (a CPU can process thousands of operations in just a second) and as if that wasn't bad enough, AI often cheats. For example, in Super Smash Bros. Melee for the Gamecube, one of the Pokemon can cause the 'lights' to go out to the effect the screen is blanked, but the CPU carry on since they don't need to see the screen to fight (they go by collisions). Another e.g, is in racing games in which racers off screen will follow a much simpler route than when on-screen, to lower processing time but can cause the AI to suddenly appear even though it was far away.

A better example of AI can be found in Resident Evil Outbreak for the PS2; when playing offline you have 2 CPU characters helping you. Assuming that you pick characters that get on well together, while not perfect, the AI will do its best to assist you. From small things such as the AI character thanking you for protecting him or her from a zombie to the CPU character handing you useful items ("A herb-for me? Thanks!")

Pac-Man is a good choice for learning AI-in the game you have the hero chased by a number of ghosts that home in on Pac-Man. For the ghosts to home in on Pac-Man you simply have to determine whether Pac-Man is to the left or right of a ghost and also if he is above or below the ghost. So you need to look up both Pac-Man's and the ghosts' coordinates and compare if they are less than or greater than (if equal the ghost needn't move in that direction). So, you move the ghost either left or right, and up or down to get to Pac-Man, that is if there isn't part of the maze in the way. You then have a choice; the ghost could wait for Pac-Man to move if it has got stuck or the ghost could move in a different direction.

The ghosts, however, each have their own rules which gives them their own personality and makes the game possible to master once the rules are learnt (this is probably how people have got such high scores on Pac-Man). If you think about it, you follow your own rules even when playing a video game. You may decide that you will only attack the gate keeper if you are unable to obtain the key from another level. The important thing to keep in mind is that humans program the rules for the AI and what makes AI stand out is if it appears to 'think' for itself. If your player is in a room and makes a loud noise but the AI ignores you then that doesn't seem intelligent.

Let's now look at some AI programming that I have done for my own game, MyDream.

Computer controlled motorbike

MyDream supports different game modes but within the normal platform mode I wanted a race between the player and AI opponents. I modelled a motorbike which is used by the player and the AI, however, the motorbike object has a behaviour that lets the player control it whereas the motorbike objects for the AI have a different behaviour that lets the object follow a set path.

When the player is riding the motorbike the player's position and rotation don't update the player object but instead update the motorbike object the player is on. The player's position and rotation are then set to be the same as that of the motorbike object giving the appearance that the player moves with the motorbike. This is similar with the AI but as the AI motorbikes follow a path and the AI is moved with the motorbike it's more like the motorbike is controlling the AI opponent.

If the AI just followed the path the race would be very predictable and the AI wouldn't seem intelligent so we need to make the AI aware of the player and other, CPU controlled racers. It is a good idea at level start to build a list of racers as object indices so that you can quickly access them.

So the first thing we need to do is detect if any other racers are near to an AI racer and when I speak of a racer I mean the motorbike object (human or CPU controlled) as that is what is actually moving with its own attributes (speed, etc). To detect if a racer is near we can calculate the average distance between the two objects, objA and objB:

float distX=fabs(objA.x-objB.x);

float distY=fabs(objA.y-objB.y);

float distZ=fabs(objA.z-objB.z);

float avrgDist=(distX+distY+distZ)/3;

Just to add, you may not want to continually search for other racers when it would be easier to create a list of racers at level start which will make it easy and quick to index the racer objects to get their values.

Once we have the average distance between the two racers we can see if the distance is within a threshold value and if so take some action. Since other racers in front could cause a collision the logical thing to do would be to see if the object that is close by is actually in front. To do this we need two vectors; the racer's directional vector and a vector pointing from the racer to the other racer. We then calculate the dot product of the two vectors which gives us the cosine of the angle between the two vectors. This scalar value will be positive if the other racer is in front and negative if it is behind. The actual value (assuming normalised vectors were used when taking the dot product) will be between 0 and 1 for an object in front and between 0 and -1 for an object behind. This means we can compare this value against another to see if the racer is within the AI's field of view. For example, a value of 0.5 would give the AI a FOV of 60 degrees in front since the dot product gives us the cosine of the angle and the inverse cosine of 0.5 is 60.

When we know that there is an object near and is in front the AI needs to do something to prevent a collision and one such course of action is to slow down or break. If you think about someone driving in real life they would lower their speed to maintain a safe distance from the driver in front and should the driver in front stop or move too slowly then the driver would either stop or try to overtake (but we will ignore overtaking for the moment).

We can define three key distance values the first of which is the far distance at which the AI starts to get concerned about the driver in front; this is the average distance value already mentioned and I will from now on refer to it as MAX_DIST. Then there is the safe distance, SAFE_DIST, which is the distance the AI will try to maintain. Should the racer in front get too close then the brake distance, BRK_DIST, can be used to apply the brakes should that distance be reached.

To keep within the safe distance the AI's speed is lowered the closer it gets to the racer in front until BRK_DIST is reached at which time the AI will stop moving. You can use something along the lines of the following to reduce the AI's speed:

float avrgDistDiff= SAFE_DIST-(SAFE_DIST-avrgDist); //How much this object is beyond safe distance

float speedReduction=maxSpeed/safeDist; //Speed reduction amount to stay in safe zone

float speed=speedReduction*avrgDistDiff; //Increasingly reduce speed the closer the object gets to the other racer

It really helps when testing to view the object's speed values to make sure the object is slowing down/speeding up correctly.

To further improve the AI you can have them try to avoid or overtake other racers and this can be done by splitting up the race area into three lanes (paths) for the AI to use. The first path will be the left lane, the second path the middle lane and the third path the right lane. When in the left lane the AI can switch to the middle lane; when in the middle lane the AI can move to either the left or right lane; when in the right lane the AI can switch to the middle lane. It's a good idea when switching lanes or before even changing to see if there is another racer in the way.

Have the racers start off following one of the three paths but when a racer is detected in front that is close the AI can switch to a different lane by finding the path point in the next path that is nearest. If you have an equal number of path points in each path and the path points roughly line up then switching between lanes should seem seamless.

To detect when racers pass the finish line you will need some sort of invisible object big enough that it covers the finish line and under no circumstances can it be missed such as by driving to the extreme left or right of the finish line. If you have a list of the racers then you only need to check if they have collided with the finish line.

Wander Behaviour

For one of my objects I wanted her to wander about part of the level until the player approaches her and talks to her. I could have used a path for her to follow but I wanted something more random although I could have used multiple paths and had the AI switch between paths. To be more random, however, I didn't want to use paths and instead thought about how I every so often could randomly generate a Y rotation value and use that to control the direction the AI moves in. So, the AI would move in its starting direction and after a set amount of time it would change direction and repeat.

Unfortunately there was a big flaw with that idea as it turns out that the standard C++ rand() function always returns a value higher than the previous value, which isn't a good form of random as you'll end up with the character going around in circles. Worse still, if the AI hits a wall and we move away from it and then generate another random Y rotation for the direction, it will most likely hit the wall again and you'll have the AI bouncing back and forth.

Although I could have switched to a better random function and indeed I will need to do that eventually, I found a way around the predictability of rand(). What I do now is, if a collision is detected (that is, the AI has hit a wall or another object), the AI is rotated 90 degrees (so is moves away from the wall or object), moved in the new direction, and a flag is flipped. The flag determines whether the random Y rotation from rand() is either taken as the actually new Y rotation or whether it is subtracted from the current Y rotation. The reasoning is that if there is a collision we can remember that through the use of the flag and effectively guide the AI away from whatever caused the collision by using the new random values as subtraction values. Whatever the new Y rotation, I always keep it within 0 to 359 by converting as necessary.

Animation

2D animation

To create 2D animation it is a simple matter of cycling through a number of pre-rendered frames with the correct timing. You can keep track of the current animation frame using an integer variable which acts as an index into which frame to use.

You could have each animation frame as a separate bitmap or texture or you can use just one large image for each animation and select part of the picture or texture to use. That is, to divide it up into the smaller frames and although that would mean only needing to load one image for each animation you will need to make sure each frame is aligned and the same size.

3D animation

There are two main ways you can animate 3D objects and that is either to use pre-calculated values for the positions of each body part or to calculate the positions as the game is played. The latter, which is known as procedural animation is more difficult to program but it has certain advantages over more traditional 3D animation. If done right, with procedural animation, you can have animations where the individual body parts react to others or other objects for more life-like animation. Another example of the use of procedural animation is to turn a character's head as the player changes the view with the controller.

Animated objects consist of the body parts arranged in a hierarchy so that, for example, when the torso moves so does the arms and head. If you move your hand then your arm also moves with it, but you don't think about moving your arm, only your hand. This type of system is known as a parent-child relationship and each object or node is either a parent or child, or both. For e.g., the upper torso is a parent, and its children are the head and upper arns. However, the upper arm is also a parent to the lower arm which in turn is the parent of the hand. In this way, when the parent moves so do the children but the children also have individual movement.

To be able to have the parent-child relationship when animating we have to keep track of the current transformations (e.g., rotation) and we can do so using a stack. The hierarchy is defined by start nodes and end nodes so when we come across a start node we know that the current transformations are to be applied to the other body parts down the hierarchy; the end node is the end of the chain. So, the torso, upperarm and lowerarm would all be start nodes and the hand an end node. This way, moving the torso also move the upperarm, lowerarm and hand just as moving the upperarm also moves the lowerarm and hand and so on except that when the hand moves nothing else does (it has no children).

We can envisage the animation hierarchy for a person as something like the following (snode=start node; enode=end node):

<snode>Upper torso

<snode>Head

Hair

<enode>

<snode>Left upper arm

<snode>Left lower arm

L hand

<enode>

<enode>

<snode>Right upper arm

<snode>Right lower arm

Right hand

<enode>

<enode>

<enode>

<snode>Lower torso

<snode>Left upper leg

<snode>Left lower leg

Left foot

<enode>

<enode>

<snode>Right upper leg

<snode>Right lower leg

Right foot

<enode>

<enode>

<enode>

Note that there are an equal number of start nodes and end nodes.

In this set-up the upper torso and lower torso do not affect each other but they both actually have a parent-the object itself. That is, we can think of the animated body as being attached to the game object. So, when the game object moves, or is transformed in another way, so are all the body parts. These transformations of the game object are the starting transformations that are first placed on the stack. So, although the upper torso and lower torso are not connected in the hierarchy, they do move with the game object.

If you are using a 3D modelling program such as 3ds Max then likely you will animate your characters in the same program but even if you use different software you will need a way to get the animations into your game. Some 3D mesh files such as the DirectX .X format support animation in addition to the 3D model information but others do not such as Wavefront .obj format. However, you may want to store the animation separately so that, for e.g., it can be applied to multiple meshes that use the same animations.

I originally built a 3D animation editor into my game MyDream but found it too difficult to use and there were a number of bugs in it that needed sorting. So I looked at using the animation data exported from 3ds Max and found that it had the option to save the animation data as an XML file by going to Animation->Save Animation... XML (eXtensible Markup Language) is a handy format for storing information as anyone can read it without too much difficulty and so can a computer although because of its text format it can take up a lot of disk space.

The .NET framework has a number of XML readers but they were a pain to get working and where possible I like to avoid the need to rely on anything tied to a particular company. So I wrote my own XML reader especially for exported 3ds Max animation data but to cut down on the code I took advantage of the fact that certain data would always be in a particular order. A good XML reader, however, should be able to handle any tag in any position in a file.

Looking online I couldn't find any information about the XML format 3ds Max uses so as I wrote the XML reader I had to work out what the different values meant. Fortunately, because of the text based format it's quite clear what the various values mean and I have been able to extract hierarchy and rotation values from an XML animation file.

I'm going to go over the general format of a 3ds Max XML animation file and what some of the values mean. The file starts with a MaxAnimation tag which includes the saved animation format version as well as the date and time the file was saved:

<MaxAnimation version="1.00" date="Sun May 03 19:45:22 2015">

The first thing the XML reader should check is that the MaxAnimation tag is present. The closing MaxAnimation tag is on the last line of the file.

Next up is the SceneInfo tag which contains the file name of the .max file that contains the 3D model and animation and then the timing values startTick (the animation start time), endTick (the animation end time), frameRate (the number of frames in a second) and ticksPerFrame (how many ticks in a frame):

<SceneInfo fileName="KittyWongRigged_walk.max" startTick="0" endTick="480" frameRate="30" ticksPerFrame="160" />

If we wanted to work out the number of frames you simply work out:

Number of frames=((endTick-startTick)/ticksPerFrame)+1

In the above example there are 4 frames (you add one because the first frame is zero).

On the next line you have the CustomData tag; to save custom data you enter values into the User data section of the Save XML animation file dialog box. This is very useful as you could, for e.g., specify that the animation is to be played twice as fast, or another use could be to point out where one animation starts and the other ends (if saving multiple animations in a single file).

Now we come across Node tags which are used for each object that makes up an animation but these node tags are only saved for the body parts that are selected when you choose to export the animation in 3ds Max. Thus, you must remember to select all objects of the animation before exporting the animation even if the body part isn't animated so that you can get the hierarchy information.

Here is an example Node tag:

<Node name="UpperTorso" parentNode="Scene Root" parentNodeIndex="0" numChildren="5">

Name is the identifier you gave the object in 3ds Max; parentNode is name of this object's parent-if it's 'Scene Root' then it has no parent. parentNodeIndex is the zero based index of the child in the chain. Lastly, numChildren is how many children the parent has. From this information we can work out the start and end nodes; if the node have children it's a parent and thus a start node. When we find the last child node in a link (parentNodeIndex==numChildren-1) we add the number of end nodes equal to the number of children. We also have to add an end node when we've processed all children of the parent that has no parent.

If a body part has a rotation value as part of the animation then the rotation value is saved in the XML file. The Controller tag is used to wrap around transformation values such as rotation. For e.g., the X rotation block starts with a Controller tag and within that a name attribute with the value:

name \ Transform \ Rotation \ X Rotation

Where name is the object's name.

Following the Controller tag is a Keys tag with attribute Count having a value equal to the number of frames. After the Keys tag is a Key tag for each frame and in that Key tag is the attribute v with the rotation value in radians. To convert to degrees you can use D3DXToDegree() if using Direct3D.

Y and Z rotation values follow each starting with a Controller tag having a name attribute similar to X rotation but with 'Y Rotation' and 'Z rotation' at the end accordingly. As rotation values are only saved for animation objects that actually have been rotated you will need to use default values for objects without rotation. Also, since 3ds Max has the Y and Z rotation axes swapped you will need to swap them in your code by loading the Y value into the Z rotation and the Z value into the Y rotation.

Combining 3D animations

If you think about a typical game you will have actions such as the player carrying objects and on first thought you may think that you need to create additional animations for each situation-player walking while not carrying, player walking while carrying, and so on. A disadvantage of creating these extra animations for when the player carries an object is that it complicates the programming and should you change, for e.g., the walking animation, you would then also have to re-do the carrying while walking animation. However, you may want the walking while carrying animation to look different to a normal walking animations in terms of how the legs move.

If you would rather not have to produce these extra animations then you can combine animations together, such as a walking and carrying animation, or any other combination. Firstly, your objects will need two animation selection variables; a main animation (e.g. walking) and a second animation (e.g. carrying). In your animation file for the carrying animation you will need to lock certain body parts (the arms) to the carrying animation and the remaining body parts (legs, head, etc.) will use animation data from the main animation. Although 3ds Max lets you add custom attributes to objects I found no way to export such attributes to an animation file. So instead I added a custom attribute 'USE_OTHER_NAME' when saving the animation data and gave it the value '_OFF'. Then I re-named all body parts that were not the arms to include '_OFF' in their names. Then, when my game loaded the animation data, it looked for the 'USE_OTHER_NAME' attribute at the start of the file and if it found it, it would then check the body part names to see if they had '_OFF' in the name. For any body part that did, the corresponding start/end node structure for the body part would be set using a special flag to remember that the body part doesn't use animation values from the animation file for that animation. Lastly, when a 3D animated object is being rendered it's a matter of checking the body part flag to see if it is set to determine whether animation data should be taken from the main addition or the second animation.

Traffic Lights

For a level I was creating I needed a pedestrian operated set of traffic lights so that the player could safely cross the road as the cars harm the player should they hit her. As common with other objects I used the object's action value to remember the current state, and it was a simple matter of detecting a collision with the player while the action button is pressed to cause the traffic lights to change. But then I had to solve the problem of animating the changing of the lights. The solution was quite easy: for each light I modelled a sphere that was coloured on one side (red/green/amber) and black on the other side. Rotating the light 90 degrees effectively changes the colour of the light, simulating it being on or off. Then it is a matter of rendering each subset of the traffic light mesh in turn but for the light mesh subsets they are rotated based on the object's current state.

Behaviours

Each object in the game will behave in a certain way and there are several ways to handle these behaviours. First let's start with probably the most simple way and that to use behaviour flags that are combined using one or more integer values.

What you need to do is declare a number of constants and give them each a unique binary value so you might want to use hex values. You would end up with something like this as an example (C++):

const AUTO_MOVE_HORIZ=0x01;

const AUTO_MOVE_VERT=0x02;

const BADDY=0x04;

Then for each object you set its behaviour variable to a certain value using the handy names above. And if you want to have objects with several behaviours then all you have to do is OR the values together like this:

int caps=AUTO_MOVE_HORIZ | BADDY

Which would be two behaviours; to move left/right by itself and to attack the player.

For handling the behaviours use an AND test to find out the necessary action such as:

if (caps & BADDY) ATTACK=true;

The variable caps is the behaviour variable which is ANDed with each constant we need to test; be sure to bracket the variable and constant if you want to combine two or more tests together:

if ((caps & AUTO_MOVE_HORIZ) && (caps & AUTO_MOVE_VERT))

Please remember that the single ampersand (&) in C++ is used with binary values but for testing boolean (true or false) use two ampersands (&&). So the left and right tests end up as true or false results which then are combined into a single boolean test.

The behaviour (caps) variable can belong to each object or you could have a number of presets set up which each object can choose from. For example, you could have the tree behaviour which has the necessary behaviour flags set and any object that acts like a tree can use that preset, and the same for any other behaviours that you need.

The problem with using behaviour flags is that it limits greatly how the objects behave although changes can be made easily. A better way to handle object behaviours is for each object to have a pointer to the behaviour function which updates the object; the function can be as simple or complex as required. A variation is that instead of using a pointer an integer index variable is used instead which is used to look up the behaviour function in a table of pointers to behaviour functions or you could use switch statements. For e.g.:

switch (behaviour) {

case PLAYER:

playerObj(objI);

break;

case ITEM_BOX:

itemBox(objI);

break;

}

So, above, the behaviour value is read from the object currently being updated and this value is an unique int value (1,2,3,4, etc.). This value gets compared with the behaviour enums (PLAYER, ITEM_BOX, and so on) so that the correct behaviour function is called, such as playerObj for the PLAYER behaviour. Note that objI is passed to the behaviour function, which is the index of the object to be updated by the behaviour function.

You will find that some behaviours will have similar traits to other behaviours and you can cut down on programming by calling common code located in different functions. You could also use behaviour flags for common features such as for allowing talking to objects, climbing etc, that are in addition to what the behaviour function does.

Making changes to code can be very time consuming, however, so it may be worth considering using scripts for your objects. Each object's script will control what behaviour functions to use and specify behaviour values. This way you could more easily put together different objects based on simpler behaviours but do keep in mind that by using scripts they have to be processed which requires you wire an interpreter as simple as that may be.

Collision Testing

It's one of the most troublesome parts of programming a video game but very important unless you are creating a virtual world without interaction. Collision testing is needed so that the objects can interact which each other and the level scenery as well as possibly other entities, such as the mouse. Without it objects would go through walls, fall through floors and so on.

It is not always necessary to do complex collision testing, sometimes it's enough to do a quick, simple collision test and then respond. Other times you may need to do a simple collision test and then having found there is a collision then do a more time consuming collision test to see if a collision actually happened and perhaps to get further information (for example, how close two objects are).

One way to do simple and fast collision testing, although not that accurate, is to use bounding shapes which are shapes that the object's graphical form will fit inside of. Common examples of bounding shapes are rectangles and circles for 2D graphics and boxes and spheres for 3D graphics. These bounding shapes are not normally seen but can be used by the game as a rough way of representing an object for collision testing. It is then a matter of checking to see if the bounding shapes overlap, however, depending on how the object actually looks, a collision may appear to occur sooner or later than it should due to the bounding shapes being an approximate representation of the object.

Let's consider the advantages and disadvantages of using bounding boxes and bounding spheres (which are of course the 3D versions of bounding rectangles and bounding circles). A bounding box requires more values and greater processing time than a bounding sphere but can better represent some objects and has the advantage that it has eight points that can be used for collision testing, which is handy for doing front, back, left, right, top and bottom collision tests. For example, you could use a bottom collision test to check if an object has landed on another object or part of the level.

Bounding spheres are quicker to use and need less data but unless the object actually is a sphere then the bounding sphere won't represent it so well. Where speed is needed, bounding spheres come into play, such as to represent the body parts of a 3D animated object.

Regardless of what type of bounding shape you use, you can do more accurate and intense collision testing once you know that the bounding shapes have overlapped. That way, you can be sure if the objects are actually touching and only need to do the more time consuming, more reliable collision testing once you know there is a good chance that there is a collision between the objects because the bounding shapes have overlapped.

As for performing better collision testing, in particular between an object and the level graphics, ray to triangle collision testing can be used. This is a time consuming, but very precise collision test in which we check to see if an imaginary ray (think of a line radiating out of an object, or the mouse pointer) has intersected a triangle. You could then locate the triangle that caused the collision (if any) and work out if it forms part of a slope, for example, or look up surface information for that triangle (is it part of a slippery surface?).

There are ways to reduce the time needed to carry out ray to triangle collision testing, which in turn helps to keep a more steady frame rate. Firstly, if you have large levels you could split them up into tiles, which are parts of the level graphics (for examples, rooms of a house), each of which can have its own bounding box. If an object isn't within the bounding box of a level tile, then there is no need to perform more accurate collision testing. Another way to cut down on collision testing time is to not do ray to collision testing with the actual level graphics but with a hidden, low polygon version of the level which would also help with encoding surface information (for example, through colour since it's not seen).

In the above screenshot, which is from my game in progress MyDream, you can see a test level I've been using to check that the ray to triangle collision testing is working. The object, which is a sphere, is represented by a bounding box (I've used bounding boxes for all objects regardless of how they look since bounding boxes allow for slightly more detailed collision testing than bounding spheres). The numbered polygons ('1' and '3') are sloped shapes for checking that the game picks up the correct angle of the triangle that the object has touched (if any). It is common even in world famous video games (Sonic Adventure, The Legend of Zelda, and so on) to have test levels built in with certain platforms, slopes and objects, and often these test levels can be accessed with some sort of hack or code.

I had big problems using ray collision testing and ended up trying a grid based approach whereby an object's position is converted to a grid position in which collision objects (parts of the level mesh) existed. So, with each collision object (a wall, for example) taking the space of a grid cell it was easy to look up what could cause a collision. As well as being able to easily find collision objects I was able to further optimize by only testing parts of the level mesh that an object would actually come into contact with based on the type of collision. For example, if we are testing for a front collision (that is, an object touching something in front) there is no need to check surfaces pointing up or down.

As good as the grid based collision system was I did have a number of difficulties mainly because of the way objects were tracked in the grid. However, I used what I had tried out with the grid and came up with a different system that works very well and has given me the best collision testing I've done so far.

The first thing to do, after the level mesh is loaded, is to build a list of information for each face (triangle). The information that is stored is the direction each face is pointing (as an enum-UP/DOWN/LEFT/RIGHT/FORWARD/BACKWARD), its 2D bounding shape and whether it is a slope. Face normals are needed to work out this information so if the normals are loaded with the mesh then you can take the average of the vertex normals to get the triangle normal. Or you can calculate the normal using the triangle's vertices.

Next we check the direction of the faces by calculating the angle between the face normal and a corresponding direction vector and we do this by using the dot product which gives us the cosine of the angle between the two vectors. Rather than having to then use arccos to get the angle in degrees we can easily use the result from the dot product as it will give us 1 if both vectors face the same way or -1 if one vector faces the opposite way of the other vector.

So, we first get the dot product of the face's normal and the up vector (0,1,0) and if the result is 1 the face is pointing up or -1 if the face is downward. We then do similar for checking for left or right by using the right vector (1,0,0) and, forward and back using the forward vector (0,0,1). If we find that the face is not pointing in any of the tested directions then we say the face is a slope. What you have to be careful of, however, is when testing for the directions you cannot check the dot product for 1 or -1 exactly since it's a f/p number but instead much check for a range (e.g. 0.9 to 1.1). How much deviation you allow for will set what is considered a slope as with a small range faces will have to be steep to be detected as a slope.

The 2D bounding shape is a rectangle formed from the lowest and highest 2D vertex values so that we have a way to know the size of the faces regardless of the order of the vertices (we can't assume, for example, that the first vertex is to the left of the second vertex). To create the bounding shape we have to check each vertex and find the lowest and highest values but which axes values we need depends on the direction the face is pointing. For example if the face is pointing up then the vertex Y values should be the same (this is assuming the face doesn't form a slope). Thus the bounding shape for the face will contain the lowest and highest X and Z values.

It may help for you to render the level with coloured triangles to remind you which way the faces are pointing and to check that the correct directions are being determined, or you could display lines pointing out of the triangles to show the directions. It is also a good idea for debugging purposes to draw the triangle that caused a collision a different colour.

When we have the face information we can check for different types of collisions between objects and the level mesh but which collision types you will need will depend on how objects can move in your game. For my game, the player can jump and fall, move forward and back, and rotate left or right to change direction. Thus I have to test for below collisions with faces pointing up, above collisions with faces pointing down and front/behind collisions with faces pointing left, right, forward or back.

Because objects in my game can rotate on the Y axis it's difficult to work out the difference between a front and behind collision. If you think about it, an object that moves forward and touches a wall, but then rotates the other way will go from a front collision to a behind collision. To get around this problem, when I detect a front/behind collision I then cast a ray using the object's current direction vector, which tells us what direction the object is moving. I then test to see if the ray intersects with the triangle that caused the front/behind collision. If the ray does touch the triangle then we know the object cannot move in its current direction. However, if there is no collision this means the object has rotated away from the collision triangle or is trying to move in the opposite direction (forward/back) and thus can move. Do, however, make sure to test the ray with all triangles that form the wall otherwise the object will be able to go through half the wall.

Using collision meshes

The problem with creating collision information from the meshes seen in the game is that they tend to have a high number of polygons and we end up with a lot of collision data that is perhaps unnecessary, especially as we could simplify some of the shapes. For example, a cylinder could be converted into a cuboid which not only reduces the number of polygons but would also mean we would only have right-angled faces which makes collision testing easier. Remember, we need to do collision tests as quick as possible to keep the game running smoothly, but we also want to keep memory use as low as possible. If you can write routines which break a mesh into a simpler version then that will be very helpful but there is an alternative. We can load a mesh purely for collision testing purposes which is a simple version of the mesh normally seen in the game.

To create the collision mesh we convert the visual mesh into a simpler form using your modelling program and then load it with the mesh seen in the game. When we want to do collision tests we transform the collision mesh the same way as the object (scale, rotate and translate) and do the tests with the transformed mesh. A sensible thing to do would be to give the collision mesh a similar name to the mesh it represents so the filename for the collision mesh is automatically generated. For example, if a visible mesh was called Area_1 then the collision mesh could be called Area_1_col. If such a collision mesh file is not found then the game could either create the collision information from the visual mesh or use a default shape, such as a box. Sometimes you won't want any collision testing done if the player is never to interact with it, such as part of a level the player can't normally reach.

Although the collision mesh doesn't need to have any materials associated with it since it isn't normally seen, adding colour values or textures can be useful as it would be one way to specify the type of surface of each polygon. That is you could use green to indicate grass, for example, so that when the player touches that polygon a certain sound is generated. It would just be a matter of storing some extra data with the collision information to remember the type of surface.

Let's look at an example: I had created a pair of Belisha beacons for a Zebra crossing and in total they use 150 polygons, as seen below in 3ds Max:

Using collision information created from the above mesh results in significant slow down in the game and worse still as it is my game can't handle sloped edges such as cylinder-like objects, causing the player to just walk through the object. However, by creating just two boxes (see below) the collision mesh uses just 10 polygons (no need for the two bottom faces) and the collision works correctly.

Loading collision meshes does mean extra memory is needed as even with simple meshes we are essentially duplicating the models we see in the game. Having said that, if we were to create collision information from the high polygon models that would need even more memory so we are at least making a saving.

Steps

To enable objects to walk up steps first detect if there is a below and front (or behind) collision. If so, work out the height of the step by subtracting the top Y position of the face that caused the front/behind collision from the Y position of the face that caused the below collision. If the step height value is close to a certain predefined value then the step is small enough to walk up. To enable the object to walk up the step set the object's Y value to the front collision face top Y value. This is a very crude method but works well; note that going down steps the object will sort of fall down them.

Slopes

Going up and down steps is one thing but handling slopes is much more difficult. Below you can see a picture I put together to help illustrate how to handle slopes.

Firstly, we must work out what faces are slopes and store that information (for e.g. as a bool) as well as the face's 3D bounding shape along with the other face information. I determine a face is a slope if either its normal X, Y or Z is between 0.2 and 0.9 or between -0.2 and -0.9. Then, when checking for below collisions between objects and the level mesh faces we do an object bounding box to slope face bounding box collision test to see if an object is near to the slope face. At this point we could cast a ray down from the object and see if it hits a slope face and if so check if the distance is equal to the object's vertical speed in which case we have found a below collision. However, if we do that the object will fall through the slope if it moves up it although it will go down the slope OK.

Instead of doing the ray test we find out how far the object has moved from the start of the slope and then place the object vertically which has the effect that the object can move up and down the slope, as well as across, regardless of the slope's angle, and the object won't fall through the slope.

The first thing we do is create a vector that defines slope side A (see picture above) by subtracting the slope face bounding box max. and min. values on the Y and Z axes. Remember that we use the face's bounding shape so that we know the triangle's lowest and highest X, Y, Z values whatever the actual locations of the vertices in 3D space. Then we convert the slope side A vector into a unit vector by calculating the vector's length and then dividing its 2D values by the length. Next we find out how far the object under test is from the start of the slope which is as simple as subtracting the object's Z position from the slope face's bounding box min. Z value. The slope side A unit vector is then multiplied by the distance value which is then used to calculate the object's Y position by subtracting the X component of the resulting value from the slope face's bounding box max. value.

Note that this works well for a slope that points in a certain direction only; for slopes that point in other directions we will need to change the approach. For example, for a slope that is walked up or down on the X axis then the object's distance from the start of the slope will be on the X axis.

Better object-to-object collision testing

If is often necessary to know if two objects have come into contact with each other such as when the player walks into another object and must then stop moving. If the player, for example, can walk forward or back then we will need to check if there is an object in front or behind of the player. One way we can do such a test is to determine if the player's bounding box has overlapped another object's bounding box and if so in what way (in front or behind). While this works, it can cause problems such as the player walking through certain objects or even getting stuck.

An alternative, better method is first do a simple collision test between the two objects by seeing if they overlap in any way using their bounding boxes. Then, if there is a collision work out if the object is in front or behind the other object by using the same technique described in Computer controlled motorbike of how to see if a racer is in front of another racer. The difference is that a FOV of 90 degrees should be used instead of 60 but you may want to try different values.

Note that if an object is moving backward and you want to test for an object behind you actually check to see if another object is in front (that is, you use the same test as for detecting if an object is in front when moving forward). This is because when an object moves backward its directional vector points in the direction it's moving which is no different to an object moving forward while rotated 180 degrees.

Player to object interaction

I wanted to go over a not so simple example of detecting when the player interacts with a game object which in this case is a bus that the player can ride in to get about a level. If the bus has stopped at a bus stop and the player is near to the bus and facing it while pressing the action button then the player will get on the bus but how exactly does one detect if the player is by the bus' door and facing it? You could get the position of the bus' door as a sub mesh and do collision testing with it while checking that the player is facing the door but I came up with an alternative technique which I'll explain with the help of this image:

The black rectangle represents the bus with its doors being the smaller rectangle and the bus is enclosed in its bounding sphere, which in the diagram is the large pink circle (although the image shows 2D objects in the game world they are actually 3D). The small yellow circle inside the bus is the bus' origin (point in the 3D world) and the green arrow shows the direction the bus is facing which will always be the front of the bus. The first step to see if the player can get on the bus is to check that the bus isn't moving, next we have to check there is a collision between the player and the bus and if so we then see if the player is facing the bus at 45 degrees (red arrow) as that will be roughly where the door is. The key thing is to then find out if the bus's door side is facing the player and this is done by using the bus' direction vector rotated -45 degrees (blue arrow) which again helps ensure that the player is by the bus' door and looking at it. If all checks pass and the player presses action then the player will get on the bus. All these steps mean that we can detect roughly that the player is by the bus's door facing it, touching it and pressing the action button regardless of the bus' Y rotation and position.

What about always placing the player outside the bus on the door side when they get off the bus? To do this calculate the bus' direction vector -90 degrees so the resulting vector points in the direction of the door side. Then to generate the player position multiply a fraction of the bus' bounding sphere radius (e.g. 1/2) by the bus' direction vector -90 degrees on the X and Y axes only and add on to the bus' position (player Y position will just be set to the bus' Y position). This will always place the player outside the bus on its door side regardless of the bus' Y rotation (it would be a good idea to set the player's Y rotation to that of the bus'). The bus' bounding sphere radius is used rather than its bounding box as the radius will remain constant regardless of the bus' rotation, although the bounding sphere will of course be large enough for the whole bus which is longer on one dimension only so the player will end up a bit of distance from the bus when leaving it which is why we use a fraction of radius. A bounding box which transforms with the bus will have a varying size based on the bus' current rotation so would not be of good use in this circumstance if we wanted the player to always be placed a set distance from the bus when they get off.

Now for some example code to make things clearer; here is a snippet from the bus behaviour (line numbers added):

1. if (playerVars.busRidingI==-1) { //Make sure player not already riding in a bus

2. if (objs.at(objI).movingSpeed==0) { //Has the object stopped moving?

3. if (isObjectTouching(objI,playerObjI)) { //Collision with player?

4. if (isObjFacingOtherObjOffset(playerObjI,objI,plyTolerance,45.0f)) { //Is player facing this object?

5. if (isObjFacingOtherObjOffset(objI,playerObjI,busTolerance,-45.0f)) { //Is this object's door side facing the player?

6. if (playerIn.action) { //Action button pressed?

1. The variable playerVars.busRidingI will be set to the index of the bus object the player is riding in or -1 if the player is not riding a bus so this is a check to make sure the player is not already riding a bus.

2. Although you shouldn't normally test a floating-point variable for an exact value I know it will be zero when the bus has stopped as the function that update an object's position will set the speed to zero when the new speed is less than zero (i.e. completely decelerated).

3. A test is made to ensure the player has come into contact with the bus.

4. We test to see if the player is facing the bus with an offset of 45 degrees. The constant plyTolerance is 0.25 which means the player doesn't have to look at the bus exactly.

5. As with step 4 but we test the bus is looking at the player -45 degrees and with a tolerance (playerObjI,busTolerance) 0.95 as the bus is long and doesn't need to be looking exactly at the player.

6. Last check is to see if the player has pressed the action button and if so the player rides in the bus.

Let's have a look at the code which places the player outside the bus (the code isn't shown which checks the bus has stopped and the action button has been pressed):

1. D3DXVECTOR3 dirVec(0,0,0); //Object's direction vector

2. D3DXVECTOR3 forwardVector(0.0f,0.0f,1.0f); //Forward vector

3. calDirVector(dirVec,objs.at(objI).rotateY-90.0f,forwardVector); //Calculate normalized direction vector according to Y rotation

4. const float rad=objs.at(objI).boundSphereRadius; //Bound sphere radius


5. objs.at(playerObjI).x=objs.at(objI).x+(dirVec.x*(rad/2.0f));

6. objs.at(playerObjI).y=objs.at(objI).y;

7. objs.at(playerObjI).z=objs.at(objI).z+(dirVec.z*(rad/2.0f));

1 - 3. we set up a variable called dirVec to store the calculated direction vector of the bus -90 degrees.

4. We get the bus' bounding sphere radius.

5 - 7. Player is placed using the bus' direction vector -90 degrees using half the bus bounding sphere radius.

Conversations

In some games, the game objects don't have much to say, in others you can have conversations and select options such as different responses. The way I handle conversations is to have a list of messages; an array of strings such as:

string messages[]={"Hello!",

"Bye!",

"How are you?"};

Each message can be selected using an index value so 0 would choose the message Hello!, 1 would select Bye! and 2 would pick How are you? Next, we need to create the conversations by using commands which are nothing more than constants:

const int MESSAGE=0;

const int END_CONVERSATION=1;

And you can have other commands to do things such as to give the player more lives, make an object attack, etc. Then we have an array of integer values which make up every conversation:

int conversations[]={MESSAGE,1,END_CONVERSATION};

The example above is of just one conversation which will display the message Bye! and then end the conversation. Typically you will either have a delay or wait for the player to press a button before processing the next command (end the conversation in this example).

The MESSAGE commands expect a value to follow which is the index of the message to be displayed from the messages[] array. But the END_CONVERSATION command requires no extra data. You can use a switch statement to execute the coding for the current command (since each command is a unique value).

You will need some way to indicate if the player or someone else is talking, especially if the objects have no mouth animation or if there is only text and no audible speech. A simple way is to change the colour of the text to represent who is talking or you could do something more complicated such as use speech bubbles or something like that placed above the character's head. Let's not forget that in many games the player says very little or nothing at all.

To tell the game who is talking you could store as a global variable (assuming only one conversation can take place at once) the index of the object. But you will still need to include with the conversation data if the player or some other object is saying something, as in most games the index of an object is not known until the object is created.

We can expand the MESSAGE command to use an ID, such as PLAYER_ID for a message that the player is saying and NON_PLAYER_ID for anything said by someone who is not the player. For example:

MESSAGE,2,PLAYER_ID,END_CONVERSATION

Would mean the player says How are you?

Because I have put all of the conversations into one array as to avoid needing a number of different size arrays due to different length conversations, there is a slight complication. If you want to use an index value to pick a certain conversation you will need a look-up table (an array of integers) that contain the index of the starting point of each conversation.

If only one conversation can happen at any time you could use a global variable to remeber the position in the conversation. I use -1 to mean there is no conversation which is an invalid index value for an array but the program can check that before trying to look anything up. Typically you cannot move the player or make the player attack, etc while in a conversation so you will need some way to determine if there is currently a conversation or not.

Debug

What really helps when trying to fix a problem is to be able to display information on the screen as you're playing, games such as Sonic the hedgehog have been famous for leaving in such features.

So, you could show the values of variables that belong to the object that's causing problems and perhaps you might add the ability to modify the variables directly as you play.

Another form of debug, is to display the collision boxes, which can be toggled on or off by pressing a pre-defined key on the keyboard. If you have a function to draw a rectangle, just an outline's best so you can see the sprite within the box, then you shouldn't have trouble writing code to display the collision boxes. You could use two different colour boxes for each object, one for the visible size and the other for the collision box.

Command line options

Note: this section assumes you are using Visual studio and the .NET framework.

When you are programming something as complex as a video game you may want to jump straight to a certain level or have something enabled when the game starts. One way to do this is to have a file containing options which are loaded and checked when the game starts. Alternatively you could make use of command line arguments which get passed to the game.

If you have a look in your main form's source file you will find the main() function which is the main entry point for your game. The single input parameter to this function is an array of System Strings called args. Each command line option you provide will be a string belonging to the args array. Thus, it's a simple matter of checking the args array to see if any command line options were passed.

For my game, I allow a single command to be specified which can be one of the following:

TITLE: go to the title screen (same as specifying no command).

LEVEL: go to the level select screen.

1, 2, etc.: load the specified level.

In the main function I first check if there are any commands (if the args array's length >0) and if so I pass the first string from args to the constructor for my main form; the overloaded constructor simply stores the argument in a private member string once converted to upper case. If there are no commands then I call the main form's default constructor.

Then in one of the game's start up methods I have code to check the stored command string and then set/clear flags and do other tasks as needed to enable the various options.

To specify the game's command line options:

If using Visual studio go to Project->Properties…->Debugging: enter the command in the Command Arguments box.

If running the game from Windows Run box:

Click Browse and select the game executable; Windows will add the path to the Run box. After the path type the command line option and then click Ok or press Return.

Game saves

Most modern games let the player save their progress whether at set points in the game, such as when a checkpoint is reached, using a menu option or an actual object in the level. As well as deciding how to let the player save we need to also think about what information to save as well as how many save files to provide. For PC games generally there is no immediate limit on how many save files we can have and there is plenty of space to store data. Such data you will want to save are things such as player score, lives, health, level being played and items collected.

When the player starts the game they will want to pick up from where they left off so your game will need some kind of file select. If the save file doesn't exist then the game will need to create a blank save file with default values. For games that remember the player's position in the level when they saved you'll need to use the saved position for placing the player when the level starts unless it's a new save file in which case the player position comes from the level data file.

If the game has a level select it would be a good idea to use a game save file especially for the level select, perhaps with a player lives, health, etc. at maximum. With my MyDream game there are 8 save files that the player can use but if a level is loaded form the level select a hidden, 9th save file is used.

Graphics

Every video game has to have them, graphics are very important otherwise you wouldn't be able to see what you are doing. Much time is spent on the graphics, the designing, the placement of objects within levels and animation.

If you are using Windows then Direct3D is perhaps your best bet for getting objects to move about at speed and smoothly although there are other solutions, such as OpenGL. Direct3D can be a pain to use but when you get used to it you can put the routines into a class so that you won't have to worry about the low-level stuff any more and so that other games can use the class to access Direct3D.

Regardless of whether the game uses 2D or 3D graphics for the levels and objects, most games have some sort of HUD (Heads-Up-Display) for showing the player's lives, health, and so on. While it's best to use symbols to represent these values where possible (e.g., a battery icon that indicates the remaining power in the player's torch), more than likely there will be a need to display text.

To be able to display text at high speed with fancy effects, your best bet is to use a texture that contains the individual characters (letters, numbers, symbols, etc). If each character is the same size and placed at a set interval, only simple calculations are required to select the right part of the texture to get the chosen character; repeat this process to form entire sentences. As 256x256 is supposedly an ideal size for a texture (in terms of speed), each character could be 16x16.

If the text is in ASCII form then it would be a good idea to place the characters in the texture in the ASCII order, starting with the space character and ending with the tilde (~) character. Then there should be room for any special symbols after, that you will need to display, such as icons. How you access those characters may require you to add escape sequences to the string (an escape sequence typically begins with a backslash \ followed by one or more characters such as \xhh to insert the hex value hh into the string).

As well as handling characters to be displayed you will also need to take care of certain control codes such as line feed (a.k.a. new line) which can be used to move onto the next line. And since a texture is used containing the characters, special effects can be used such as scaling, rotation and changing the colour.

You could also include an optional background behind the text (perhaps as a texture) to help the text show up over the game world. If you do use a background behind the text it will need to be sized so that the text fits within perhaps with a slight border around the text. You could place a texture behind each character to acts as the background but for performance reasons it would be better to use a single background that is the size of a one character and then scaled to take up the space of the text plus a border if you want that. However, if a small texture for the background is made many times bigger it may not look so good but it's best to use a more or less plain background behind the text anyway as to let the text stand out over it. By making the background texture at least a little bit transparent it will make for a slightly less plain looking background since the game world will show through somewhat from behind.

How you actually render the individual characters and background to the screen depends on what you are using to display the graphics. For Direct3D you can use a sprite which is a 2D object that can use a texture and be positioned and rotated as needed. You only need one actual sprite object that you can use multiple times for each frame and then tell Direct3D to actually draw them.

The main thing is the text can easily be read so a bold font that has a style any can read is best. You could use an existing font for the texture or make up your own, as long as each character is placed at a set distance in the texture and is no bigger than a maximum size.

It's likely that the function to display the textured text will need many input values so it would be a good idea to use a structure that has default values (perhaps using its constructor), which is passed to the text function.

Let's look at an example of where textured text may be needed to explain where it would be required to handle unusual control values in the text. Say you had a pause menu but you wanted to indicate to the player which option is selected by changing its colour. If every pause menu option was displayed using a single textured string (so that a single background is placed behind all the pause menu options) and of the same colour, how can the colour of just one option be changed? The answer is to insert a control value into the text string before the option we want to change the colour for (the function for displaying the text will use that different colour only for a single line of text, i.e., up to a line feed/new line control code):

0x01FF208034

The 0x01 is the control value which tells the text function to change the colour only for the next line of text. Following that is the AARRGGBB colour value to use (0xFF208034). To place those values into the text string you may need to use an escape sequence. Note that 0x01 in ASCII is traditionally a control value anyway so it's not normally used to display a character like 0 or F, so we can use it as we please.

Textured text has many advantages but it requires a lot more work from the programmer as well as putting together the characters in the texture. But it looks so much better than non-textured text and can really help to add a little something extra to your game.

Graphical problems

There are a number of things that can catch you out and leave you scratching your head, wondering why things aren't looking the way they should. For example, if you have transparent objects you may notice that they don't render correctly; the transparent object has the wrong texture or some objects don't show through it. When it comes to transparent objects the Z buffer doesn't handle them correctly (at least not in Direct3D) and you must help it out by rendering non-transparent objects before transparent objects. Also, you may need to turn off Z buffer writes for transparent objects, but keep the Z buffer enabled.

Typically you will have a list of objects to render and they will probably be in an order that reflects the order they were created. So if that is the case for you, you will need to sort the objects in order of transparency before rendering them. You will only need to sort the objects again when there is a change, such as objects added or removed or if a transparency value alters.

In my game MyDream, there are two main modes-edit mode in which the levels can be edited, and non-edit mode when the game is being played (the level is 'live'). MyDream uses both objects and tiles with the distinction being that objects are complex entities that can move, rotate, interact with objects, etc and tiles are less simple objects that are mainly for visual and collision purposes. In edit mode objects and tiles are represented by template objects as in edit mode they are there mainly for visual reasons. It is fairly simple to sort the objects based on transparency so that they appear correctly.

When actually playing a level the template objects are used to create the real objects and tiles which use different structures as objects need more variables than tiles. So as there is a list of objects and a list of tiles the game renders the objects first then the tiles but if an object or tile is transparent they won't be in the right order as objects are in a different list to the tiles. Yes, I could sort the objects and tiles as one list but I could not see how this was possible using the existing container sort routine. The workaround I found was to use a list that holds the index of every object and tile along with a flag to say if the index refers to an object or tile. Then it is a matter of sorting this list while passing my own function to the sort algorithm which looks up the transparency values from the objects using the index values.

A game should not fail with a memory fault if a mesh or texture could not be loaded; check for valid pointers and log errors and display a warning to the user. Use a default mesh or some other way of visually indicating that a mesh is missing and for textures that could not be loaded use a default texture that makes it obvious there is a fault even if it's just a simple colour (bright pink is a good idea).

2D Game Graphics

There are three main types of graphics that feature in most games and they are the moving objects (sprites), the background which may be scrolling and the score, etc which usually consist of text and icons.

If you are any good at drawing then you might want to create the graphics 'by hand' to be used in your game or you could use existing art (if you have permission to do so). Originally I made the sprites and backgrounds using the art program Paint pixel-by-pixel but more recently I use the ray tracer Pov-Ray so that although the graphics are actually 2D when used in the game, they have a 3D look.

Graphic priorities allow you to display some graphics behind or in front of others but this can come at a cost, namely CPU time. The simplest but not the best way is to assign a priority value to every object and then when it's time to draw the graphics, check every object and display it if it has the right priority value. To speed that up you could sort the objects based on their graphic priority and then they would be ready to draw in order.

An alternate and more basic approach is to limit the game to only three priority levels which will probably be enough for most games. That way you could have, for example, the player appear in front or behind the other objects.

There would be nothing stopping you from changing the graphic priority values as the game is played (provided they aren't const) as to simulate certain effects.

3D Game Graphics

Please go to 3D Modelling.

Input

If you are programming a game that is to be played on a computer then you will need to assume that the player has at least a keyboard, probably a mouse too. A controller is usually perfect for playing most types of game but support for it has to be offered as an option, although there are a great deal of computer users who have a controller.

DirectInput can be used for interfacing to the keyboard, mouse and controller for fast input but there have been some recent changes to note. Usually, using Windows messages or keyboard events that encapsulate them, are fast enough for keyboard input, and the equivalent mouse events are fine for responding to the mouse. Although DirectInput can be used to communicate with all controllers, XInput was especially designed for Xbox 360 compatible controllers.

If you are going to support different forms of input such as keyboard, mouse and controller, then it would be best to program an input class that provides a universal form of input to the game while handling the different input sources. One way to do that is for the input class to update a virtual controller so that the game uses the same controls but are updated by the selected input device via the input class.

There are times when instead of needing to respond to a single key or button press we actually need a string of characters from the keyboard, such as for entering a name. With non-game applications we can use an input box but with games that is not usually convenient since the game renders directly to the window (or screen). A pop-up window containing an input box could be used but that can be distracting and requires an additional window to be created.

A better way which uses the existing window is to use a keyboard buffer which stores each key press from the keyboard. The keyboard buffer only needs to be a string but it's a good idea to limit its size to a sensible limit as to keep memory requirements low. For e.g., if the player's name is limited to 10 characters then the keyboard buffer only needs to be able to hold those few characters (if the keyboard buffer is not used for bigger strings). By using a string class for the keyboard buffer its size will grown or shrink as needed and characters from the keyboard can easily be added.

Likely string input from the player will only be needed at certain times so recording the key presses can be turned on and off when needed. When a new input string is required the keyboard buffer will need to be cleared which can usually be done with a clear() method of the string class or by setting the string to "". As for adding characters to the keyboard buffer, depending on the string class, it could as easy as using += with the character key code (ASCII value). The key presses only need to be recorded during the keyboard KeyDown event but you may want to filter for displayable characters only.

Level editing

(Updated: 8/10/9)

When you first start work on your game you might be able to manage with a few objects set up in your coding. But there will come a time when you will need to be able to edit levels and save your changes.

You could either use a separate program to edit the levels or you could integrate a level editor into your game which has the advantage that any changes you make you will be able to see much quicker. If really necessary you could always remove the level editor when you have finished the game, but if you do leave the level editor in, if you were to let other people play your game they could make their own levels.

However you are able to edit the levels you will need to save the level information for each level, perhaps to separate level files.Values that you will need to save for each level include such things as the size of the level, the type of weather, and what music to play. You will also need to save the starting values for every object that is in the level when it first starts (the player is most likely one of those objects). For example, you will need to save the position, rotation, and size for each object. This can be handled in one of two main ways; either save a script (series of commands) or just the actual values for each object. A script has the advantage that it can be edited with a text editor and can contain complex commands but each instruction has to be processed by your game. Saving just values is a lot more limited but means loading a level is very simple (i.e. just load the values and pass them onto the objects).

You may decide later on that you want to add more values to the level files or remove some but you may be faced with the problem that you've already created some levels and don't want to lose them. The solution (although you need to do it from the start) is to save with each level file a version number. If the game finds that the level file is an older version than what the new version of the game uses it can skip certain values. For example, say that in version 2 of level saving you added a value that sets the weather type, but in version 1 the weather was always sunny. If the game detects that it is loading version 1 of a level file it can skip loading the value from the level file and set it to sunny. Note that if you are using level scripts to save the level information you may have a different problem, that is, having to deal with old commands.

In 3D games especially you need to think about how you will split up large levels such as a hub that leads to other levels. If you have buildings the player can enter it would be a good idea to treat them as separate levels. In this case, when the player approaches a building to enter it the appropriate level is loaded which is inside the building. If you actually show the building door opening then you will need to show inside so you will either have to show the inside as darkness or a very rough approximation of the interior.

In my game MyDream there is a train station that the player enters using downward stairs in the level hub; when the player gets near to a certain point on the stairs the train station level is loaded. Because the loading times are very short the transition from the level hub to train station is almost seamless but if your game has long loading times you may want to use a graphical effect such as a fade in/out or a loading screen, or have the train station part of the level hub.

When we have loading points such as the example of stairs it can be difficult from a modelling point of view because you need to show part of the next level, like with the 'entering a building' scenario. There are sneaky things you can do, however, other than black areas, such as to have stairs at right angles. I had a level with a large indoor area and as you approached the entrance, part of the graphics in the distance would not render (as it was too far away) so I put in a right angle turn in the hallway so as you near the entrance you see a wall, not the indoor area.

My Kitty Wong Game Engine

(Updated: 8/7/9)

My Kitty Wong game engine started off as part of several 2D scrolling platform games before I upgraded it to handle 3D games. First I will talk to you about the 2D version and then its offspring, which handles 3D games. I programmed them all using C++ as classes.

Kitty Wong 2D Game Engine

The Kitty Wong game engine gets its name from the game that I made that it was developed for but since then I have re-used and modified it for other games. This is a good point to make clear that you can put a lot of effort into making a game engine which can then be used for other games with changes and even updates so that it's even better than before.

Let me point out first that there are three classes that make the game possible, and they are the main class, the DirectDraw (it's a 2D game) class and the game class which is the Kitty Wong game engine. The main class has to initialize the two other classes and talks to them; the main class tells the DirectDraw class what to display and the main class provides timing for the game class. The game class can also give information to the main class such as for providing debug data about the objects since the main class does not handle the objects directly.

There is actually a fourth class, but it's part of DirectX, and that's the DirectInput class. As with the other classes, the main class sets up the DirectInput class, and gets the state of the keyboard and passes the data onto the game class so that it can move the player, etc as need be.

Now onto the objects in more detail, which are the sprites, the moving parts of the game that interact with each other. Every object will need to have information stored about them so that the game can remember what they are doing.

Some obvious but essential variables are the 2D coordinates (position) called x and y (how ever did I think of that?) and also, width and height sizes that define the rectangle that the sprite fits into.

struct object {

int x,y;

int width, height;

That's all very well, but what about if we want the sprite to be invisible at times, or maybe some objects don't have graphics at all. Then we can include and check the state of the visible flag (it's always a good idea to label variables and functions that remind you of what they do and aren't too long, so thisVariableWhenSetDisplaysGraphics wouldn't be such a smart choice, for example).

bool visible;

Then there's the animated objects that use a number of pre-drawn frames to give the illusion of walking, jumping, etc. I store the frames that the sprites use in an offscreen buffer and align the frames horizontally for each object. When it comes to drawing a sprite, no matter if it's animated or not, it's a simple calculation to find the start of the frame to use from the sprite buffer. I use animFrame for each object to remember what frame is currently being draw, by multiplying it by the width of the sprite (assuming each frame is the same size) you get the start x coordinate of the current frame's position in the buffer for drawing.

int animFrame;

A game wouldn't be much if you could just walk through everything so collision testing is something you'll have to consider sooner or later. Sometimes we want a reaction regardless of the type of collision other times we need to know exactly what type of collision just occurred.

I define four main varities of collisions which are simply named top, bottom, left and right. I deal with collisions between two objects so if, for example, object A landed onto object B, the bottom of object A would be touching object B's top. With respect to object A, this would be classed as a top collision but if you take it from object B's point of view, it would be a bottom collision.

So, when an object falls because of gravity (if it is affected; if the Sonic and Mario games have taught us anything it's that platforms can float), we would want to check if that object had landed onto another object that acts like a platform or block. Once we have detected a top collision, we need to look at object B's data to see what type of object it is.

bool isBlock;

The isBlock flag, when set, tells us that it behaves like an average platform object and will stop objects affected by gravity from falling if landed onto it. If the flag is cleared, however, then objects will just fall past it as if it weren't there.

Another use of the isBlock flag is for left and right collisions; if the player is walking or running along and hits (a collision occurs) an object with the isBlock flag set then the player shouldn't be able to walk through it. Also, if the player's jumping and hits the bottom of a block in the sky then the player should start falling. Of course you might want different reactions, these are just suggestions.

While on the subject of collisions, a common theme found in countless video games is the attraction of picking up rewards or health items just laying there, ready to be taken. They may be rings, coins, rupees, stars or whatever, we need a way to determine what to do because of the collision. Perhaps there are rings to collect, rotating gold torus shaped items that were no way inspired by the Sonic the Hedgehog games and upon picking one up your score increases. One way to handle such a thing would be to use the isRing flag in the object structure:

isRing;

Then the coding could be something like this:

if (leftHit || rightHit || topHit || botHit) { //Check for all possible collisions

score++; //Increase score by one

Then we have those nasty baddies that make Sonic loose rings or Link hearts; we use the isGood and isBad flags to determine whether health is lost or some other bad thing happens because of a collision between two objects.

if (isGood && isBad) { //Object A is good and object B is bad

if (health>0) { //Must check that health isn't already zero

health--; //Take away good object's health

}

else { //Health is already zero

dead=true; //Object has been defeated

To do simple collision testing you can calculate the collision box of an object by adding the width and height to its position but there will be times when you'll want the object's collision box to be a dfferent size to the actual sprite. To do this we need four more variables:

int colOffX, colOffY;

int colWidth, colHeight;

Now the collision box is calculated by adding colOffX to the object's x position and colOffY to its y position. Then colWidth is added to the result of x+colOffX just as colHeight is added to y+colOffY. This allows the collision box to be a different size to what the sprite appears to be, you could even have only half of the object, for example, involved in colision tests.

These collision boxes are similar in concept to hot spots, i.e., an area of the sprite-smaller or larger-actually used for collision purposes. The mouse pointer that we're all familiar with has a hotspot; the top of the pointer is used for collision testing but not the bottom, otherwise it wouldn't seem right and could cause problems.

Now, what game would be complete without platforms and other objects that move by themselves, helping the hero to cross dangerous lands and reach areas that only a twin-tailed fox could access? You may have platforms that move horizontally or vertically, that change direction after a certain amount of time. To do this, I give each object their own timer (I'm that kind), you could have more than one timer per object but that depends on how advanced the objects you want and how much memory and CPU time you have to spare.

int timer;

int timeLimit;

bool timerEn;

bool timerOneShot;

Notice the four variables added to the object structure, starting with the timer which is basically an integer that starts with the value zero and is increased so as long as the timerEn flag is set, otherwise the timer will stop counting as soon as timerEn is false. As for the timeLimit flag, when the timer reaches this value, it'll reset to zero and starting counting up again.

The timerOneShot flag doesn't enable the timer to have one shot at getting things right, it's for deciding if the timer should count again once it has reset. If the flag is true then, when timer is the same value a timeLimit, the timer will return to zero but it won't start counting again because timerEn will be made false. The timer can be made to count again simply by setting timerEn to true once more. For the moving platforms you'll want to keep the timerOneShot flag as false but for other objects like special effects it would be best to have the flag set otherwise it may cause problems.

Let's talk more about those magical platforms; we can use a number of flags to decide how they should move.

bool moveHoriz;

bool moveVert;

bool faceRight;

bool faceUp;

If the moveHoriz flag is true the object will move left/right, changing direction whenever its internal timer reaches the time limit. To remember the direction it is travelling and facing (for objects that look different when they face a particular way), the faceRight flag does that job; if true the object is moving to the right but if false then it's moving to the left.

It should be no surprise that the moveVert flag causes the object to move up and down, changing direction just like with moving horizontal. The faceUp flag means that the object is moving upwards when true otherwise the object is moing down.

What should happen if both flags moveHoriz and moveVert are set at the same time? If programmed right it won't destroy the universe, instad the object will move diagonally. This is a time (a pun?) when it would be a good idea to have two timers per object (if we can afford such a thing or maybe they'll have a special offer of buy one, get one free) so that the object can move horizontally and change direction independently of when it is also moving vertically.

Kitty Wong 3D Game Engine

As well as working with objects that can be transformed (moved, rotated, etc) in 3D, this version of the Kitty Wong game class improved in other ways. Object behaviours are handled better and I created a simple way for objects with different behaviours to 'talk' to each other. However, there were still big problems that needed sorting, especially as the level editor wasn't integrated well into the game class. This prompted me to work on version 2 which aims to do all the hard work, leaving as little as possible to the other classes when it comes to updating the game objects.

For more information please see my game at MyDream.

Objects

The objects are the entities in a game that provide some form of interaction, including the player, items, etc. and usually (but don't have to) have some visual form. I recommend using the STL vector containers since they allow easy adding and removal of objects as well as helpful functions. You can create a structure of the variables that each object has and use that as the vector type.

For spawning objects, you could have a set number of objects that are initialized as needed or actually allow the container to grow, perhaps up to a limit. Either way you will need to know if a particular object is currently being used so each object could have:

bool active;

If false the object is not being used and could be used again as perhaps a different type of object, but if true then the object cannot be used as anything else. To illustrate, imagine the player had found an item; this object's active flag will have been set to true. But the player then picks up the item which is then removed, so its active flag is cleared to false, meaning it can be used as another object.

How the objects are spawned and deleted is really just a concept that helps us understand what is happening. If an object is removed, for example, the memory doesn't actually go anywhere and the object remains, but by changing the values of an object's variables it can look and behave in a totally different way.

If more memory is allocated every time an object is added then memory requirements can be kept low until there are lots of objects. The other way is to have a fixed number of objects which at least means a certain amount of memory will be needed and no more, but then you can never have any more objects. Either way you will still need to check through every object to see if a now unused object (active flag is false) can be used for the object to be spawned.

To be more flexible, it is usual to create new objects as the game is being played but all objects could be spawned when the level was created and then activated as needed. For example, if you had some kind of item container the item to be spawned could already exist but then 'come alive' when the item container is activated by the player. However, that would be restrictive in that only one item could be spawned from the container or you would have to have every type of item ready for one of them to be used, but they could be reused for every item container provided only one was ever needed at a time. Also, you must consider how simple it would be to make a level using either of those methods when using a level designer.

It is important that an object has as few variables as possible, that is, each object uses as little memory as can be. If a value never changes, such as the strength of an object's attack or its maximum speed it can be a constant value shared amongst all objects that use that specific value. You can create sets of values used by certain objects which can be referenced by each object using an index value.

Particle System

In many older games, particles such as dust, dirt and bits of grass were simulated using animated textures which represented the particles. While this approach is often satisfactory, there are better, more realistic ways of handling particles which involve creating, updating and rendering each individual particle. Such a system allows full control over every particle, meaning they can move and be transformed in other ways based on circumstances in the game world. For example, instead of particles just falling for a certain amount of time they can actually react to other objects or to each other.

Direct3D has a feature called point sprites which can be used to handle particles. Although not the best way to render the particles, point sprites are certainly one of the easier methods to use and give very good results.

A point sprite is a position which Direct3D automatically maps a texture to, saving you having to create the billboards (a billboard is a rectangle that always faces the camera to make it seem 3D) yourself. Because of this, Direct3D can render a great number of point sprites with the same texture at ease.

In the screen capture below from my game MyDream, you can see a demonstration of point sprites using a graphics demo mode built into the game. It shows off both rain and snow effects, totalling over 1000 particles. What you can't see from the image, unfortunately, is how smooth the particles move.

Although each of the particles is 2D, as they are textured billboards, they are placed in the game world with 3D positions so they will be affected by the camera, causing perspective effects. You can walk through the particles and see them rain around you in 3D.

The way I handle particles is by defining particle objects which act as a container for particles. For example, a rain particle object contains the individual particles and information about them. These particle objects can be added as needed, based around a supplied position which is used to generate the individual particle positions.

For rain and snow, each particle's starting position is generated by taking the supplied 3D position and then adding a random value within a certain 3D area, plus an offset so that positions are produce around the supplied position. The particles are then updated by adding a set amount to move multiplied by a random value, so some particles move slightly slower or faster than others. The size of each particle is randomly generated at the start to further add variation to each particle.

When a particle making up the rain or snow reaches a certain position it has a new position and size generated so the rain continually falls. So, instead of removing and adding the particle each time it is re-used which is more efficient.

Player Object

While AI objects tend to be complex if they have human-like behaviour, the object directly controlled by the player can be very complicated as we have to take into account the many conditions of the player and decide what to do in response to those situations. For even a simple game the player may be able to do the following:

Walk/run

Jump

Attack

Pick up/put down objects

Swim

Ride objects

For the above player commanded actions we then have to think about when these actions are allowed. So for e.g.:

Can walk/run if:

Player is on a solid surface.

Player is not in water.

Player has not been attacked.

Etc.

Thus we must think very carefully what the player can do and when they can perform the actions. Note that some very serious bugs of well known video games have been discovered because players have performed certain actions when the player is in a certain state that the developers did not test for (or did not bother to fix),

We can outline the conditions and the actions the player can perform by creating a flowchart which we can then use to program the main player update function. For my game MyDream I did not initially design such a flowchart at first which result in a complicated player update function that is somewhat difficult to follow. From the code that I've written so far I've created a flowchar, which is a backward approach, but I can then use the flowchart as a means to better understand the code, any potential bugs, and how I can improve the code.

Before showing the flowchart it's important to talk about what software is available to create flowcharts and in terms of online software Lucidchart (www.lucidchart.com) is a very good choice as it makes designing flowcharts very straightforward. However, the free account only lets you have 60 objects maximum (a limit that's easy to reach) and the paid for, less limited account options, requires an annual subscription which is not ideal if you will not be creating flowcharts often. An alternative is draw.io (www.draw.io) which is completely free with the only paid for options giving server integration. Although draw.io is not as easy to use as Lucidchart it's not too much of a compromise considering it's free to use with no limits. It has a decent amount of shapes and supports impotin/exporting various file formats and has integration with Google drive/Dropbox/OneDrive as well as support for local device storage.

If you have not used draw.io before be sure to check out a tutorial such as this one:

https://youtu.be/Z0D96ZikMkc

Now let's look at the flowchart I did for my player update function which shows how it is currently structured:

MyDream Player Object Flowchart 1V66.pdf

Remember, I made the above flowchart from the code I currently have in my player update function rather than doing the flowchart first but it illustrates some interesting points. Firstly, it highlights the number of tests that must be done to determine what actions the player can perform, what animation to use and other ways the player is affected. Ideally, the player update function should just mainly consist of function calls but while there is a lot of code held in other functions (Update player in quicksand, Update player very cold, etc.) there is much more code that needs to be moved to other functions so that the main player update function is much more readable and manageable. Once that is accomplished we can have a flowchart for each main player update function. Again, this is why it's so important to do the planning first so that we have a well thought out structure that can then be expanded,

There are 2 checks for the player losing all health (player is dead) which I've highlighted in yellow along with the checks/processes that follow, that both end in the player update function terminating. The second check is redundant since the only time the player can be killed after the first check is if the player has touched a death box (an invisible barrier) and that ends in the main player update function ending. Again, had I done a flowchart first I would have avoided repeating code although you could argue it's better to do certain checks multiple times should a bug cause the first check to miss a condition.

We can't escape that when updating the player there are many condition checks we must do with the large decision triangle toward the end of the flowchart (Player not jumping/moving/etc.) being a good e.g., and should really have its condition checks separated but would have taken up a lot of space in the flowchart. There are better ways we can handle the player condition tests which we'll explore in other sections.

Modifying the flowchart we've already seen, the updated flowchart can be seen below. The main flowchart is on the left and I've moved some of the logic to its own sections to the right, represented by the green boxes on the left. I've also made a couple of fixes where I had made some mistake in the previous flowchart as we should exit if the player is dead or riding a bus. I've also re-worded the last main decision shape (Player not performing...) just so it reads better.

MyDream Player Object Flowchart 1V67.pdf

Now the main flowchart is a bit more readable with only very simple logic remaining and demonstrates a better structure.

So while the above flowhcart still needs some work to it I hope you get the gist of how the flowchart should be laid out; complex code should be placed in individual functions called from the main function. There should be very little logic in the main flowchart allowing the code to be read easily and flow well when reading.

Player Variables

While your game may have many different objects that interact with each other usually the player object will need additional variables which can be placed inside a structure. These extra variables include such values as the current number of lives the player has along with the current health as well as other data. The reason for these supplementary variables is not just that the player will have extra information that needs to be stored (e.g. lives) but also because common values (e.g. object position) can be more conveniently retrieved from the player variable structure than the player object (at the cost of duplicating the information).

To go into more detail, part of the problem can be the way the player object is placed in memory. If the player object is always (for example) the first object then it's a lot easier to access the player object as no pointer to the player object is needed. However, if the player object can be at a different place in the list of objects depending on which level is being played (or due to other circumstances) then a pointer will be needed to keep track of where the player object is in memory. Rather than keep using a pointer to access the player object variables they can be accessed once each update and then certain variables can be copied to the player variables structure and used elsewhere by other functions.

The way to think of the player variables structure is as extra data attached to the player object which may link other objects to the player. For example, if they player can drive a car, while the player is driving it may be necessary to store in the player variables structure an index to the car object. This way we know when the player is driving (because the car object index is valid) and the car object can quickly be accessed to do collision testing and whatever else is needed. The way I use an index variable in a scenario like the one described is to set it to -1 to say the index is not valid and use 0 or higher to point to an object, as 0 is the first object index. It is very important when creating a level or restarting an event to reset the player variables as needed (for e.g., health may be reset but not lives).

Reflections

When we come across a mirror or other shiny surface we expect to see reflections of objects located in the surrounding area. Adding reflections to a game helps convey the type of surface of an object and could even be used as an aid to alert the player of something approaching. Whatever the reason, there are 2 main methods for generating reflections each of which have their good and bad points. Starting with the traditional way, you can render all objects a second time but at an inverted position from the reflective surface and with an inverted appearance. This technique is fairly easy to implement but requires space for the reflected objects to be placed so in the case of a mirror room, for e.g., the room would need to be twice as big on one axis than where the player would be able to roam. You also have to make sure no reflected objects go through surfaces, which can happen if an original (not reflected) object goes through a surface.

You can also create reflections by rendering the scene to a texture from the point of view of the reflected player (or whatever object the camera is on). This texture can then be used on any objects that have a reflective surface but you must do a new render to texture with a different position/angle for every reflective object. On the plus side the reflection is only on the surface of the object so it is ideal for small objects such as a dressing table mirror.

While a texture reflection is very useful I will be going into further detail on the first mentioned technique where we render objects a second time to create the reflections. Let's think about the player standing in front of and facing a mirror on the Z axis in a large room where there are also other objects in view. The mirror is simply a large box type mesh with a little bit of transparency so we can see the reflected objects behind the mirror.

The player will see the player reflection staring back and as the player moves away from the mirror the reflected player goes into the distance (the 'mirror world'). So we can work out the reflected player object position by calculating the distance from the player object to the mirror on the Z axis and then adding that to the mirror Z position to get the reflected player position; X and Y would be the same. But the reflected player needs to also be rotated on the Y axis by taking the real player object's Y rotation from 180 so that the reflected player is facing the correct way based on which way the player is rotated.

It's not just position and rotation that needs to be inverted, so do the textures for the mirrored objects. We can easily flip textures by inverting the UV coordinates (i.e. 10 becomes -10) and to get to the UV's without too much difficulty we can take advantage of the UV coordinates being passed to the vertex shader. In the vertex shader we check 2 flags - one that flips the U coordinate and the other that flips the V coordinate - and inverts the UV coordinates as needed. Then it is just a matter of updating the 2 UV flip flags in the shader based on the mirror axis, remembering to reset the flags before drawing the 'normal' objects.

We can have mirrors on different axes (that is, the axis that goes through the reflective part of the mirror) and we have to transform the reflected objects differently. To simplify things, we can have just one mirror object in a level, store and index to it for quick access and keep a record of the mirror axis. When rendering the reflected objects you can render only objects that are near to the mirror and there is no need to render the mirror object a second time. If the player isn't even facing the mirror or it is out of view we can skip rendering the reflections altogether.

Another type of surface that can have a reflection is water and typically in a game the water will be just a textured box that is transformed to show movement such as waves. We can get away with only rendering reflections in water on the surface only so that when the player goes under water we can stop the reflections. To detect the player has gone under water we need to do more than just check the player's position against the water box, we have to take the camera into consideration. By performing the inverse of the current view matrix and then accessing the ._41, ._42 and ._43 elements of the resulting matrix (Direct3D) we will have access to the current camera position taking into account rotation. It is then a simple matter of comparing the camera Y position (._42) with the top of the water box Y position to see if the camera is under water.

Scrolling

Games like Tetris and Pac-Man managed well enough with a static screen but most 2D games scroll horizontally, vertically or in both directions. Usually, the screen doesn't scroll until the playable character reaches the middle of the screen but in some levels of a game the scrolling may happen automatically as to hurry the hero on his or her way.

There are two main ways to handle scrolling and which option you go for will pretty much be down to how much memory you have to spare and perhaps what is easier for you to program. If you have enough memory, you could draw all the graphics to a playfield bigger than the screen and then scroll the playfield. The other way is to draw the sprites and other graphics when a certain scroll value has been reached.

Whenever the hero reaches the middle of the screen and moves right you increase the horizontal scroll variable until he or she reaches the end of the level. And when the playable character is moving to the left while at the middle of the screen you decrease the horizontal scroll value until the begining of the level is reached. However, an alternate method is simply to calculate the scroll values from the player's position so that he or she is always in the middle of the screen or window but you will need to adjust the values as to not show beyond the start or end of a level.

By adding the width of the screen to the scroll value you get the range of x position values that are checked against the other objects'x positions to see if they should be diplayed. To do vertical scrolling you need another scroll variable, of course, but the principle is the same.

You have the option to move and update the objects while on or off screen if you want which is more realistic but may cause slowdown. If you update the objects only when they are on screen then, although the game will run smoothly (or it should) objects may appear to suddenly come to life when they become visible.

I have to confess that I found vertical scrolling harder to program than the horizontal scrolling and I'll explain why. The horizontal origin (zero) is at the left of the screen which I choose to be the start of the level, as the player moves right the horizontal scroll values increases. But the vertical origin is at the top of the screen yet I wanted the start of the level to be at the bottom so that as the player moves up the vertical scroll value increases. So that had to be reversed which means that both the width and height of the level are defined as positive values which is logical.

Weather Effects

Rain or snow, for example, can really change the mood of a level and add to the graphics to create a more familiar look; it's not always sunny in the real wold (especially if you live in England). It's not difficult to create weather effects but you will need a fair amount of memory to remember the position of each rain or snow particle. At the very least you will need an array of positions for each particle; you could use a structure of the location variables.

Whether it's rain or snow you're simulating the basic idea is to move each particle down until it reaches a predefined Y value. This is when you randomly pick a new Y value for that particle which by chance will be near the top of the screen; you could also generate a new horizontal position as well. If you don't randomly choose a new position for each particle the rain or snow just won't look right.

The rain particles can be displayed simply as lines coloured blue or grey (which is how most games draw rain), and snow can be just circles coloured white, of course. An alternative is to use point sprites which are basically billboards but many of them can be rendered without a big impact on frame rate as they use the same texture. To seem a bit more 3D you can alter the length of the rain particle lines or the size of the snow circle particles whenever 'new' particles are needed. So you'll need a size variable for every particle as new particles aren't all generated at the same time.

Another extra is to change the speed of all particles after a predefined amount of time. One moment the rain could be falling slowly and the next-fast, giving the impression of a downfall. And even better would be to stop the rain or snow now and then, or change from rain to snow. Another thing to consider is where in your game world the rain or snow is located-is it in one place, or does it follow the player (which is good for simulating rain or snow over a wide distance).

You may want to have a look at the Particle system section to read up more on handling weather and similar graphical effects.

Water Boxes and other boxes

Water is a common feature in many video games and in particular, the player having to lower or raise the water level to reach certain places or to uncover items. Water can be handled as a simple box but when placed correctly along with the level scenery, the water will appear to have taken on the shape of the landscape. However, if the camera is not restricted, it may be possible to see that the water is just a box, a problem with older games.

In the above screenshot from my game in progress, MyDream, you can see a level that I haven't quite finished but I thought shows well how the water is nothing but a box. If you look at the top right you should be able to see the edges of the water box yet at the shore and around the island the water appears to surround the beach areas as you would expect, as if the water was a more complex shape. What you can't see from the image, is that the water continually raises and then lowers itself slightly to bring the water to life. That is done by scaling the water box on the Y axis but with its origin located at the bottom of the water box so that the size change is only visible at the top. If the water box's origin had been at its centre, it would scale both at the top and bottom, which wouldn't quite look right.

The water box can be loaded as a simple cube mesh (or be generated by the software) and scaled as needed. If the player or any other objects react to being in the water (e.g. the player can swim, player moves slower, etc.) then collision testing will need to be done between the objects and the water box. In some games water kills the player instantly in which case only a simple bounding box collision test would be needed. In other games, the player can wade through water or swim through it. One way to decide if the player is able to wade or swim in the water is by checking the height of the water box in relation to the height of the player. If the water box's height is below a certain amount compared to the player's height then the water would be too low to swim in. However, the water box's other dimensions would also need to be compared to the player to make sure it's big enough to swim in.

To help give the water 'life' its surface texture can be animated (translated) and particle effects can be added when the player swims or wades in the water or jumps into it. Another useful effect is to have water drip from the player when they exit the water and to have the player model more shiny than normal to give the appearance of wet skin and clothes. You could also have the player leave behind wet footprints after coming out of the water.

As well as water boxes there are other boxes you could add to your game such as ice boxes, sand boxes and fire boxes. With an ice box, you could have the player slip along which can be done by decreasing the player's acceleration speed (so it's more difficult to walk) and by decreasing the player's deceleration speed (so the player continues to move even after no control direction has been pressed). You could also have the ice box lower the player's health if they spend too much time on the ice box.

For the sand box you could have it act as quicksand so that the player begins to sink if they keep still too long or after a set amount of time whether the player is moving or not. After the time delay, start to make the player sink up to a certain point and slow the player down (decrease the player's acceleration speed and increase the player's deceleration speed) so it's like they are wading through the quicksand. To make the player sink in the quicksand it may not be as simple as changing the player's position as that would for my game cause the player to fall through the quicksand box to the bottom because of the effects of gravity. What I had to do was disable gravity for the player while in the quicksand box and then I was able to update the player's position as needed and then re-enable gravity once the player was out of the quicksand box.

You could have the player sink up to a certain point or if they sink too much they are killed. Either way it's a good idea to have some way for the player to escape the quicksand, such as by repeatedly pressing the jump button. As an added effect, when the player comes out of the quicksand you could change the model's textures to show the quicksand on the player which fade over time so it looks like it comes off.

With a fire box it could harm the player when they come into contact with it or even set them on fire if they spend too much time on the fire box. There are all sorts of other boxes you could have such as ones that cause sudden death should the player come into contact with them.

If your game is to have multiple boxes of different types then you could use the one box mesh and change its textures accordingly. One way to do this is to have a texture-less box mesh which when rendered has the appropriate textures applied, which were loaded separately. An alternative method if the boxes are only to each have one unique texture is to load a box mesh that has a different texture on each face for each type of box. Then, when a particular box is to be rendered one of the textures that was loaded with the box can be selected and used for the entire box. The advantage of this approach is that the textures are loaded with the mesh but they must in order, since the correct texture will need to be selected.

Picking up and carrying objects

It's a common task in video games to be able to pick up an object, such as a box, carry it somewhere and then drop it, perhaps on a switch. While this is not too difficult to do, it does get a bit tricky when it comes to showing that the player is holding the object, in the case of 3D games.

Firstly, the player needs to be able to pick up an object, which in this example will be a box. The box's behaviour will check if the player is touching it and facing it and if so, wait for the action button to be pressed. When the action button is pressed, the box will store its object index into a variable so that the game knows that:

1. An object is being carried.

2. The object that is being carried can quickly be accessed.

The way I handle object index variables is by storing a value of -1 to mean no object (in this case no object is being carried) and any value > -1 to refer to an object's index (in this case, for example, 5 means the 6th object is being carried).

While the player is carrying the box it needs to be placed in front of him/her and about halfway up. The player and box bounding box values can be used to position the box as needed. However, the problem is when trying to always keep the box in front of the player as she/he turns you may find the box rotates oddly or is positioned incorrectly.

The workaround is to hide the box object and disable collision testing on it while the player is in carrying mode; the box object is made visible and its collision testing enabled again when the player exits carrying mode. Then, while in carrying mode the box mesh is transformed with the player using the following formula:

scaleMatrix*tranMatrix2*rotationMatrix*tranMatrix

Where:

scaleMatrix is the box's scaling matrix

tranMatrix2 is the box's relative position from the player (using bounding box values) as a translation matrix

rotationMatrix is the player's rotation matrix

tranMatrix is the player's translation matrix

What this does is rotate the box about the player so that it always appears in front of the player. Note that if the bounding box values change as objects rotate you may see some shifting in the placement of the box.

When the player decides to put the box down by pressing the action button, as previously mentioned the box object's graphics need to be re-enabled along with collision testing. But in addition, you will need to update the box object's position so that it is placed in front of the player and the rotation so that it matches that of the player's at the time of putting the box down.

Riding objects

If you want the player or AI to be in control of a vehicle then one option is to have the driver positioned and rotated the same as the vehicle, however, like with the situation of the player carrying a box (see above section) it can cause rotation problems. Thus, we can use a similar technique of transforming the rider along with the vehicle so that they move and rotate together. We also hide the driver's graphics and disable its collision while riding and then turn back on its graphics and collision when it gets off the vehicle.

Transforming a driver with a vehicle avoids the need of having to program object behaviours to position and rotate driver objects with the vehicle. Also, it removes the problem of the driver stopping the vehicle from moving because it's detecting a collision with the driver-whether this will be a problem depends on your programming. You could alternatively disable collision testing with driver objects.

Climbing

To help the player get about the levels you may want a ladder or similar object for reaching those higher places. While you would think that the basic mechanics of a ladder shouldn't be too difficult to program you need to get right the player's climbing animation and synchronisation with the rungs. If you are to have ladders that can be rotated on any of the three axes then movement of the player along a ladder can get complicated.

Firstly, the basics-when the player is touching the ladder while facing it and a button is pressed the player is positioned on the ladder. You will probably at least want the player to be able to grab on to a ladder from the top or bottom. To determine where the player is in relation to the ladder you can use the ladder's bounding box. We also hide the player object and turn off its collision testing and do the reverse when the player gets off the ladder.

While the player is on the ladder, pressing up moves the player up two steps and pressing down moves the player down two steps; pressing the action button releases the player from the ladder. The reason the player advances by two steps each time is so the complete climbing animation plays each time in which both legs are used.

When moving the player up or down it's very important to make sure that not only the player's feet are still in line with the steps when the movement is completed but also that the movement starts at the right moment. I found the movement looked best when the movement was delayed by one key frame, however, on the downside it does create a delay.

So that the player is correctly rotated with the ladder we can use the technique from the 'Picking up and carrying objects' section but have the player transformed about the ladder. In this way, any player Y translation will result in the player moving up or down the ladder regardless of how the ladder is rotated. So that we can calculate the player Y position the game remembers the player's current step which also makes it easier to detect when the player has reached the top or bottom of the ladder. This step count can easily be scaled to the player Y position, however, so that there is movement between the steps you will need a sub step counter also or just a single counter which is then divided up by the number of sub steps.

So, while the player is on the ladder the player object is hidden but the player mesh is rendered with the ladder. Most likely you will want the camera to follow the player up or down the ladder and when the player gets off the player object will need to be correctly positioned. Fortunately, we can get the player mesh position from the final matrix used to calculate the player and ladder transformations by accessing the matrix's ._41, ._42 and ._43 elements. This position can then be used to update the player object so that the camera position is updated and ensuring that the player object is in the correct position for exiting the ladder.

It's a good idea to detect when the player has reached the bottom or top of the ladder and then allow something different to happen. If the player reaches the bottom of the ladder and you try to go down further you could either stop the player from going any further down or release the player. As for reaching the top, which you'll want to be before the last rungs of the ladder (otherwise the player would be holding onto the air), it's a little tricky to get the player to continue going up and then over the ladder. Instead, you could let left or right be pressed which would mean the player is released from the ladder and then placed on either side of the ladder.

Dreamcast Game Programming

Please go to Dreamcast Game Programming.

All content of this and related pages is copyright (c) James S. 2007-2019