2/05/07

Discuss solutions to last week's project

Wood's solution is Square Racer.

Game Update and Render Discussion

It didn't require any knowledge of the update/render system to finish last week's assignment, but it is an important process that should be understood.

		case WM_TIMER:
			int tick;
			int updatesNeeded;
			
			updatesNeeded = 1;
			tick = GetTickCount();
			tickDifference = tick - lastTick;

			// work on updates per second, not frames per second
			if (tickDifference>TIMEDELAY)
			{
				tickMisses = tickMisses+tickDifference;
                if (tickMisses>TIMEDELAY)
				{
					updatesNeeded = tickMisses/TIMEDELAY;
					if (updatesNeeded>MAXCATCHUPS)
					{
						updatesNeeded = MAXCATCHUPS;
					}
					framesSkipped += updatesNeeded;
					tickMisses = tickMisses%TIMEDELAY; // save the leftover
				}
			}
			lastTick = tick;

			iFrameCount++;
			
        for (i=0;i<updatesNeeded;i++)
        {
          // this is the update code (NO SCREEN DRAWING!)
          iPosX = iPosX + vX;
          iPosY = iPosY + vY;
		}
		
		// No repaint the screen of offscreen area
		updateOffscreenArea();

This is the update section of our C/Win32 game in F15. It's working on updates per second, not frames per second. This is to allow for slow (or faster) machines, so that the actual game runs at the same speed on every machine. On a very slow machine the time to draw the screen will be the limiting factor. So, we keep all the positioning and game information separated from the display and update that each time our timer fires. This allows up to do multiple positional updates when the machine has been away longer than a single frame. These positional updates are computationally 'cheap' and we can do many of them in a single timer event while the drawing code is computationally expensive. Once all the positions have been calculated, we update the offscreen display once. Upon the next WM_PAINT message, this offscreen display will be copied to the screen. In general we will be skipping frames periodically, but we should not see any significant game slowdown which would occur if we had to repaint the screen (or offscreen area) on each and every update since painting a complex screen can take over 20ms.

This code is crude and there are still some problems with it. One easy one I can see is that on a very fast machine, the offscreen bitmap will be repainted even though the time delay is less than required for each frame.

A second problem is that there should also be a maximum number of frames that can be skipped. For machines that go to sleep waiting for a network or drive timeout skipping hundreds of frames could be a problem. This could cause the game to do some very strange things after the timeout and the application returns to activity. Limiting the number of updates that can occur will still cause a 'jump' in time, but should not be a serious detriment to game play.

Discuss Image Maps

The image to the right is an image map used in some of my samples for last year's class. It shows an sheep oriented in 8 different direction in a single image. Each individual sheep is placed in a 32x32 pixel area.

In Win32, BitBlt is used to display a bitmap image. Here is the definitition of the BitBlt function:

BOOL BitBlt(
    HDC hdcDest, // handle to destination DC
    int nXDest, // x-coord of destination upper-left corner
    int nYDest, // y-coord of destination upper-left corner
    int nWidth, // width of destination rectangle
    int nHeight, // height of destination rectangle
    HDC hdcSrc, // handle to source DC
    int nXSrc, // x-coordinate of source upper-left corner
    int nYSrc, // y-coordinate of source upper-left corner
    DWORD dwRop // raster operation code
);

Complete details on BitBlt can be found on MSDN.

Using something like BitBlt we could display an individual orientation image within the image map..

    int cellNum = 3;
    BitBlt(hdcDest,screenX,screenY,32,32,hdcSheep,0,cellNum*32,SRCCOPY);

screenX and screenY are where you want the image to display on the destination/screen.

32,32 is the size you want to be displayed. In this case, one sheep is 32x32 so we are limiting the size to one sheep image.

hdcSheep is the actual bitmap loaded with LoadBitmap.

0 is the left hand column of the sheep images. Since there is only one column this is always 0.

cellNum*32 calculates the row to display in pixels. In this case 2*32=64 which is the third sheep which faces EAST..

 

Torque Game Builder Introduction

Remember the goal.

Create fun games using whatever platform is best for our specific game or required by customer contract. If you are forced to use a specific platform then you may have to tailor the game to that platform.

80% rule

Remember, 80% of the battle will be learning a new tool or language. Once we understand the tool it will be much easier to create the actual game or application. For a first application in a new language you should expect to spend at least 80% of your time just fighting the quirks of the new tools. So if you think an application or game will take a certain amount of time in a language you already understand, at a minumum you should add 80% to your estimate when using a new language or tool set. This is not a scientific number, just an estimate.

Torque Overview (Wood's walk through)

I'm going to try and give a walkthrough of TGB using the outline below.

Torque Game Bulder

A 2D game engine. This will be a good way to get familiar with Torque Script before we proceed into the 3D engine. We will build one game using this tool, then move to 3D.

The Game Builder includes a networking engine, but I don't recommend building a networked game using the Game Builder unless you have source or two separate computers. The standalone version of TGB will only allow one instance to be run on a specific computer. The only way around this is using a version compiled with a debug setting and we do not have source to TGB. Don't plan on building a 2D networked game in this class. We'll deal with the networking in the 3D. This is a disappointing chioce the GG folks made when releasing TGB as they should have included a debug version of the TGB application.

Note: As of TGB version 1.5 they have said this is no longer an issue and you can run multiple clients on the same machine. 1.5 has some really nice improvements.

Torque language refernce

If you have language issues, the yellow book has the best reference in chapter 4 pages 97-142. Nothing I have found online compares to that chapter in the book.

NOTE: I've actually banned this book from my collection. I kept coming back to it over and over and I've found it to be absolutely unreadable and not worth my time..

Difference Between Levels and Projects

The TGB is both a level and project editor. To build a complete game you will probably have many different levels and load each one using Torque Script at the appropriate time.

Projects in Torque are stored in the c:\program files\TorqueGameBuilder\games directory. Creating a new project will automatically create a directory tree in the games directory using the name you used. I sugges keeping spaces out of your game name, but you are welcome to shoot yourself in the foot if you would like. I don't mind as it is a good learning experience.

Projects contain many levels. All the editing you do within TGB is done on a level by level basis within a specific project.

Project Directory Structure

Inside the project folder is a main.cs script file. Open and look at it. Anytime you create a new script, you will have to add it to this file using exec("./gameScripts/myfile.cs"). Make sure you use proper case. Windows is not case sensitive, but if you build a great game and want to release it on Apple or Linux (yes, the games you create can be built on those platforms), then you will not have to debug a bunch of script problems due to naming differences.

The gameScripts directory contains all the scripts for your game. You should not put any of your scripts in any other directories. The script files have a .cs extension. You will see files with a .cs.dso extension. Torque will compile your scripts to a bytecode format which is what you will release with your game. This keeps the source code private in your released games.

The data directory contains all the game specific information, like audio, images and levels etc.

The gui directory contains game menus. We will do more with these in the engine, but may do some gui editing within the TGB depending on the time we have.

Level Editing

When you are placing objects in the graphical area and changing their attributes, you are actually changing a specific level. The levels are saved in the data\Levels directory.

Restarting TGB on every script change

It seems that every change to a Torque Script in the TGB will require a restart of TGB. The 3D engine is better about this. It's a quick start, but still annoying. Just get used to it. All tools have annoyances. If you made a code change and it doesn't work, make sure you restarted TGB, it may be that the TGB is still using the old version.

In some informal testing I found that TGB will only compile scripts on startup. Any changes to scripts will require a TGB restart which is very annoying, but not surprising. All tools have annoyances.

Three basic modes/tabs

Create has all the various game elements you can drag into your game area.

If you want to edit the attributes of a given object in the game area, switch to the edit panel and click on the object. If it is 'under' another object multiple clicks will drill down to the object.

The project tab shows the various objects in the current level.

 

The basic mechanic is to drag stuff off the Create tab, switch to the Edit tab and modify the properties of the object instances.

Object Edit properties

Every object has hundreds of different properties that you can change or manage. Torque includes detailed documentation on each of these properties.

Scene object includes things like position, layer and grouping.

Scripting allows you to tie a specific object to a specific script object type. All scripts are edited outside TGB in a separate text editor. You probably have a favorite, use it.

Collisions automates all sorts of behaviors based on collisions and intersections including possible call backs to Torque Script. This takes a lot of the drudgery and difficulty out of game programming.

Physics allows you to change behaviours like gravity on an object by object basis and include things like mass, velocity and force. Another feature that takes a lot of the drudgery out of game programming.

Mounting is just the grouping of multiple objects.

World limits allow a lot of flexibility between objects, physics, collisions and scription. We will discuss this below.

Dynamic fields allow you to add specific fields that are accessible to the scripting. You can change these fields within the game builder to give specific object different properties.

World limits

Holding your mouse over an object will pop up a quick link menu. The most importanted are collision polygon and world limits. Select World Limits.

This will zoom out of the game and show the world limit area for a given object. This boundary is used to send events to torque scripts when the object reaches the specified limits. This makes automated behavior very easy in that you only have to write code for event when the object reaches a specific point.

NOTE: I got stuck here and it took a while to figure out. When you are in the world editor (or the collision polygon which we'll discuss next) you are in a TGB editor special mode. To get out of this mode simply click the arrow tool that doesn't look like it is active and doesn't look clickable. Yes it's odd, but it works.

Collision polygone editor

Use the quick link menu and select collision polygone.

There are four different modes for collision detection that you can select under the collision properties. The most usefull is the collision polygone which you can edit. Simply click out the vertices and move individual vertices into a polygone that encompases the object.

Note: The polygon must be a Convex polygon as that is what the engine requires. The math for concave polygon intersection is much more difficult (slow) and not required very often. If you are clicking and a vertice is not added or dragging and a vertice does not move, you would probably outside the bounds of a convex polygone.

Again to exit the editor simply click the arrow that doesn't look active or clickable.

GUI editor

Pressing F10 will toggle the GUI editor on and off. TGB itself is created using the TGB engine. The level/project interface itself is created using this GUI edtor. If you end up in the GUI builder, just press F10 to return to the regular editor. Changes in the GUI editor including loading a different GUI can cause significant problems in TGB and may require a reload from the TGB backup (see below). If you switch GUI files, you will have to load the TGB GUI before returning to you app. The TGB GUI is called "LevelBuilderBase -1592". Good luck with the GUI editor it is very confusing, but something we will have a lot more interaction with in the TGE.

Shared code area and a TGB clean copy

The lab machines will be sharing a copy of TGB. This may mean that someone could foul up the version of TGB on a specific machine since we all have access to write to that directory. If you find a version with a irrecoverable problem don't panic. There is a clean copy of TGB in c:\program files\TorqueGameBuilder-backup which you can use to restore from. Simply copy the contents of that directory to the TorqueGameBuilder directory and completely replace the engine with a clean backup copy.

Torque Script

Just some quick notes I made while learning Torque Script.

Variables

Everything is a string.

%value is a local
$value is a global

Basic debugging

open the console/debug window with: ~

echo("The %this object is " @ %this);

Creating new objects

Add to onLevelLoaded:

moveMap.bindCmd(keyboard, "space", "$pShip.createMissile();", "");

Creation of new sprite object:

function playerShip::createMissile(%this)
{
   %this.playerMissile = new t2dStaticSprite()
   {
      scenegraph = %this.scenegraph;
      class = playerMissile;
      missileSpeed=%this.missileSpeed;
      player = %this;
   };
   %this.playerMissile.fire();
}
The code that initializes the new object
function playerMissile::fire(%this)
{
   %this.setWorldLimit( kill, "-85 -115 155 50" );
   %this.setLinearVelocityX(%this.missileSpeed);
   %this.setPosition(%this.player.getPosition());
   %this.setImageMap(playerMissileImageMap);
   %this.setSize(12, 2);
   %this.setCollisionActive( true, true );
   %this.setCollisionPhysics(false, false);
   %this.setCollisionCallback(true);
}
          

Great Tutorials

The TGB includes a number of great tutorials. Simply start the TGB and select Help/Documentation. The best are the Fish Demo, Fish Game and Shooter. Checkers is multi-player so not as useful for this class since multiplayer with TGB requires two computers. We will run through the Fish Demo, Fish Game and Shooter in class tonight.

Fish Demo Tutorial

Complete the Fish Demo Tutorial. When you are done with the tutorial tell me and I'll keep a count of the number of finishers. Once 10 people have completed the Fish Demo we will move on. If you want the class to move faster, simply finish your tutorial and go help someone else finish more quickly.

Fish Game Tutorial

Complete the Fish Game Tutorial.

Shooter Tutorial

This is very similar to the Fish Game tutorial, but it will show another aspect of TGB which is important. It will also give you more experience with the tools.

The features tab on the TGB documentation

The Features tab on the TGB documentation gives details on many other apects of the TGB engine. You should familiarize yourself with the parts of this section that look interesting to you.

TGB forums

You have access to a wide range of support when using TGB. Please use take a look at the forums and search them when you are stuck. There are answers to most questions on these forums. I added these links because I could never seem to find the private forums. You should have a login for the sites, if not please contact me as we have enough for every student.

Public Forums

Wiki Documentation (Torque Developer Network)

 

Some Personal Notes on places I got stuck or made notes for later reference

Quit without saving?

TGB seems to allow you to quit without warning you that your work will be lost. In other cases I have found places where it seemed to save automatically when changing object attributes. Just make sure you save before exiting. It is definitely something to watch out for as you build your levels.

This should be a lesson to you. Don't build applications that allow users to quit without saving the changes they have made. After using TGB for a while you will know how it feels. Give your users a warning before they lose the information they have worked hard to create.

Simple mistake

function MyClass::myFunc(%this, %param)
{
  %save = %param;   // does not save a local class variable like flash
  %this.save = %param;  // proper save of a class variable
}

Another simple mistake

Named my function onLevelLoad instead of onLevelLoaded. I could see the script loading, but the onLevelLoad function was not executing because it was named wrong. Simple error, but hard to find. If all else fails compare the code character by character with something that you know works.

Timers

There are two types of timers in Torque script.

A single event timer attached to a specific object.

 

function MyObj::onLevelLoaded(%this, %scenegraph)
{

  // schedule something 2 seconds out
  %this.timerschedule = %this.schedule(2000, "twoSecTimer");
}

function MyObj::twoSecTimer(%this)
{
  echo("TWO SECOND TIMER **********************************");
}

   // ****************************
   // you can see if an event is already pending or cancel and event using
   if(isEventPending(%this.respawnSchedule))
      cancel(%this.respawnSchedule);
   // ****************************

        

And repeating interval timer

 

function MyObj::onLevelLoaded(%this, %scenegraph)
{
  // repeating interval timer
  %this.setTimerOn("3000");
}


function MyObj::onTimer( %this )
{
  echo("Three second interval timer");
}

Splash screen

Just name some object SplashTitle on the splash level

function SplashTitle::onLevelLoaded(%this,%sceneGraph)
  {
  // schedule something 2 seconds out
  %this.timerschedule = %this.schedule(2000, "endSplash");
  }

function SplashTitle::endSplash(%this)
  {
  %sg = %this.getSceneGraph();
  echo("loading level after splash sg=" @ %sg);
  %sg.loadLevel("MyGame/data/levels/firstlevel.t2d");

  // in reality, firstlevel should probably be a main menu
  // since that is where you want to go after the splash
  }

 

CPSC240 - Games Development
Chapman University
Instructor: W. Wood Harter
(c) copyright 2006-2007 - W. Wood Harter - All Rights Reserved
Screen shots on banner (c) copyright their resprective owners