|
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
}
|