Вы находитесь на странице: 1из 62

A Torque Game Engine Primer

David J. Sushil

April 14th, 2008

Copyright 2007, David J. Sushil

David J. Sushil

davidjsushil@gmail.com

Importing Assets from 3D Studio Max............................................................................ 4


Torque DTS Exporter...................................................................................................... 4
Preparing Your File for Export........................................................................................ 4
Importing to Torque......................................................................................................... 6
Using the Mission Editor............................................................................................. 6
Using Code...................................................................................................................6
Animating Objects in Torque........................................................................................... 9
Animating in 3D Studio Max...........................................................................................9
The Basic Process........................................................................................................ 9
Handling Multiple Animations.................................................................................. 10
Indicating Your Sequences............................................................................................ 11
Creating a Sequence...................................................................................................11
Begin/End Controllers............................................................................................... 11
Handling Other Forms of Animation......................................................................... 12
Playing Animations in Torque....................................................................................... 12
Creating Triggers in Torque...........................................................................................14
Adding Triggers............................................................................................................. 14
Basic Trigger Functions................................................................................................. 15
Animation Control Via Triggers.................................................................................... 16
An Additional Function................................................................................................. 17
Binding Keys in Torque with ActionMap......................................................................18
Basic Mapping............................................................................................................... 18
A Sample Function........................................................................................................ 19
Multiple Action Maps.................................................................................................... 19
GlobalActionMap.......................................................................................................... 20
Input Devices................................................................................................................. 20
Particle Effects in Torque............................................................................................... 21
Introduction....................................................................................................................21
Particle Data (PD).......................................................................................................... 21
Particle Emitter Data (PED)...........................................................................................23
Particle Emitter Node Data (PEND).............................................................................. 25
Getting Our Steam On................................................................................................... 25
Where To Go From Here............................................................................................... 26
Animating Particles....................................................................................................26
Multiple Particles....................................................................................................... 26
Moving an Emitter..................................................................................................... 26
Conclusion..................................................................................................................... 27
Detailing Your Environment Textures.......................................................................... 28
Introduction....................................................................................................................28
Detail Textures...............................................................................................................28
Bump Textures...............................................................................................................28
Playing Sounds................................................................................................................. 30
Descriptions................................................................................................................... 30
Profiles........................................................................................................................... 31
Playing the Sound.......................................................................................................... 32
Playing Sounds Manually.......................................................................................... 32
Playing Sounds through the GUI............................................................................... 32
2

David J. Sushil

davidjsushil@gmail.com

Playing Sounds through Special Effects.................................................................... 32


How Do I Turn This Thing Off?!...................................................................................33
Animating Characters in Torque................................................................................... 34
Building the Model........................................................................................................ 34
The Body....................................................................................................................34
The Legs.....................................................................................................................36
Adding Animation......................................................................................................... 37
Creating the Bone Structure....................................................................................... 37
Skinning the Model....................................................................................................39
Keyframing Animation.............................................................................................. 40
Preparing to Export........................................................................................................ 41
Initial Preparations..................................................................................................... 42
The Schematic View.................................................................................................. 42
Animation Sequences.................................................................................................43
Utilizing the Model in Torque................................................................................... 44
Troubleshooting............................................................................................................. 45
Assertion Failed on Skin Object.............................................................................45
Skin Found on Linked Node...................................................................................45
Bones are Visible in Torque.......................................................................................45
Character Faces the Wrong Way, or is Rotated......................................................... 45
Creating Doors in Torque .............................................................................................. 46
Introduction ...................................................................................................................46
Building the Model ....................................................................................................... 46
The Basic Model ...................................................................................................... 46
Animation ................................................................................................................. 47
Interfacing with Torque .................................................................................................48
A Whole System of Doors............................................................................................. 49
Baking Textures for Greater Realism............................................................................ 52
Preheat the Oven with Lights.........................................................................................52
Bake at 450 for 20 Minutes.......................................................................................... 53
Allow to Cool 2 Minutes, Serve.................................................................................... 53
Simple AI in the Torque Game Engine..........................................................................54
Overview........................................................................................................................54
Adding a Bot.................................................................................................................. 54
Updating the AI..............................................................................................................55
Styles..............................................................................................................................56
The Players ID.............................................................................................................. 57
Complete Code...............................................................................................................58
Appendix A: Modeling Torque Interiors with 3D Studio Max.................................. 60
Troubleshooting............................................................................................................. 62

David J. Sushil

davidjsushil@gmail.com

Importing Assets from 3D Studio Max


This tutorial is a primer on preparing models in 3D Studio Max for use with the Torque
Game Engine. It assumes the reader has a working knowledge of Max, and does not
cover how to create models in general, but rather the additional steps that need to be
taken to satisfy Torques insatiable lust for order and adherence to outlandish laws. Lets
begin.

Torque DTS Exporter


To begin using your brilliant models in Torque, youll need a handy little plug-in for Max
known as the Torque DTS Exporter. Your first challenge is to properly install this tool.
Its easy enough copy the max2dts.dll file, and paste it into Maxs plug-ins folder (on
my system, its C:\Program Files\Autodesk\3dsMax8\plugins\).
To make sure the Torque DTS Exporter is installed properly, open 3D Studio Max. Open
the Utilities panel by clicking on the hammer icon on the far right of your screen. The
exporter utility will not be listed by default. Instead, we need to add it to the Utilities
panel by clicking on the button labeled More... In the list that appears, click on DTS
Exporter Utility, and click the OK button. You will notice that additional rollouts have
been added to your Utilities panel. Now were ready to rock.

Preparing Your File for Export


At this point, you should open an existing model, or create a new one. Either way, I
should warn you, there are handy-dandy tools in 3D Studio Max that are not compatible
with Torque. The rule of thumb is this: simplicity reigns. That nifty hair and fur modifier
you love to play with? Its not going to work in Torque. If youre unsure about using a
technique or a particular modifier, first ask yourself, can I reasonably expect Torque to
support this feature? Then, go consult additional documentation if youre still unsure.
One such feature where Torque loves simplicity is materials. Torque can support
Standard and Multi/Sub Objects, and works well with the Unwrap UVW modifier.
However, it does not currently support Architectural, Ink n Paint, or any of the other
materials you might be interested in using. In fact, when it comes to applying diffuse
maps, Id stick to plain old bitmaps. Volumetric effects like Noise wont work.
Once youre ready to export your model, we need to take a few preparatory steps. First,
give every object in your scene a unique name. If youre modeling a table, that means
you cant have objects names leg1, leg2, leg3, and leg4. Instead, name them back-leftleg, back-right-leg, etc. Why? Because Torque supports multiple levels of detail for a
model. As a high-poly model recedes into the distance, Torque can swap it with a lowpoly model, which minimizes system strain. These level-of-detail models are stored in
the same file, and their names are appended with numbers. So if we kept our table legs
appended with digits, only one of them would be present at a time, and as we moved
away from the table, maybe other legs would appear and disappear. So for now, stick
with unique names.

David J. Sushil

davidjsushil@gmail.com

At this point, select every object in your scene, and click on the button marked Renumber
Selection A dialogue box will appear, asking for a new number. Type 2, and hit the
OK button. This adds the number 2 to the end of every objects name, committing them
all to a set level-of-detail. Since were not going to bother having multiple detail levels
for this initial model, were done for now.
At this point, we need to add a few helper objects to the scene. We can do this manually,
or we can have the Torque DTS Exporter do it for us. Simply click the button labeled
Embed Shape, but only click it one time. You will get no indication from the plug-in that
anything has occurred, but if you click the Select By Name button in the main toolbar,
youll notice that your scene is now home to base01, detail1, and start01 helper objects
that Torque needs to see in order to process your model. Well see these again when it
comes time to add collision detection.
Next, we need to show Torque where our model begins and ends in the scene. Click on
the Create panel tab (indicated by an arrow pointer), make sure Standard Primitives has
been selected from the dropdown listbox below, and use the Box tool to create an object
that surrounds your entire model. Name this object bounds. It should be a close fit, but it
should also contain all the objects in your scene make sure nothing is poking out.
Next, we need to create collision meshes, which let Torque know when your model has
collided with something in the engine. To do so, create another box that surrounds your
model, but is inside bounds, and name it Collision-1. Once it has been positioned and
scaled, and rotated properly, convert it to an Editable Mesh. Clone it (using Edit >
Clone), and name the cloned copy Col-1.
Collision meshes come in pairs, and they following the naming convention of CollisionN and Col-N, where N is a number from 1 to 8. This means you can have multiple
collision meshes for an object. Keep in mind, however, that collision meshes must be
convex shapes meaning every internal angle must be less than 180. Boxes are fine. So
are cylinders and spheres. In general, since the process of collision detection can be
intensive for a game engine, its best to use as few collision meshes as possible. And
where possible, stick with boxes, as they contain the least number of vertices.
Now would be a good time to select bounds and all of your collision objects, and hide
them. We dont want to accidentally move them now that were happy with their
positions.
With your collision meshes in place and out of sight, we now need to link them to two of
the helper objects we embedded earlier. To do so, click on the Schematic View (Open)
button on the main toolbar (it looks like an orange box pointing down at a grey box).
Using the Connect tool in the top left of the Schematic View window, connect all of your
Collision-N meshes to base01, and all of your Col-N meshes to start01.
At this point, we are ready to export. From the Utility panel, click the button labeled
Whole Shape. Select a destination for your file, and click the Save button. Simple,
right?
5

David J. Sushil

davidjsushil@gmail.com

Importing to Torque
Your model is now saved in DTS format. Before we can load it into Torque, we should
place it somewhere in the Torque file hierarchy. I recommend sticking with tradition, and
putting it somewhere in demo/data/shapes/, preferably in its own folder. In addition, any
files you used to texture the model in 3D Studio Max should be placed in this folder as
well, otherwise the model it will appear gray in your game.
Once your model is placed somewhere in the Torque directories, we can load it into a
mission. There are several methods to accomplish this task, and we will cover two of
them using the Mission Editor, and using code. In general, I would recommend adding
shapes via the Mission Editor wherever possible. However, be aware that there are times
when we need to add shapes via code.

Using the Mission Editor


Perhaps the easiest way is through the use of the Mission Editor. Go ahead and load the
Torque Game Engine Demo application. You will see a title screen for GarageGames,
and then a menu screen will appear. Press the F11 button on your keyboard to load the
Mission Editor.
Next, select World Editor Creator from the Window menu. You will see a new panel
appear on the right, with several categories, including Interiors, Shapes, Static Shapes,
and Mission Objects. Click the plus sign to the left of Static Shapes, and drill down
through the subsequent folders (demo, data, and shapes), until you locate the model you
wish to import. Click on the name of the shape, and it will magically appear within your
level.
Once imported, you can modify the position, rotation, and scale information for the shape
by selecting World Editor Inspector from the Window menu, and clicking on your object
from the list on your right (it will be the last item in the list, since we added it last).
Whenever you make a change, be sure to hit the Apply button, or it might not stick.
When you are satisfied with the location and size of your object, save your mission. The
next time you load this level, the shape will still be there.

Using Code
While the Mission Editor is a great way of adding Static Shapes (shapes that are purely
decorative), adding shapes via code is also an important skill to master, and doing so is
fairly simple.
First, create a new file, and call it myshape.cs. Open the file with any text editor
(Notepad works well), and add the following code:
datablock StaticShapeData(myShape){
shapeFile = "demo/data/shapes/myshape/myshape.dts";
};
function addShape(){

David J. Sushil

davidjsushil@gmail.com

%obj = new StaticShape(){


datablock = myShape;
position = "100 100 100";
rotation = "1 0 0 0";
scale = "1 1 1";
};

When you have done so, save this file in demo/data/shapes/myshape/.


Notice that in this code, we have two main sections a datablock and a function. Think
of datablocks like classes. They are a means of storing template information in memory.
Datablocks dont visibly appear in Torque, however, we can make instances of them,
which are unique copies of the parent datablock. In this case, we are creating a
StaticShape datablock called myShape. myShape has one property, shapeFile, which
indicates the path and name of the model we exported. You should change this line to
reflect the location and name of your exported file.
Next, we have a function called addShape(). In the first line of addShape(), we create a
new StaticShape, and assign its ID to a local variable called %obj. This new StaticShape
takes on the properties assigned to myShape through the use of its datablock property
(notice how we assign the parent, myShape, to this unique instance). The position,
rotation, and scale properties are fairly straightforward. Position takes three values,
representing the shapes x-, y-, and z-coordinate. The scale property also accepts three
values, which stretch or shrink the object about its x-, y-, and z-axes. In this case, all
scale values are 1, which means it should be the same size as it was in 3D Studio Max.
Our rotation property is a little tricky. Torque stores rotation information in quaternion
format. Ill be honest, no college math course I took ever addressed quaternions, so Im
not the foremost expert on how they work. Here, I rely on the Mission Editor to generate
my rotation coordinates. In fact, this is perhaps the best strategy use the Mission Editor
to place, rotate, and scale your static shape initially, then record this information in code.
When youre ready to test your shape, open the Mission Editor in Torque, then open the
Console by pressing the tilde (~) on your keyboard. Type the following code:
exec("demo/data/shapes/myshape/myshape.cs");
addShape();

The first line loads your .cs file into memory. Of course, change the information passed
to the exec() function to reflect the location and name of your file. The second line calls
the addShape() function we wrote. If everything was entered correctly, the shape should
appear at the position you specified.
You could also add these lines of code to another file, one that would execute them
automatically as the level loads. Thats a topic we will explore at a later time.
Now, why would we want to add shapes via code, when it seems so much easier to add
them via the Mission Editor? The answer is versatility. You cant use the Mission Editor
7

David J. Sushil

davidjsushil@gmail.com

to add shapes to your mission once the game has begun. And once we start working with
animated shapes and other objects in later tutorials, a code-based approach makes more
sense. Better to get a handle on the technique now, then struggle with it later.

David J. Sushil

davidjsushil@gmail.com

Animating Objects in Torque


This document picks up where the Importing Assets From 3D Studio Max tutorial leaves
off. If you havent done so, I highly recommend reading that paper and familiarizing
yourself with the process before proceeding. Once youre comfortable with importing
static assets, animated assets will be a cinch. Of course, consult with your doctor if you
experience any dizziness, painful or difficult swallowing, or bouts of inexplicable terror.
We will address three aspects of animating objects first, how to create animation
sequences in 3D Studio Max; second, how to properly configure your files for Torque;
and third, how to trigger the animations within the engine. Lets begin!

Animating in 3D Studio Max


At this point, Im going to make an assumption that youre fairly comfortable with using
3D Studio Max. As a result, Ill only cover areas of the program that deal specifically
with animation, as this might be a new concept for some readers.

The Basic Process


To begin, open an existing model, or create a new one. Once all of the model architecture
is in place, were ready to begin animating. Animating is simply the process of setting
keyframes on the timeline. The timeline is located at the bottom of the screen, just below
all four viewports. Notice the time slider on the left hand side? You can drag the time
slider left and right to move forwards and backwards through your animation. Likewise,
the animation controls are located below the timeline on the right. There are buttons for
playing and pausing the animation. These will be useful later.
For now, we want to focus on two important buttons. The first is the Toggle Auto Key
Mode button, indicated by the text Auto Key; the second, the Set Keys button,
indicated by a picture of a key.
When you are ready to begin animating, click on the Toggle Auto Key Mode button.
When Auto Key mode is activated, the timeline will become red. Please be careful! It is
painfully easy to forget that you are working in Auto Key mode, so its best to get in the
habit of turning off Auto Key mode whenever you are finished animating. If you dont, it
could have serious consequences!
With Auto Key mode enabled, click on an object within your scene. When an object is
selected, it is possible to set keyframes for that object on the timeline. Each object in the
scene has its own private timeline, where only its own keys appear. To access this
timeline, you must select the object.
By way of example, lets imagine were animating an electric fan. The blades of the fan
are a single object, which we want to rotate 360 from the start of the animation to the
end. To do so, wed select the blade object. With Auto Key mode enabled, we would
need to set a keyframe at the start of the animation, on frame 0, by clicking on the Set
Keys button (the one with the picture of a key). Notice how a red and green block is
added to the timeline at frame 0. This is how 3D Studio Max indicates a frame has been
9

David J. Sushil

davidjsushil@gmail.com

set. Next, we would reposition the timeline slider to the end of the animation sequence,
maybe on frame 50. With the timeline slider positioned, we could then rotate the fan
blades 360. When we are happy with the rotation, we would set a keyframe at frame 50,
again by clicking the Set Keys button.
The effect of this process is that if we move the timeline slider back and forth between
frames 0 and 50, 3D Studio Max interpolates the position of the blades accordingly. Its
all mathematics at frame 25, for example, the blades should be rotated approximately
180.
We could also test this by playing the animation using the animation controls. However,
since the default length of an animation is 100 frames, and our animation is only 50
frames long, it would appear as though our animation has stopped midway through. We
can remedy this by clicking on the Time Configuration button, which is located in the
bottom-right of the screen, and looks like a window with a clock in front of it.
From this menu, we can set the Start and End times of the animation. In our case, we
would want the End time to be 50, or the last frame in our blade spinning animation.
In either case, once we are satisfied with our animation, we should turn Auto Key mode
off, by click on the Toggle Auto Key Mode button.
The most basic forms of animation are transformations that is, animations that involve
moving, rotating, or scaling objects. Torque supports transformation animation, as well
as a few other types. Well explore those additional animation types in a moment.

Handling Multiple Animations


In case you were wondering, every animation for an object can be contained on the same
timeline. In the case of our electric fan, we might have two different animations one
where the blades are spinning normally, a second where the blades spin crooked (as if the
fan has been damaged), and a third animation for when our player gets bored and shoots
the fan into smithereens.
Weve already animated the normal spinning sequence. The second damaged
animation would begin on frame 51, and end on frame 101. For this animation, we
would rotate the blades 360 from start to finish just like our normal animation,
however, we would also rotate the blades forward and back slightly, to create the look
that the blades are wobbling.
In the third animation, wed deform the entire model into a broken heap. This animation
would begin on frame 102, and end on frame 110. Its a quick animation.
The secret to keeping all of the animations pure is to make sure that their keyframes
butt up against each other. That is, if our first animation ends with a keyframe at 50,
then our next animation begins with a keyframe at 51. Keyframe 51 should reset our
model to precisely the way we want it to look at the start of our second animation.

10

David J. Sushil

davidjsushil@gmail.com

Otherwise and this is the critical part 3D Studio Max will interpolate from keyframe
50 onward. This could possibly result in a poor animation.
The question is, how do we tell Torque where one animation begins and another ends?
We do so by creating helpers objects called Sequences.

Indicating Your Sequences


Sequences are invisible objects created in 3D Studio Max which Torque reads like an
instruction manual. Sequences give each animation a unique name, indicate where an
animation begins and ends on the timeline, and designate whether an animation is cyclic
(looping) or non-cyclic (non-looping). Sequences have a few other properties as well, but
in general these are the three most important properties.

Creating a Sequence
To create a sequence object, click on the Helpers button from the Create panel. In the
dropdown listbox that appears, select General DTS Objects. This option will only appear,
by the way, if you have loaded the DTS Exporter Utility from the Utilities Panel. See the
Importing Assets From 3D Studio Max tutorial for instructions.
From the Object Type rollout, click the Sequence button. Go ahead and create a sequence
by clicking and dragging in a viewport. A simple box will appear. Dont worry if this
sequence isnt within the bounding box of your model its strictly a helper object that
communicates between Max and Torque. It will not be rendered in the engine.
From the Modify panel, give this sequence a name. Also, if you want your animation to
repeat, be sure that the Cyclic Sequence box is checked. Otherwise, uncheck the box, and
the animation will only play one time. Rotating fan blades should be cyclic. On the other
hand, the animation for opening a door should be non-cyclic.
Create a sequence object for each animation on your timeline. Our electric fan has three,
which well call spin, wobble, and die. Spin and wobble are cyclic; die, non-cyclic (it
only has to die once).

Begin/End Controllers
The final step is to indicate where each sequence begins and ends on the timeline. To do
so, we open the Curve Editor. Do so by clicking the Curve Editor (Open) button, located
on the toolbar, and represented by a line chart icon. A curve editor (sometimes referred to
as a dope sheet by animators), is normally used to control the speed and smoothness of an
animation. We will use it to set special keys for each sequence, which Torque will use to
partition our animations in the engine.
To set these keys, locate the first sequence in the panel on the left. In the case of our
electric fan, the sequence is located in the Objects section, and is title spin. Open the spin
object by clicking on the plus sign to its left. From within this object, open up the Object
(Sequence II) sub-object. Finally, click on the Sequence Begin/End controller. Now, set
two keys on the timeline to the right one at the start of the animation (frame 0), and one

11

David J. Sushil

davidjsushil@gmail.com

at the end of the animation (frame 50). You can set keys by selecting the Add Keys
button in the toolbar, and clicking directly onto the timeline.
Repeat this process for the next animation. That is, in the panel on the left, locate the
next sequence (in the electric fan example, its wobble), drill down until you find its
Sequence Begin/End controller, and set keys at the start and end of the animation.
Once each animations beginning and ending frames have been set, were pretty much
done. Sequences, unlike collision meshes, dont need to be linked to anything in our
scene, so we need not bother with the Schematic View, except to make sure that our
sequences are unlinked, and that everything else is embedded and arranged properly.

Handling Other Forms of Animation


By the way, I did mention that animations can take different forms. Just for the sake of
argument, select a sequence and click on the Modify panel. Expand the Export Control
rollout panel, and observe the various forms of animation that Torque supports. As stated
earlier, transforms are the most basic, and export by default note the checked box next
to Transform Animation.
Most of these animations are self-explanatory. For example, the Morph Animation
option allows you to deform your model vertex by vertex. This is good for creating a
melting effect. Likewise, the Visibility Animation option allows your model to fade inor-out of the scene.
If your animation falls into any of these categories, simply check the corresponding box,
and export your shape as you otherwise would for Transform animations.

Playing Animations in Torque


Once your sequence objects have been set, its time to export your model. Even though
weve added animations, exporting an animated shape works exactly the same way as for
a static shape. Again, consult the Importing Assets From 3D Studio tutorial (seriously).
To test out your animation in Torque, we need to import the asset via code. Its a fairly
simple process, really. Like any other object, the code looks like this:
datablock StaticShapeData(Fan) {
shapeFile = "demo/data/shapes/fan/fan.dts";
};
function addFan() {
$fanObj = new StaticShape(Fan){
datablock = Fan;
position = "234.95 -206.45 194.5";
scale = "1 1 1";
rotation = "1 0 0 0";
};
}

12

David J. Sushil

davidjsushil@gmail.com

This code should be placed within a .CS file say, fan.cs, located in
demo/data/shapes/fan/, for example. Notice the datablock called fan, which has one
property the location of our .DTS fan model.
We instantiate the fan using our custom addFan() function. Of course, you should change
the position, scale, and rotation properties of the fan object to reflect its transform data in
your level.
See how we store our fan object in a global variable ($fanObj)? Well need that variable
to control our animations later.
In the meantime, to test this code, load Torque, and pull up your console window by
pressing the tilde key (~). Enter the following code:
exec("demo/data/shapes/fan/fan.cs");
addFan();

If everything worked correctly, your fan should appear. Youll notice, however, that it is
not animated! Animations are controlled via a method called playThread. It looks like
this:
$fanObj.playThread(0, "spin");

We call the method from the global variable $fanObj. It takes two arguments. The first
we can ignore (its usually 0), but the second argument is the name of the animation we
want to play. Remember that spin is the sequence in which the blades rotate normally.
Its a cyclic sequence, so once it begins, it continues indefinitely. We can call any
animation sequence we want simply by calling playThread and passing the name of the
animation as an argument.
To make our fan spin when its loaded, insert the playThread code within our addFan()
function. Simple enough. Have fun animating objects!

13

David J. Sushil

davidjsushil@gmail.com

Creating Triggers in Torque


Triggers are invisible structures in the Torque engine which have the ability to execute
code. You can create triggers using several methods, including by using the World Editor
Creator feature in the Torque mission editor. Perhaps the easiest method is through the
use of code, which we will explore in this thankfully brief tutorial.

Adding Triggers
To add a trigger through code, create a .cs file and add and modify the following code.
datablock TriggerData(FilingCabinetTrigger){
tickPeriodMS = 1000;
};
function addTrigger(){
%obj = new Trigger() {
position = "100 100 100";
scale =
"1 1 1";
rotation = "0 0 1 0";
dataBlock = "FilingCabinetTrigger";
polyhedron = "0 0 0 1 0 0 0 -1 0 0 0 1";
};
}

As you can see, the first step is to create a datablock called TriggerData. It takes one
argument, which will be the name of the parent trigger. In this case, were calling it
FilingCabinetTrigger.
The datablock has one parameter, labeled tickPeriodMS. This indicates how often the
datablock executes code. Weve assigned it a value of 1000, meaning the trigger will be
executed every second. By the way, the smaller this number, the greater its strain on your
CPU. Deciding on a reasonable interval is important.
Next, we have a function called addTrigger, which, as you might have guessed, creates an
instance of FilingCabinetTrigger.
The first line creates a local variable called %obj, and assigns it the ID of a new Trigger.
This new trigger has several parameters of importance. First, its position is where it
appears in the mission. Its scale is also reported, as is its rotation. These three properties
should be familiar to you, having previously worked with static shapes.
%obj will take on the properties of the FilingCabinetTrigger outlined above, by assigning
it to the dataBlock parameter.
Finally, a property called polyhedron creates the shape of the trigger. It is currently set up
to represent a box, although additional shapes are possible. To date, I have not found any
resource that explains how this polyhedron parameter works. I tend to manipulate the
triggers scale in order to create the proper size and shape.

14

David J. Sushil

davidjsushil@gmail.com

By running the addTrigger() function from the console, we can add an instance of the
FilingCabinetTrigger to our mission.

Basic Trigger Functions


Next, we need to make it do stuff. The following code offers an example:
function FilingCabinetTrigger::onEnterTrigger( %this, %trigger, %obj )
{
$CabinetInRange = true;
echo("In range.");
}
function FilingCabinetTrigger::onLeaveTrigger( %this, %trigger, %obj )
{
$CabinetInRange = false;
echo("Out of range.");
}

This code obviously doesnt do much, other than offering you a framework to build on.
Every trigger has two important functions built into it onEnterTrigger() and
onLeaveTrigger(). As you might expect, onEnterTrigger() is called whenever the player
moves into the space the trigger occupies. onLeaveTrigger() is called whenever the
player moves out of the space the trigger occupies. Remember, we set the tickPeriodMS
to 1000, which means these functions will be called only once a second, and only if their
assumptions are met. There is a third method, onTickTrigger(), which we will address
later.
In this case, when the player enters the trigger, Torque will set the value of a global
variable called CabinetInRange to true. It will also print In range in the console.
Likewise, when the player exits the trigger area, CabinetInRange will revert to false, and
the Torque will print Out of range in the console.
Notice that these functions take three arguments, which are supplied by Torque. These
arguments are %this, %trigger, and %obj, which are essentially the following objects:
Variable
%this
%trigger
%obj

What It Represents
The datablock associated with the trigger.
The trigger which executed the function the one we created in
code.
The object which moved into (or out of) the trigger area it could
be the player, for example.

Now, in order to make this code work effectively, we need to execute the .cs file in which
it exists, either through the console, or by placing it in your game.cs file. Either way, the
code to run this is as follows:
exec("demo/data/shapes/filing-cabinet/filing-cabinet.cs");
addFilingCabinet();

15

David J. Sushil

davidjsushil@gmail.com

Of course, you will need to change the first line to reflect the name and location of the .cs
file you have created. You should also add a static shape in roughly the same spot as your
trigger.

Animation Control Via Triggers


If you wanted to control a shapes animation using triggers, we need to take a few extra
steps. First, we need to create an animated object. Lets assume weve made a filing
cabinet, which will open and close whenever the player enters and leaves the trigger area.
We might write code like this (and for your sake, Ill boldface what Ive changed from the
previous examples:
datablock StaticShapeData(FilingCabinet){
shapeFile = "~/data/shapes/filing-cabinet/filing-cabinet.dts";
};
datablock TriggerData(FilingCabinetTrigger){
tickPeriodMS = 1000;
};
function addTrigger(){
%FilingCabinetObj = new StaticShape(){
position = "100 100 100";
scale =
"1 1 1";
rotation = "0 0 1 0";
datablock = FilingCabinet;
};

%obj = new Trigger() {


position = "100 100 100";
scale =
"1 1 1";
rotation = "0 0 1 0";
dataBlock = "FilingCabinetTrigger";
polyhedron = "0 0 0 1 0 0 0 -1 0 0 0 1";
cabinetID = %FilingCabinetObj;
};

This new code should not be unfamiliar to you at this point. We create a static shape
datablock called FilingCabinet, and then create an instance of that datablock in the
addTrigger() function. Notice that we are storing the ID of the static shape in a local
variable called %FilingCabinetObj, which we then assign to our triggers cabinetID
property. In this way, we can modify our onEnterTrigger() and onLeaveTrigger()
functions to control the static shapes animation, like so:

16

David J. Sushil

davidjsushil@gmail.com

function FilingCabinetTrigger::onEnterTrigger( %this, %trigger, %obj ){


$CabinetInRange = true;
echo("In range.");
openCabinet(%trigger.cabinetID);
}
function FilingCabinetTrigger::onLeaveTrigger( %this, %trigger, %obj ){
$CabinetInRange = false;
echo("Out of range.");
closeCabinet(%trigger.cabinetID);
}
function openCabinet(%id){
%id.playThread(0, "open");
}
function closeCabinet(%id){
%id.playThread(0, "close");
}

Voila.

An Additional Function
Finally, lets look at an addition trigger function, onTickTrigger(), which checks to see if
something is inside the trigger area. This function accepts the same three arguments as
onEnterTrigger() and onLeaveTrigger(), but will be executed not just once, but every time
the tickPeriodMS timer is reset. This could be a good way of assigning damage to a
player who has fallen into a pit of lava, for example.

17

David J. Sushil

davidjsushil@gmail.com

Binding Keys in Torque with ActionMap


This mousy slip of a tutorial addresses how to add keystrokes to your game, and back
them up with some action on screen. To do this, we will create and modify an action
map.

Basic Mapping
The first thing were going to do is check out some of the existing code Torque has to
offer. For this, we turn to demo/client/config.cs. Contained in this file we find three
important functions:
// Torque Input Map File
moveMap.delete();
new ActionMap(moveMap);
moveMap.bindCmd(keyboard, "escape", "", "escapeFromGame();");
moveMap.bind(keyboard, "f2", showPlayerList);
moveMap.bind(keyboard, "a", moveleft);
moveMap.bind(keyboard, "d", moveright);
// Etc., Etc., Etc.

The first line is common courtesy. If an action map named moveMap exists from a
previous game, delete it. Why is this important? Between games (heck, between levels)
the applicable keys may change, and the key responsible for firing a weapon might
become the key responsible for jumping. If we tried to fire a gun that doesnt exist in the
all-jumping level, worlds collide.
In the next line, we create a new action map named moveMap. The new ActionMap()
command function takes one argument, which is the name of our action map. This leads
us to an interesting question. Can we create more than one action map for our game?
The answer is, absolutely! Well explore this a little later.
Next, we have a list of key bindings. These key bindings can be created using one of two
commands.
The first, and easiest, is bind(). Bind() takes three arguments the name of the input
device, the triggering event, and a function to call. The two input devices we are most
concerned with are keyboard and mouse0. As you can see, in line four of the above code,
we are binding a function called showPlayerList to the F2 key on the keyboard. Easy as
pie!
The second method of binding keys is the use of the bindCmd() function. BindCmd()
allows you to add two functions to a key one when the key is pressed, and another when
the key is released. So, in line three, we can see that we are assigning two commands to
the Escape key. The first argument (known as the make command), is blank, indicated by
empty quotation marks. The second argument (known as the break command), is
escapeFromGame(), which as you guessed, escapes from the game. This means that
nothing happens when you press the Escape key, but when you depress it, it calls the
function which quits out of Torque.
18

David J. Sushil

davidjsushil@gmail.com

A Sample Function
Now, lets write a few simple functions to test this. Place the following code in a .cs file
called bindTest.cs, and place it in the demo/data/ folder:
function getPlayerPos() {
echo(localclientconnection.player.position);
}
moveMap.bindCmd(keyboard, "x", "", "getPlayerPos();");

Finally, load the .cs file into memory using the exec() command in Torques console
window, like so:
exec("demo/data/bindTest.cs");

Finally, test your method by walking through the terrain with the Mission Editor
disengaged (that is, hit F11 if you still have the menu bar and heads-up-display visible),
and the console window closed. Press the x button on your keyboard. Open the console,
and you should have the x-, y-, and z-coordinate values of the player recorded.

Multiple Action Maps


Now, lets go back to the notion of multiple action maps. Imagine your game has
vehicles which the player can enter and exit. Obviously, the controls used for driving a
car are different from the controls for moving your players avatar. We might create two
sets of key bindings, like so:
new ActionMap(playerMap);
// List key bindings here via playerMap.bind() or playerMap.bindCmd()
new ActionMap(vehicleMap);
// List key bindings here via vehicleMap.bind()or vehicleMap.bindCmd()

Now all we need to do is select an appropriate map based on whether the player is in a
vehicle or not. Such code might resemble the following function:
function toggleMaps(%inVehicle){
if (%inVehicle){
playerMap.pop();
vehicleMap.push();
} else {
playerMap.push();
vehicleMap.pop();
}
}

The function toggleMaps is called whenever the player enters or exits a vehicle. This
function takes one argument, %inVehicle, which is either true or false. If it is true, we
need to use the action map for vehicles. We push (activate) the vehicle map, and pop
(deactivate) the player map. If the player is not in a vehicle, we push (activate) the player
map, and pop (deactivate) the vehicle map.

19

David J. Sushil

davidjsushil@gmail.com

GlobalActionMap
It should be noted that Torque has a default action map, labeled GlobalActionMap, which
saves us from at least a few headaches. Some keys should always be available, no matter
whether were in a vehicle or on foot. Keys that display help menus, for example, or
which allow us to exit the game at any time. These should be stored in GlobalActionMap
rather than in our other, mode-dependent action maps. And of course, its a good idea to
never pop (deactivate) GlobalActionMap.

Input Devices
Finally, we should address the existence of additional input devices. Torque can
recognize a single keyboard, multiple mice, multiple joysticks, and multiple unknown
devices.
To bind commands to the keyboard, we simply invoke the keyboard interface. The
keyboard has an extensive range of inputs digits, lowercase letters, uppercase letters,
and F-keys which can be modified by adding the prefixes shift, ctrl, or alt, followed by
a space. Please note that to use the shift, ctrl, or alt keys on their own, use lshift, rshift,
lctrl, rctrl, lalt, and ralt.
We can define multiple mice by appending the word mouse with a digit, beginning with 0
for the first mouse. So, to accept a two-mouse interface, we need to bind keys to mouse0
and mouse1. By default, mouse without a digit indicates the mouse0. The mouse consists
of a series of buttons, labeled button0, button1, button2, etc. The mouse also has an xaxis
and yaxis which may have commands assigned to them.
Likewise, multiple joysticks and multiple unknown devices are invoked the same way as
mice, with joystick0 or unknown0 as the first device in the series, and each subsequent
device increasing its appending value. In addition, these devices, like the mouse, consist
of a series of buttons, labeled button0, button1, button2, etc.

20

David J. Sushil

davidjsushil@gmail.com

Particle Effects in Torque


Introduction
In modern 3D games, designers are often faced with the challenge of balancing strain on
the system with pure gloss. As our cowboy hero rides across the desert, we expect little
clouds of dust to appear beneath the metal-shod hooves of his trusty steed. We expect the
heat of the desert to warp and wobble the sight of distant mountains. We expect flies to
buzz about the ears of buffalo, and shell casings to fall from discharged rifles.
Clouds of dust and swarms of flies are difficult to model in 3D, and as 3D models, they
would hog system resources. As a result, they must be faked. For this, we implement
particle emitters. These special effects systems are comprised of sprites (sometimes
called billboards), which are bitmap images with some level of transparency. They may
be animated. In any case, they almost always face the screen.
Creating particle emitter systems in Torque is really a three step process. It requires
creating the particles themselves, the behavior that drives the particles, and spot for them
in 3D space. These are manifested in Torque as Particle Data, Particle Emitter Data, and
Particle Emitter Node Data. If these terms scare you, dont sweat it once we have a bit
of working code on screen, it will all make sense.

Particle Data (PD)


We will begin by looking at particles. These could be sparks, puffs of smoke, drops of
water, or specks of dust. They have certain characteristics, like transparency, a life
expectancy, and how they are affected by wind and gravity.
To create a Torque particle, we begin by making the image in a program like Photoshop
or GIMP. Particle image sizes should be powers of 2, not exceeding 512 x 512 pixels.
Keep in mind that Torque ignores all color data in this image, and uses it instead as a
transparency map. In this way, black pixels will be transparent; white pixels, opaque;
gray pixels, translucent. Save your image as either a JPEG or PNG file.
Creating a particle datablock in Torque is fairly simple, once youve done it once or
twice. Lets look at some sample code:

21

David J. Sushil

davidjsushil@gmail.com

datablock ParticleData(steam_puff){
textureName = "~/data/shapes/steam/steam_puff.png";
lifetimeMS = 300;
lifetimeVaranceMS = 100;
colors[0] = "0.5 0.5 0.5 0.75";
colors[1] = "0.4 0.4 0.45 0.5";
colors[2] = "0.3 0.3 0.4 0.125";
colors[3] = "0.2 0.2 0.35 0";
sizes[0] = 1.0;
sizes[1] = 1.1;
sizes[2] = 1.5;
sizes[3] = 2;
times[0] = 0.0;
times[1] = 0.3;
times[2] = 0.6;
times[3] = 1;
spinSpeed = 0;
spinRandomMin = -100;
spinRandomMax = 100;
gravityCoefficient = -10;
constantAcceleration = 5;
dragCoefficient = 2;
};

Here, we create a ParticleData object template and call it steam_puff. You will notice
that the first property within our datablock is a texture name, which points to our image
file. When using Torque, its not necessary to include a file extension such as .PNG or .
JPG. Torque will instinctively try to open either one.
Next, we have lifetime information, which indicates how many milliseconds a particle
may remain in the world. In this case, our steam puff particle will last three tenths of a
second, give or take 100 ms, as indicated by the lifetime variance property. Creating
variability is an excellent way of giving your particles some character.
Next, there are lines which control the color and size of the particle throughout its
lifetime. Notice the lines that begin with times[0] times[3]? These are keyframes, and
the values they contain represent percentage values, with 0 being the instant the particle
enters the world, and 1 being the instant that it leaves. Torque will look at the
information contained in the colors and sizes arrays, and interpolate between them based
on the times values.
The colors array accepts four values for each member, which represent red, green, blue,
and alpha values. Remember, our particle image is a transparency map, and otherwise
contains no color, so we have to colorize it ourselves. For color values, 0 always
represents no color, while 1 represents full color. Likewise, 0 is invisible, while 1 is fully
opaque. In this example, or particle begins life as a semi-transparent gray (red, green and
blue are at 50% each, and our alpha channel is at 75% opaque). Over time, it becomes
darker and darker, and more and more transparent. If you notice the blue channel, it
grows darker slightly less than the red and green channels, so our steam puff also appears
bluer as time goes on.

22

David J. Sushil

davidjsushil@gmail.com

The sizes array works exactly like the colors array, with the size of the particle changing
based on the values stored. A value greater than 1 indicates an increase in size, which a
value less than 1 indicates a decrease in size. For our steam puff, it doubles in size from
its initial appearance to its untimely death. Please note that the members of the sizes
array can take values ranging from 0 to infinity.
Now, do you have to include four keyframes? No. In fact, you dont have to include any,
but if you dont, Torque defaults to solid white sprites exactly the size you created them,
which dont change their appearance from the time theyre born to the time they die.
There are three variables that control the rotation of a particle. They are spinSpeed,
spinRandomMin, and spinRandomMax. The spinSpeed property can accept values from
-10,000 to 10,000. In this case, we indicate no spin at all, which is 0. On the other hand,
we specify a spinRandomMin of -100, and a spinRandomMax of 100, which allows
Torque to randomly adjust the spin of each particle. Again, this adds variability, and
variability adds character.
The final three properties control how a particles motion changes over time. The first
property, gravityCoefficient, indicates how gravity affects each particle. Particles with a
positive gravity coefficient will fall, while those with a negative coefficient will rise.
Since were working with steam, we want it to rise, hence the negative value. The
constantAcceleration property indicates how fast the particle moves. It can accept either
positive or negative values, indicating forward or backward motion, respectively. Finally,
the dragCoefficient property indicates how much the particle is slowed per second. We
dont have to worry about this much, since our steam has a shelf life less than one second.
However, its useful to demonstrate how particles can be slowed with time.
Are these all the properties for a particle? No. There are more, but these are enough to
get you started.
Now, a particle on its own does nothing. In order to generate a stream of particles, we
need a particle emitter, which, coincidentally enough, is what we cover in the next
section.

Particle Emitter Data (PED)


Particle emitters handle how our particles come into the world, how fast they travel, and
how they move. Particle emitters also have properties which control how long they last,
and which way our sprites face.
Taking a look at an effective emitter for steam, we find:

23

David J. Sushil

davidjsushil@gmail.com

datablock ParticleEmitterData(steam_column){
particles = steam_puff;
ejectionPeriodMS = 25;
periodVarianceMS = 2;
ejectionVelocity = 5;
velocityVariance = 2;
thetaMax = 10;
thetaMin = 0;
phiReferenceVal = 0;
phiVariance = 10;
lifeTimeMS = 0;
};

This particle emitter is called steam_column. Youll notice that the first property, labeled
particles, accepts our steam_puff ParticleData template. This means steam_column will
generate multiple steam_puffs, based on the remaining properties in its declaration.
First, we have properties which control how our steam puffs are brought into the world.
In this case, ejectionPeriodMS indicates how often a particle is emitted, and
periodVarianceMS gives us some variability. So our column of steam will generate one
puff of steam approximately every 25 milliseconds. Rather frequent, but hey, its steam.
Next, ejectionVelocity and velocityVariance control how fast each particle travels away
from the emitter. Dont get confused between ejectionVelocity in the emitter and
constantAcceleration in the particle itself. These two motion-based properties could be
forcing the particle along two different paths say, up and right.
In fact, thats where thetaMax and thetaMin come into play. These properties essentially
control the emitters aim, at least around the x-axis. They can accept a range from 0 to
180, but of course, the minimum or maximum depends on its counterparts value. So, if
thetaMin is 10, thetaMax must be at least 10. In any case, a value of 0 sends particles
shooting straight up, while a value of 180 sends them straight down.
Likewise, phiReferenceVal and phiVariance control rotation around the z-axis, and can
each take a range of values from 0 to 360. Yes, its rather inconsistent from the theta
controls, but it works nonetheless. In this case, our phi reference value of 0 keeps the
emitter from rotating around the z-axis, but our phi variance value allows for some
wiggle room. Again, this kind of variety adds spice.
Finally, we have a property, lifeTimeMS, which determines how long the emitter itself
exists in the world. Dont be fooled, a value of 0 means it never leaves. Any other value
for this property must be a positive number. So if you wanted your emitter to work for 5
seconds and then quit, set this value to 5000.
Again, these are not all of the properties for an emitter, but they are enough for now.

24

David J. Sushil

davidjsushil@gmail.com

Particle Emitter Node Data (PEND)


Finally, we have particle emitter nodes, which contain transformation info, a wink and a
nod to our emitter, and an odd little property which affects how the system behaves
overall. Heres an example:
datablock ParticleEmitterNodeData(steam_source){
timeMultiple = 1;
};

Yeah, its not much, but this one value affects how often particles are ejected, and their
position when ejected. How this happens is not clear to me, so lets assign it the identity
value (1), and move on.
Of course, the transformation data and the emitter property arent assigned within this
template. Instead, they are assigned when an instance of the node is created.

Getting Our Steam On


To make the steam particle emitter work, we have to jump through a scant few hoops.
Create a file called steam.cs, and place it in demo/data/shapes/steam/. This file should
contain all of the datablocks we outlined in the above sections, plus the following code:
function addSteam(){
%steamObj = new ParticleEmitterNode(){
position = "238 -205.75 191";
rotation = "1 0 0 0";
scale = "1 1 1 1";
dataBlock = steam_source;
emitter = steam_column;
velocity = 1;
};
}

Notice, this ParticleEmitterNode object an instance of steam_source, our node template,


and its emitter is steam_column. The position, rotation, and scale properties should be
more-or-less routine now, and you need only change the position data to reflect your
mission. The velocity property indicates an initial ejection velocity for the emitter,
exactly why, I couldnt tell you.
This files ready to go, but if we add it via the console to test it, youll notice that our
pretty steam puff images from page 1 of this document have been hijacked by giant white
squares. Somethings clearly amiss.
As it turns out, all of our particle effect information must be preloaded into Torque. We
cant add it during a mission, or it misbehaves. To preload your particle emitter, locate
demo/server/scripts/game.cs, and open it for editing. In the onServerCreated() function,
locate the section set aside for basic data blocks, and right around the reference to
chimneyfire.cs (another particle emitter, by the way), add the following line:
exec("demo/data/shapes/steam/steam.cs");

25

David J. Sushil

davidjsushil@gmail.com

Now, when you load up Torque, open your console window, and type the following
command:
addSteam();

That was almost as easy as pie, if pie was six pages long, right?

Where To Go From Here


There are only a few additional topics to cover. The first is animating particles. The
second is generating multiple particles from the same particle emitter node. The third is
moving an emitter once it has been created. All three tasks are possible in Torque.
Briefly, lets address them.

Animating Particles
To animate a particle, add the following code to your particle datablock (steam_puff,
from page one):
animateTexture
framesPerSec =
animTexName[0]
animTexName[1]
animTexName[2]
// Etc., up to

= true;
32;
= demo/data/shapes/steam/steam_puff-0.png;
= demo/data/shapes/steam/steam_puff-1.png;
= demo/data/shapes/steam/steam_puff-2.png;
animTexName[50]

You must set animateTexture to true for this to work. As for the framesPerSec property,
32 is the threshold at which humans see fluid motion, but feel free to choose any value
between 1 (the default), and 200.

Multiple Particles
If you want your broken pipe to emit jets of water as well as steam, theres not necessarily
a need to create separate emitters. All we need to do is define a new kind of particle, say
water_jet, and link it to steam_column, our particle emitter. Ill skip the water_jet
particle data template (this tutorial is long enough already), and instead Ill show you how
to list multiple particles in the emitter. Check out the code:
particles = steam_puff SPC water_jet;

This line lists two particle templates, steam_puff and water_jet, which are separated by
the keyword SPC, which designates a space.

Moving an Emitter
Normally, particle emitters cannot be moved via code. However, a hack exists which will
allow you to move emitters to your hearts content. It goes like this:

26

David J. Sushil

davidjsushil@gmail.com

// Create our particle emitter node, and store its ID in %steamObj


%steamObj = new ParticleEmitterNode(){
position = "238 -205.75 191";
rotation = "1 0 0 0";
scale = "1 1 1 1";
dataBlock = steam_source;
emitter = steam_column;
velocity = 1;
};
// At this point, %steamObj is stuck at 238, -205.75, 191
// However, we could...
%steamObj.position = "100 100 191";
// ...set a new position, which does absolutely nothing, unless...
%steamObj.setScale(%steamObj.getScale());
// ...we use the setScale() function to reflexively assign the scale to
// itself, which has the added effect of changing the position.
// Weird, huh? But such is Torque.

Conclusion
Although this tutorial doesnt cover every nook and cranny of Torques particle effects
capabilities, its a good overview. The best thing to do now is practice and experiment.

27

David J. Sushil

davidjsushil@gmail.com

Detailing Your Environment Textures


Introduction
At this point, youre probably comfortable either algorithmically generating or handpainting textures onto your topography. You may have noticed that no matter how nice
your textures look in Photoshop, they always appear stretched and blurry in the Torque
engine. Theres little we can do to improve the way these textures look in-game, but
what we can do is assign additional textures onto the environment which add detail and
pop to your level.
There are two kinds of textures we can use to augment the look of our ground covering.
The first is a detail texture, which is an immediate answer to the problem of stretched and
blocky environment mapping. The second is a bump texture, which gives the illusion of
variations in height.
Perhaps the only problem with detail and bump textures is that they are a blanketed across
the entire environment. Much like the Immortals of Highlander, there can be only one!
While your topography can have multiple, blended environmental textures, detail and
bump maps are the same throughout. This means you need to choose your details and
bumps wisely.

Detail Textures
Detail textures are blended with the environmental textures to create subtle variations at
close range. This helps offset the blurry, patchy nature of the environmental textures.
Details exist in a cone around the player, and diminish as they recede into the distance.
Detail texture files should be 256 x 256 .png or .jpg files with no transparency. In order
to add a detail texture to your map, add the following code into your mission files
TerrainBlock section:
detailTexture = "~/data/terrains/details/detail1";

Change the path and filename to reflect the position of your detail file. Load Torque,
open your mission, and observe the ground.

Bump Textures
Bump textures must be black and white 256 x 256 bitmaps in either .jpg or .png format.
Ideally, such a texture will have a high contrast the higher the contrast, the more
dramatic the effect becomes. To add a bump map to your environment, add the following
code into your mission files TerrainBlock section:
bumpTexture = "~/data/terrains/details/bump.png";
bumpScale = "10";
bumpOffset = "0.075";
zeroBumpScale = "1";

28

David J. Sushil

davidjsushil@gmail.com

Of course, you should change the bumpTexture property to reflect the proper path and file
name for your level.
The bumpScale property affects how stretched the bump texture is on screen. A value of
1 is not stretched at all, which values greater than 1 are stretched, and values less than one
are shrunk.
The bumpOffset property indicates how drastic the effect appears on screen. The greater
the offset, the greater the effect. In general, subtle offsets look best.
The final property, zeroBumpScale, creates a cone around the player where the effect is
present. Any areas outside of the cone will not have the effect applied. This lessens the
strain on the CPU, and quite honestly, past a certain point onscreen, the effect is
indistinguishable from noise, and should therefore be limited.
Once the bump texture properties have been added to your mission file, save it, and load
the mission in Torque. By the way, you can use the World Editor Inspector panel to
tweak the bump settings in the engine without having to restart the engine.

29

David J. Sushil

davidjsushil@gmail.com

Playing Sounds
Generating audio in the Torque engine is a snap. There are very few hoops to jump
through when setting up and playing sound effects.

Descriptions
While it may seem confusing at first, playing a sound requires establishing two objects in
memory an AudioDescription and an AudioProfile. (Yes, I know profile and
description mean the same thing. Tell it to the people who created Torque.)
Lets start with descriptions, since in many ways they are a parent to our profiles. An
AudioDescription is a set of properties that determines how sounds are played in
general. That means that several sounds can share the same AudioDescription.
This will become clear when we look at some code, which well do in just a moment.
First, we need to establish how our sound will be used within Torque. Will it be
localized to our computer or accessible across a network? The answer to this question
will determine which keyword we use to create our sound. Localized audio is created
using the new keyword, whereas networked audio is created using the datablock
keyword, like so:
// Create a localized sound effect, which
// can only be heard on your computer.
new AudioDescription(localized_3D_sound){
volume = 1;
isLooping = false;
is3D = true;
referenceDistance = 1;
maxDistance = 10;
type = $DefaultAudioType;
};
// Create a networked sound effect, which
// can be heard by multiple computers.
datablock AudioDescription(networked_3D_sound){
volume = 1;
isLooping = false;
is3D = true;
referenceDistance = 1;
maxDistance = 10;
type = $DefaultAudioType;
};

Descriptions, whether created via new or datablock, take one argument the name of
the description. In the first description, its localized_3D_sound, and in the second, its
networked_3D_sound.
Lets look at the properties within these descriptions. First we have volume, which is
set to 1, or 100% of the actual volume of the sound file in question. Values greater than 1
will increase the volume of the sound, while values less than 1 will decrease it.

30

David J. Sushil

davidjsushil@gmail.com

Next, the property isLoop determines if the sound in question loops, or plays one time.
Music will probably loop, so a value of true is appropriate. On the other hand, explosions
should only play one time, so a value of false is appropriate.
The is3D property determines whether the sound is ambient or specific to a particular
source. For example, the sound made when you click on a button in a popup window is
ambient it exists outside of the game world. Music is also ambient (unless tied to a
source in-game, such as a phonograph or radio). For these effects, wed set the is3D
property to false. On the other hand, a door opening, glass shattering and dynamite
exploding are sounds tied to a particular source. Their volume and stereo position may
change depending on where they happen relative to the player. In this way, the is3D
property should be set to true.
The next two properties, referenceDistance and maxDistance, are only relevant
if our sound is a 3D effect. The first property, referenceDistance, establishes the
distance at which the audio is played at full volume. In this case, the sound effect will be
played at full volume as long as it occurs within 1 world unit (about 3 meters) of the
player. maxDistance indicates at what point the volume drops to zero. In this case,
the audio will not be heard if it occurs more than 10 world units from the player.
Finally, we have the type property, which indicates what channel the audio will play
from. Torque has three built-in channels, but others can be created. Our example
description uses $DefaultAudioType, which is channel 0. Two other channels are
$GuiAudioType (channel 1), used for the graphical user interface; and
$SimAudioType (channel 2), used for in-game mission objects.

Profiles
Notice how neither of these descriptions reference a particular file? Thats what our
AudioProfile is for. An AudioProfile essentially specifies which sound to play,
and which AudioDescription to play it with.
Profiles, like descriptions, also fall victim to the stigma of being either localized or
networked, and so we again need to determine if we use the new or datablock
keyword. Lets looky codey:
new AudioProfile(explosion){
filename = demo/data/sounds/explosion.ogg;
description = localized_3D_sound;
};

Profiles accept one argument the name of the profile which in this case is
explosion.
Profiles have two properties, filename and description. Filename is simply the
path to our intended sound file. Description is a reference to an
AudioDescription, in this case localized_3D_sound, which we created a few
pages ago.
31

David J. Sushil

davidjsushil@gmail.com

Simple enough!

Playing the Sound


Now that we know how to prepare audio for playing, its time to investigate methods for
actually playing it. As it turns out, we have a few tools in our Torque tool belt.

Playing Sounds Manually


The easiest way to play a sound is by calling the alxPlay() function. We do so like
this:
%obj = alxPlay(explosion_2D);

Wow, that was ridiculously easy! alxPlay() takes one argument, the name of the
AudioProfile for our sound. It returns an ID number, which we store in %obj. This
only works, however, for localized, ambient sounds. Networked or 3D sounds must be
played some other way.

Playing Sounds through the GUI


It is also possible to link sounds to GUI controls. Again, these sounds must be localized,
ambient sounds. Lets take a look:
// The following commands can be executed via
// the console, or planted in functions
// elsewhere.
GuiButtonProfile.soundButtonOver = over_2D;
GuiButtonProfile.soundButtonDown = press_2D;

Both of these properties (soundButtonOver and soundButtonDown) reference the


GuiButtonProfile, which is responsible for the behavior of default buttons in
Torque. Assigning an AudioProfile to either of these properties will cause the sound
to play whenever the mouse moves over the button, or presses the button, respectively.
Now, because these commands are assigned to GuiButtonProfile, they will play for every
button assigned that profile. If you want to assign a sound to a particular button, then that
button should be assigned a unique GUI profile. This is beyond the scope of this tutorial
a topic for another day, so to speak.

Playing Sounds through Special Effects


Finally, sounds may be attached to particular special effects in the Torque Game Engine.
This is accomplished via the soundProfile property of certain datablocks. These
sounds, unlike the other methods, may be either localized or networked, and ambient or
specific.
The execution of these sounds varies across datablock type. Lets look at a few
examples:

32

David J. Sushil

davidjsushil@gmail.com

datablock ProjectileData(arrow_shaft){
// Here we would normally list all of this
// datablocks properties, however we are
// really only interested in
sound = whistle;
};

Here, we create an arrow as a projectile. As the arrow travels through the air, it generates
a whistling sound.
datablock ExplosionData(bloody_arrow_hit){
// Here again wed normally list all of this
// datablocks properties, however we are
// really only interested in
soundProfile = messy_thump;
};

Here, we create an explosion actually, an explosion of gore when an arrow strikes its
victim (yuck!). When the explosion occurs, it plays a messy thump sound, indicated by
the soundProfile property.

How Do I Turn This Thing Off?!


The other side of the audio coin is stopping sound in its tracks. This is particularly
important when playing music.
Remember when we called alxPlay(), and how we stored the sounds ID number in a
variable? Well, we need to reference that ID when we want to stop our sound, which
looks like this:
alxStop(%obj);

Of course, if were playing music, we might want to store its ID number in a global
variable, like $music_ID or something catchy.

33

David J. Sushil

davidjsushil@gmail.com

Animating Characters in Torque


One of the most difficult tasks when working with the Torque Game Engine is the
creation and implementation of custom characters. This tutorial is a starting point for
students who wish to develop their own characters. It is not intended as a definitive guide
to character development other references exist which provide a more in depth
exploration.

Building the Model


The first task in crafting a custom character is building the model. When doing so, the
following heuristics are important to keep in mind:
1. The character should always face towards the positive y-axis
2. The character should be built using Torques world unit scale
3. The character must be an editable mesh
As with all asset modeling, beginning with a clear goal in mind is vitally important to
building a successful character. It is recommended that students build a rough draft
model first, and having perfected the process, go on to build the model a second time for
use with Torque.

The Body
OK, lets begin with a simple enough character a Scuttlebot. Scuttlebots resemble
horseshoe crabs. They are four-legged robots with a tail and a carapace-like frame. They
are also fairly easy to model in 3D Studio Max, so lets get down to it.
Start by clicking the Box tool in the Create panel. Using the Keyboard Entry rollout,
create a box that is 1 x 1 x 1.
In Torque world units, this is about three cubic feet. Its incredibly tiny. In fact, its so
tiny that 3D Studio Max has trouble working with models this small! You will notice
undesirable behavior mostly interface inconsistencies quite often as we work with
character models at this scale. This leaves us wondering, why dont we just build the
model at whatever size we want, and then scale it down later? Unfortunately, doing so
can cause behavior that is even worse than.
Click on the Modify panel, and name your box scuttlebot. Under the Parameters
rollout, give the box 3 height, 3 length, and 3 width segments. This will allow us to
modify the shape of the box. Convert our scuttlebot to an editable mesh by right-clicking
on it, and selecting Editable Mesh from the Convert submenu. You should have a model
that looks like Figure 1.
Now we can begin deforming the shape to our liking. Before we do so, make note of the
world axis in your Perspective viewport. The side of the box that is facing towards the
positive y-axis is the front of our model. Its important that we keep track of where our
model is facing, because Torque doesnt like objects that have been rotated post hoc.

34

David J. Sushil

davidjsushil@gmail.com

Open the Editable Mesh modifier and select the


Vertex tool. Grab the top-most level of vertices,
and using your Select and Uniform Scale tool
scale them all inward. Having done so, select
only the top-most, outer rim of vertices and pull
them down slightly. Finally, grab the top-most
corner vertices, and scale them all inward a
second time. Following these steps will create a
round dome on top of our model, as pictured in
Figure 2.
Next, we want to create flares around the bottom
of the scuttlebot, in order to protect its legs.
Working with the bottom-most layer of vertices,
grab all four corners, and scale them outward
slightly. You should create flares similar to
those in Figure 3.
Were almost done with the main body of our
scuttlebot. What remains is the tail, which we
will create by extruding a face on the rear of the
model.
From the Editable Poly modifier, select Polygon.
Click the polygon which faces towards the
negative y-axis in the middle of the lowest level
of polygons. From the Edit Geometry rollout in
the Modify panel, use the Extrude tool to create a
protrusion from the back of the model, as seen in
Figure 4.
Now, use your Select and Uniform Scale tool to
make the tail begin to taper. Use your Select and
Rotate tool to make the extruded polygon face
upwards slightly. When you have done so, its
time to extrude another polygon from the end of
the tail. Again, scale and rotate this new face.
Finally, extrude a third polygon, and scale it so
that it appears to come to a point. Figure 5
demonstrates how your tail should look when
you have finished.
Finally, lets merge the vertices at the tip of our tail, to avoid problems with texturing
later on. We do so by selecting Vertex from the Editable Mesh modifier. Select all four
vertices at the tip of the tail, and then click the Selected button in the Weld section of the
Edit Geometry rollout panel.

35

David J. Sushil

davidjsushil@gmail.com

Congratulations! Youve created a scuttlebot body. I wish I could say the worst is behind
us, but sadly, it is not. Lets take a moment to save our work, lest disaster strike us
unprepared.

The Legs
Our scuttlebot has four cylindrical legs which move in a shuffling sort of way. In part
due to their inconspicuous placement under the model, we can skimp a bit on precise
animation. This is, after all, more a tutorial on interfacing with Torque than it is a treatise
on picture-perfect animation.
Begin by creating a cylinder that is 0.25 units
high, with a radius of 0.1. You can do so by
clicking on the Create panel and choosing the
Cylinder tool. I recommend using the Keyboard
Entry method of creation creating it by hand at
this scale in 3D Studio Max can be problematic.
Under the Modify panel, give the cylinder 1
height segment and 12 sides. By default, the
cylinder will be placed dead-center in your
model. Using your Select and Move tool,
position the cylinder roughly where the frontright leg should be. The numerical position of
this front-right leg is (-0.35, 0.35, -0.25), if
youre keeping score. Check out Figure 6 for a
reference.
Next, we need to clone this leg three times, positioning each clone where a remaining leg
should be. We can do so by clicking on the Select and Move tool, holding down the shift
key, and clicking and dragging on our original leg. Doing so pulls out a cloned copy of
the leg. You will be presented with a Clone Options dialog box simply make sure the
Object is set to Copy, and click OK. The remaining legs should be positioned according
to the following coordinates:
(0.35, 0.35, -0.25)
(0.35, -0.35, -0.25)
(-0.35, -0.35, -0.25)
At this point, your model will look similar to Figure 7. If so, we can attach the legs to the
body. Do so by first selecting your scuttlebot body. From the Modify panel, click Attach
List, located in the Edit Geometry rollout. Select all the cylinder objects from the list
these are our legs and click the Attach button. Now, our four leg cylinders have been
merged into the body mesh, and our scuttlebot is one solid piece.
If youd like, you can take the time to further refine your scuttlebot model, but for our
purposes, its lookin good, and we can move on to animating the object.

36

David J. Sushil

davidjsushil@gmail.com

Adding Animation
Torque has some nifty animation options available. First and foremost, if youre
animating a humanoid character, theres a better than average chance you dont even need
to worry about animation. The reason for this is that Torques poster boy and stock
character, Kork, comes with preset animations stored outside of his .DTS model file.
These stock animations can be utilized by any biped character that possesses a similar
bone structure to Kork.
Our scuttlebot, on the other hand, is not a biped (its a quadruped), so we need to create
our own custom animations. We begin by setting up a skeleton.

Creating the Bone Structure


The cornerstone of good animation is a well-crafted bone structure. We will create one
by accessing the Bone Tools dialog, available from the Character menu in 3D Studio Max
8, and the Animation menu in 3D Studio Max 9.
The Bone Tools dialog will allow us to create individual bones in a chain, as well as to
link chains together to form a skeleton. Its important to always start a chain from the
center of the character and work your out for example, start with the shoulder and create
out towards the fingertips, not the other way around. Doing so makes the difference
between the dog wagging the tail and the tail wagging the dog. Our scuttlebots pelvis
will be the root bone for our entire model everything else stems from this point.
Lets begin by creating the bone chain that begins with the pelvis and works its way out
towards the head. We will need to create six bones altogether the pelvis, three
vertebrae, a head, and a final bone called eye, which we will discuss shortly. To create
this chain, click on the Create Bones button in our Bone Tools dialog. Now, because
were working on such a small scale, our bones will be enormous if we begin creating
them now. First, from the Create panel, set the Bone Object Width and Height to 0.1
each. That way they will fit the size of our model properly.
With the Create Bones tool selected, position
your cursor in the Top viewport, just where our
scuttlebots hips would be, and click one time.
This sets the base for our pelvis. Clicking a
second time will end the pelvis bone and begin
the first vertebra. Make the pelvis just a square
block. Each vertebra you set should be longer
than the pelvis, however the head should be
about the same size. Finally, once you have set
the base of the eye bone, right click to end the chain. Your bone chain should resemble
the one in Figure 8.
While naming your bones for custom animation is not necessary, its still good practice.
Someday you might want to borrow Korks animations (or better yet, have your own
custom characters borrow animations from each other), and its important to rehearse the

37

David J. Sushil

davidjsushil@gmail.com

conventions Torque expects for such an occasion. The names of bones in Torque are
borrowed from 3D Studio Maxs Biped character, so a handy reference is available at any
time from the Create panels Systems mode. In general, each bone begins with a Bip01
prefix, such as Bip01 Pelvis. Bip01 is always followed with a space (one of the few
times a space is allowed to be exported from a 3D Studio Max model to Torque), and
then the name of the bone. Repetitive bones, such as vertebrae, follow a pattern like this:
1. Bip01 Spine
2. Bip01 Spine1
3. Bip01 Spine2
4. Bip01 SpineN (where N is the total number of bones in the chain, minus one)
The only bones that dont follow this naming convention are special objects, three of
which well address in a moment. Lets go ahead and name these bones, like so:
1. Bip01 Pelvis
2. Bip01 Spine
3. Bip01 Spine1
4. Bip01 Spine2
5. Bip01 Head
6. eye
That last one isnt a mistake. Eye is a special bone which Torque uses to control the
placement of the camera when in first-person mode. By linking eye to our Bip01 Head
bone, we can make sure that when the character moves its head, the camera moves with
it.
Before we proceed, check to make sure that this bone chain is not only centered in the
Top viewport, but passing through the middle of the bottom row of polygons in your Left
viewport.
Now, lets set two bones for our scuttlebots
front right leg. These bones are Bip01 R
UpperArm and Bip 01 R ForeArm (notice the R
qualifier on the opposite side, well use L
instead). The first bone will begin at the top of
the cylindrical leg and end about halfway down,
at which point the second bone begins and
continues to the bottom of the cylinder. Be sure
to check your Top viewport as well, and
position the bones central to the cylinder according to that perspective as well. Use
Figure 9 as a reference if youre unsure of how to proceed.
Just like we did with our original leg cylinders, we can clone this bone chain and position
the copies in their respective locations. The names of the remaining bones are:
1. Bip01 L UpperArm and Bip01 L ForeArm
2. Bip01 R Calf and Bip01 R Foot
3. Bip01 L Calf and Bip01 L Foot

38

David J. Sushil

davidjsushil@gmail.com

The final bone chain is the tail. Add three bones, one for each of the extrusions we
created. Name them Bip01 Tail, Bip01 Tail1, and Bip01 Tail2, respectively. When you
are finished, your bone structure should look like that which is pictured in Figure 10.
Finally, we must link our bone chains together
into one skeleton. We do so by first selecting
the Bip01 Pelvis bone. In the Bone Tools
dialog, click on the Connect Bones button.
Moving the mouse over your active viewport,
you will notice a dashed line that follows your
cursor around. Click on the Bip01 L Calf bone,
and a new bone will appear. Rename the bone
Bip01 L Thigh. Reselect the pelvis, and click
the Connect Bones button again. This time,
click on the Bip01 R Calf bone. Again, a new
bone will appear. Rename it Bip01 R Thigh.
Repeat this process for the font legs, connecting
the Bip01 Spine2 bone to the UpperArm bones.
The connecting bones should be renamed Bip01
L Clavicle and Bip01 R Clavicle. Finally, create
a Bip01 TailBase bone that connects the pelvis
to the tail. Your skeleton will now resemble the
one pictured in Figure 11 (Ive hidden the model
so you can see the entire bone structure).
Were almost done with dem bones. We need
only create one more chain, consisting of two
bones: unlink and cam. These bones dont
animate our character at all. Instead, Torque
uses them to position the over-the-shoulder camera when not in first-person mode. To
create this chain, click on the Create Bones button, and in your Left viewport, create a
bone which begins just before the back legs, and rises up through our scuttlebot and
above the shoulders. After setting unlink, right click to set cam. Name both of the bones
accordingly. Your finished model will look like the one pictured in Figure 12.

Skinning the Model


Our next step is to add a Skin modifier to our scuttlebot model. Skin will bind the model
to the bones, so that whenever a bone is moved, the model will deform according to the
movement.
This is a fairly simple procedure. First, click on the scuttlebot model. From the Modify
panel, click on the Modifier List, scroll down, and select Skin. From the Parameters
rollout, click the button labeled Add, which appears to the right of the word Bones. From
the dialog box that appears, select all of the bones which will deform the model. That is,
everything except eye, unlink, and cam.

39

David J. Sushil

davidjsushil@gmail.com

Now, the model acts like skin around the bones. We can test this by clicking on our
Bip01 L ForeArm bone, and using the Select and Move tool to reposition it. If our Skin
modifier was setup properly, the front left leg should move in unison with the bone.
You may notice that the front right fender around the leg also moves. Thats OK for now.
This is not a tutorial on animation, so much as it is a tutorial on properly interfacing with
Torque. We can always refine the animation later.
PS: Save your work!

Keyframing Animation
With our recently skinned scuttlebot (that sounds gross, doesnt it?), we can begin to craft
animation for use with Torque. We will create two animation sequences a default idle
animation, and a walk cycle animation. Lets begin with the more difficult walk cycle.
For simplicitys sake, select the eye, cam, and unlink bones, and hide them from the scene
by right-clicking and selecting Hide Selected from the popup menu. Now, were only
working with the bones that deform our model.
To animate our model, well need to use the timeline at the bottom of the screen. See the
button marked Auto Key? Click it. Our timeline becomes red, which serves as a warning
that were no longer working with a static model, but a dynamic model that changes over
time. If youre done animating at any point, click the Auto Key button again to return our
timeline to its normal gray color.
Next, click on the Bip01 R ForeArm bone. Were going to animate the bone swinging
forward, then back, then forward again. Using your Select and Move tool, position the
bone slightly closer to the head of the model, which will deform the front right leg into a
forward-stepping position.
When you are satisfied with the placement, click the button below the timeline that looks
like a key. Notice how a box has been added to the timeline on frame 0? Thats a
keyframe. 3D Studio Max and Torque create animation by computing the look of the
model based on transitions between keyframes. This saves us time instead of animating
each frame, we animate a few keyframes, and Max and Torque do the rest of the work for
us. Fancy that!
Now, we need to drag our timeline slider out to about frame 15. Using your Select and
Move tool again, swing that front leg bone into a backwards position. Set the keyframe
by clicking the key button below the timeline.
Now, you can test your rudimentary animation by dragging the timeline slider back and
forth between frame 0 and 15. If youve followed this tutorial correctly, the leg should
swing forward and backward with the slider.

40

David J. Sushil

davidjsushil@gmail.com

We need to set one final keyframe for this bone


at frame 30. This time, swing the bone back
into the forward stepping position. It should
match frame 0 almost exactly. Set the
keyframe, and test the animation by dragging
the timeline slider back and forth.
One leg down, three to go! Follow the same
procedures to animate the front left leg, back
right leg, and back left leg. They should all
share keyframes 0, 15, and 30, in order to march
in step with each other. Check out Figures 13
through 15 for a play-by-play example of how
your model should look at each keyframe.
This completes our walk cycle animation. The
next item on our to-do list is an idle animation,
which is easy enough. Our idle animation will
begin on frame 31, and run to frame 41 (10
frames altogether). It will consist of our
scuttlebot wagging its tail happily, in
anticipation of its next great adventure, scuttling
here and there in the ignorant bliss of a robotic
consciousness.
OK, move your timeline slider to frame 31. For each of the four leg bones you worked
with in the walk cycle, set a keyframe which positions them in a downward position. Set
keyframes at frame 41 for each leg as well. This pins the legs into a standing position
immediately after the walk cycle ends and for the duration of the idle cycle.
Now, click on the last tail bone. For frame 31, set a keyframe with the tail off to one side.
Set the timeline slider to 36, and set a keyframe with the tail off to the opposite side.
Finally, move the slider to frame 41, and set a keyframe which matches the tails position
with that of frame 31.
Be sure that when youre satisfied with your animation, you click the Auto Key button to
turn off animation mode in 3D Studio Max.
Were finished with the animation section of this tutorial. Keep in mind, you can add
additional animation sequences to the timeline. Just make sure the next one starts on
frame 42. In the next section, well look at how we interface our 3D Studio Max model
with the Torque Game Engine.

Preparing to Export
Its important that we properly prepare our model for use with Torque. There are a
handful of hoops to jump through, but once youve practiced the routine a few times,
41

David J. Sushil

davidjsushil@gmail.com

those jumps will begin to make sense. By the way, whenever Torque starts to make
sense, immediately shut down your computer, visit a pleasant park in your city or town,
and consider therapy.

Initial Preparations
In order to export your model, youll need to access the Torque DTS Exporter utility. If
youve never used this tool before, I recommend reading the Importing Assets From 3D
Studio Max tutorial.
Like every other model, we need to renumber and embed the shape. So make sure youve
selected our scuttlebot, and click the Renumber Selection button from the Utilities panel.
In the Renumber dialog box, type 2 and click OK. This renames our scuttlebot to
scuttlebot2. Then, click the Embed Shape button, but only one time. This button
creates a few helper objects in our scene Start01, Base01, and Detail2. It otherwise is
not apparent that it worked, so check your Select by Name tool to make sure theyve been
added.
Next, we need to add a bounding box to our scene. Using the Box tool from the Create
panel, create a shape that encompasses the entire model. Name this box bounds. Its
important to note that we should not resize bounds using the Select and Uniform Scale
tool. Although the size will change in 3D Studio Max, it will not change in Torque. This
is because scaling geometry is much like adding a modifier to the object, which Torque
doesnt understand. Instead, use the properties in the Parameters rollout, located within
the Modify panel, to change the size of our bounding box.

The Schematic View


Open your Schematic View window by clicking on the Schematic View (Open) button in
the toolbar the one that looks like an orange box pointing at a gray box. This window
contains a representation of the relationships among objects in our scene. We need to
make a few changes to these relationships in order for Torque to be happy.
First, we need to disconnect scuttlebot2 from start01. Normally, this is exactly the way
our scene should be setup, however, since we have a bone structure in the mix, we need
to make this adjustment. In order to disconnect scuttlebot2, click on its representative
box in the Schematic View, and click the Unlink Selected button in the toolbar. Leave
scuttlebot2 hanging out on its own it doesnt need to be connected to anything in our
scene (hes a loner, anyhow).
Next, we need to link our Bip01 Pelvis object to start01. In order to do so, click on Bip01
Pelvis, then click the Connect button in the toolbar. Moving your cursor into the
Schematic View window, you will notice a dashed line following the mouse. Click on
start01 to link the pelvis as its child.
As usual, bounds remains on its own. So too does unlink and cam. Check out Figure 16
for an example of how your Schematic View should look. Dont freak out if youre
missing objects called root and run well create those in the next section.

42

David J. Sushil

davidjsushil@gmail.com

Animation Sequences
Next, we need to add a few helper objects which tell Torque where to locate our
animation sequences. These helper objects can be accessed from the Create panel by
clicking on the Helpers button (it looks like a white box with a circle in it). From the
dropdown list just below the Helpers button, select General DTS Objects. Next, click the
Sequence button, and create a sequence objects in the Perspective viewport by clicking
and dragging. Name the object run. Run is a special name that Torque recognizes.
Run animation is played you guessed it whenever the player causes his avatar to run.
Create a second sequence object and call it root. Root is the special name Torque
understands for idle animation. There is a whole list of these special animation names,
and you can of course create your own. Its best to plug in to the engine as often as
possible, so utilizing existing names for animations is highly recommended.
A comprehensive list of the existing animation names is available in the player.cs file,
which is located in demo/data/shapes/player/. What follows is a partial list of some of the
more common animation names, and a brief description of their purposes:

43

David J. Sushil

Name
root
run
back
side
fall
land
jump
standjump
deathN

davidjsushil@gmail.com

Description
Idle animation the avatar is not doing anything
Moving forward
Backpedaling animation (running backwards)
Strafing animation
Falling animation
Landing animation
Jumping animation when the avatar is moving
Jumping animation when the avatar is standing still
Death animation (replace N with a number from 1 to 10)

Once we have created our sequences, we must take one final step to let Torque know
where they begin and end on our timeline. We do so by opening the Curve Editor, which
is accessed by clicking the Curve Editor (Open) button on the toolbar, which is located
left of the Schematic View (Open) button.
With the Curve Editor window open, click the plus sign to the left of the Objects item on
the left side of your screen. Locate root, and expand it as well. Within root is an item
called Object (Sequence II). Expand it, and click on Sequence Begin/End. Now, we need
to add keys on the chart which designate where the root animation begins and ends. To
do so, make sure you have the Add Keys button highlighted in the toolbar, and click on
the timeline at positions 31 and 41. If you accidentally misplace a key, you can move it
by highlighting the Move Keys button.
Next, repeat the above steps with the run animation, but set the beginning and end keys to
0 and 30. When youve done so, you can close the Curve Editor window. Were almost
done!
One final note on animation sequences you need to designate whether your animation
loops or whether it plays only once. For example, running is a cyclic sequence, whereas a
death animation is non-cyclic. It would look rather silly if our character died over and
over again, or if our character ran through one walk cycle and then glided everywhere.
We can designate a sequence as cyclic or non-cyclic by toggling the Cyclic Sequence
check box in the Modify panel of any given sequence object. By default, all sequences
are cyclic, so we dont have to worry about root or run.

Utilizing the Model in Torque


Finally, were ready to reap the rewards of our hard work. Before we do, lets make a
backup copy of the existing player model Kork. Navigate to demo/data/shapes/player
in your Torque directory. Locate player.dts, and make a copy of the file. That way, we
can always bring Kork back into action.
To export your custom character model, click the Whole Shape button in the Utility
panel. In the Export DTS window that appears, navigate again to
demo/data/shapes/player in your Torque directory, and save your file as player.dts. If all
44

David J. Sushil

davidjsushil@gmail.com

goes as planned, you should be able to open Torque and immediately see that your player
model has replaced Kork. If so, congratulations on building your very own scuttlebot! If
not, well, the next section is for you. Good night and good luck

Troubleshooting
There are any number of ways to screw up a character model in Torque, and if youre
reading this section, you most likely discovered at least one of them. Take a deep breath.
Ill walk you through some of the more common errors you may encounter.

Assertion Failed on Skin Object


Lets start off with an easy one the ol Assertion Failed on Skin Object error. What
Torque means to tell you is that your model is not an editable mesh. Its probably an
editable poly. To fix this error, click on your scuttlebot and go to the Modify panel.
Delete the Skin modifier on your object by right-clicking on it and hitting Delete. Right
click on your scuttlebot and select Convert to Editable Mesh from the Convert To
submenu. Add another Skin modifier to the object, and re-add all your bones. Export the
model again and the error should not appear.

Skin Found on Linked Node


If this error appears, it means you most likely forgot to replace your character model with
Bip01 Pelvis as a child of the start01 object in the Schematic View. Re-read the section
titled The Schematic View. In short, disconnect your character model from start01, and
connect the root bone of your skeleton (most likely the pelvis) instead.

Bones are Visible in Torque


Sometimes a characters bones are visible in the engine. This can be remedied one of two
ways. First, make sure the bone is properly positioned within the model, and that no parts
of the bone are protruding in 3D Studio Max. You can also set the bone Width and
Height to smaller values in the Modify panel. If youre still having problems, its
probably because the bone has a trailing number in its name for example, Bip01 Spine2.
If the trailing number (in this case, 2) matches the trailing number of your character
model (say, scuttlebot2), then Torque thinks the bone is supposed to be rendered.
Rename the bone to Bip01 SpineTwo, or Bip01 Spine-2 (negative two). Either way,
the bone should stop appearing in the engine.

Character Faces the Wrong Way, or is Rotated


The easiest way to avoid this error is to make sure that you keep track of where your
model is facing in 3D Studio Max. By default, all character models should face towards
the positive y-axis. Rotating a model into this position later on is dicey at best, so be sure
to get it right the first time! This may also occur because you rotated an object in the
scene (say, a cylinder for an arm), and then attached the entire model to the rotated object,
which may have the effect of rotating the entire model out of whack. Try to attach such
objects to the main body, instead of vice-versa.

45

David J. Sushil

davidjsushil@gmail.com

Creating Doors in Torque


Introduction
One truffle conspicuously missing from Torques assorted box of datablocks is the ability
to create a door. This tutorial will address some basic techniques for making triggered
entranceways. Well start by building a simple animated object in 3D Studio Max, and
then explore two programming methods for interfacing the models in Torque.

Building the Model


The first thing we need is a door model. Of course, you can create whatever kind of door
youd like a Star Trek style sliding door, a boulder that rolls away from a cave entrance,
or a drawbridge that lowers. In this tutorial however, we will create a free-standing door
and frame with a handle. We are preparing this model for the purpose of animating it
swinging inward. If you're pretty comfortable with your modeling skills in 3D Studio
Max, then you can probably skip this section.

The Basic Model


We begin by using the Box tool in the Create
panel. Our intention is to make a door frame,
and we will do so by creating a compound
object.
First, make a box that is similar to the one
pictured in Figure 1. Be sure that it has only one
length width and height segment each, and name
it Frame. Make a copy of frame using Edit >
Clone, and name the copy Subtract. Modify
Subtract to be somewhat shorter and less wide
than the original box. Finally, in anticipation of
later steps, let's clone Subtract and name the
copy Door. We'll use this copy in just a
moment. For now, go ahead and hide it so it's
not in the way.
Next, select Frame, and from the Create panel,
select Compound Objects instead of Standard
Primitives. Click the Boolean button. This will
allow us to use Subtract to cut away the inside
of Frame. In order to do so, we must identify
Subtract as our Operand B. Click the Pick
Operand B button, and then select Subtract.
You should be left with an object that looks like
the one in Figure 2. If so, convert it to an
editable poly so Torque will understand it later.

46

David J. Sushil

davidjsushil@gmail.com

Unhide Door, and modify its dimensions so it is not quite as thick as the surrounding
frame (most doors aren't flush with their frames, after all).
We also need to create a doorknob for each side of the door. This can be done by placing
a couple of boxes, cylinders, and spheres in the proper positions. You can see the
finished door (with textures applied) in Figure 3. Name the additional objects Panel,
Shaft, and Knob. To designate which side they belong on, append the names with Front
or Back. Remember that adding trailing numbers (like 2, 3, 4, etc.) designates levels of
detail, and may result in objects missing in your game.
To make things easier for animation, go ahead and group Door and your doorknob objects
by selecting them all and selecting Group > Group from the menu bar. Name the
selection Doorswing.
We've now completed our door model. In the next section, we'll look at how to animate it
properly.

Animation
Now that we have our door object constructed, we need to create two animation
sequences - one where the door swings open, and the other where the door swings closed.
Before we begin keyframing these animations, we need to edit the center of gravity for
Doorswing. At the moment, if we rotate the door, it will rotate around the center, much
like a revolving door would. This is because the Pivot point of our door is aligned to its
center. To align the Pivot point to the doorframe, select Doorswing, and from the
Hierarchy panel, select Affect Pivot Only. The Pivot will appear in the scene as a thick
red, blue, and green tripod. You can then use your Select and Move tool to align the
Pivot to the edge of Frame. With the Pivot repositioned, turn off Affect Pivot Only.
We're now ready to animate the door.
As with any animation, we begin by turning on Auto Key mode, located below the
timeline in 3D Studio Max. Select Doorswing. We will set four keyframes on the
timeline, representing the door at four stages:
Frame
0
35
36
71

Physical Description
The door completely closed
The door completely opened
The door completely opened
The door completely closed

Sequence Position
Start of the Open sequence
End of the Open sequence
Start of the Close sequence
End of the Close sequence

Once you have finished animating these sequences, be sure to turn Auto Key off otherwise additional changes to your scene might be contingent on the timeline, which is
never good. By the way, if you are unfamiliar with how to keyframe animation, please
see Animating Objects in Torque for additional instructions.

47

David J. Sushil

davidjsushil@gmail.com

Interfacing with Torque


With our model built and our basic animation complete, we now focus our attention on
preparing our door for use in Torque. This consists of three steps: first, embedding our
shape like any other object; second, creating an animated collision mesh; third, creating
sequence objects that indicate where our animations begin and end.
The initial step - embedding the shape - should be familiar to you by now. By way of a
refresher, we will briefly recall the steps necessary for a proper export. First, select all the
objects which will appear in your scene (Frame and Doorswing, and anything else), and
click the Renumber Selection button in the DTS Exporter Utility rollout of the Utilities
panel. Assign the selection the number 2. Next, click the Embed Shape button, which
assigns helper objects to your scene. Check your Schematic View window to make sure
all the normal helper objects are present and that your objects are connected to them
properly. Your schematic view window should look similar to Figure 4.

In addition, we need to create a bounding box (bounds), which encompasses the all
visible objects in our scene. Bounds is not linked to anything in our Schematic View, and
it may be hidden from sight once created.
The next step is to create our collision meshes - Collision-1 and Col-1 - and animate them
to match the motion of Doorswing. From the Create panel, select the Box tool and create
a primitive that roughly matches the size of Doorswing. Name it Collision-1, and convert
it to an Editable Mesh. Clone it, and name the copy Col-1. Animate both shapes using
the same techniques outlined in the Animation section above - including moving the
Pivot point.
When you have finished, be sure to link Collision-1 and Col-1 to their parents in the
Schematic View - base01 and start01, respectively.
Finally, we can create our sequence objects. These objects will be named Open and
Close, and they correspond with the animations we created previously. Use the Sequence
button - located in the General DTS Objects dropdown section of the Helpers panel. It is
very important that you set both sequences to be non-cyclic - that is, uncheck the Cyclic
Sequence box in the Modify panel for both sequences.

48

David J. Sushil

davidjsushil@gmail.com

You also need to use the Curve Editor window to designate where each sequence begins
and ends on the timeline. Do so by clicking the Curve Editor (Open) button on the
toolbar. Find the Open sequence, and drill down through its menus until you find the
Sequence Begin/End controller. Set keys on the timeline at 0 and 35. Repeat the process
for the Close sequence, but set the keys to 36 and 71.
At long last, we are ready to export our model. Of course, it won't function properly yet,
but we can at least check it out in the Torque Game Engine and see if it looks nice.
Export the shape by click the Whole Shape button in the Utility panel. Save the model in
your Torque file hierarchy, preferably in demo/data/shapes/door/door.dts.
Next, we'll explore how to code door behavior in TorqueScript.

A Whole System of Doors


Create a new .cs file in demo/data/shapes/door/ and call it door.cs. This file will contain
all of the code necessary for a functioning door. Add the following lines of code:
datablock StaticShapeData(door){
shapeFile = "demo/data/shapes/door/door.dts";
};
datablock TriggerData(doorTrigger) {
tickPeriodMS = 1000;
};

These statements create two datablocks - a StaticShape called door, which references our
door model, and a Trigger called doorTrigger, which we will use to execute our
animations in the engine.
Next, we need a function that will create instances of these datablocks. We'll call this
function addDoor(), and it looks like this:

49

David J. Sushil

davidjsushil@gmail.com

function addDoor(){
%doorObj = new StaticShape(){
position = "233.3 -206.45 191";
scale = "0.05 0.0575 0.0505";
rotation = "0 0 1 -90";
datablock = door;
};
%obj = new Trigger(){
position = "232.3 -205.25 191";
scale = "1 1 1";
rotation = "0 0 0 0";
dataBlock = doorTrigger;
polyhedron = "0.0000000 0.0000000 0.0000000 2.0000000
0.0000000 0.0000000 0.0000000 -2.0000000
0.0000000
0.0000000 0.0000000 2.0000000";
doorID = %doorObj;
};
}

These two statements basically instantiate copies of our datablocks, assigning them to a
particular location in the level. You will of course need to alter the position, scale, and
rotation of both objects to correspond with their location in your level.
Notice our new Trigger stores the ID number of the StaticShape door we just created. If
you wanted, you could create a whole network of doors in your level, simply by copying
these two statements and altering the transform data in each (position, scale, rotation). So
long as your Trigger stores the ID number of its accompanying StaticShape, the system
will work.
Now that we have a door and trigger in our level, we need code to animate them. The
code is as follows:
function openDoor(%id){
%id.playThread(0, "open");
}
function closeDoor(%id){
%id.playThread(0, "close");
}

Each function takes one argument - the ID number of the door - which it uses to call
either the Open or Close animation sequence we created in 3D Studio Max.
Now all we need are the trigger events which call these two functions. They are:

50

David J. Sushil

davidjsushil@gmail.com

function doorTrigger::onEnterTrigger(%trigger, %this, %obj){


openDoor(%this.doorID);
}
function doorTrigger::onLeaveTrigger(%trigger, %this, %obj){
closeDoor(%this.doorID);
}

This file is finished. You can test it in Torque by loading your mission, pulling up the
console (~), and running the following two lines of code:
exec("demo/data/shapes/door/door.cs");
addDoor();

By walking up to the door, it should open. When you walk away, it should close.
Mission accomplished!

51

David J. Sushil

davidjsushil@gmail.com

Baking Textures for Greater Realism


A significant difference between game engines and 3D rendering programs is that the
former are on a tight schedule, while the latter have all the time in the world. 3D Studio
Max, Maya, and Blender are the languishing love interests in an F. Scott Fitzgerald novel,
lounging by a pool somewhere. They can afford to take a few minutes to render a single
frame. Torque, Unreal, and other game engines, on the other hand, must render
approximately 30 frames a second in order to present the illusion of motion on screen.
As a result, real-time games may never look as realistic as their cinematic counterparts.
In order to fudge a more realistic look, however, we can use some of the tools in 3D
Studio Max to assist Torque. One way we can do this is by baking textures.
Baking is the process of updating a models texture to include details like shadows. That
way, we dont have to worry about rendering the shadow in 3D (which is a resource
intensive process); rather, we can simply use a texture with a pre-rendered shadow. This
will give your in-game assets a more polished look.
The following sections will walk you through how to bake shadows into your textures in
3D Studio Max in such a way that Torque wont mind.

Preheat the Oven with Lights


Open an existing model, or create a new one. Im going to assume that youre applying
your textures via an Unwrap UV modifier. You dont have to, by the way, but they look
so much better than a tiled texture, dont you think?
Once your model and textures are set, its time to add a few lights. The trick here is to
simulate what the lighting conditions will be like in the game. The more accurately you
can represent the lighting in your level, the more realistic your baked textures will look.
Adding lights seems like a fairly simple process. In truth, selecting the perfect color,
position, and intensity for multiple lights is a skill that takes years to hone. Were not
going to dissect lighting theory in this article other resources exist which provide much
more detail.
To add a light to your scene, click on the Lights button in the Create panel. There are
several light types to choose from, but well stick with Omni lights. Omni lights are
useful for casting light rays in all directions. Since were probably only working with a
single model in your scene, Omni lights seem like a simple and useful choice. To place a
light, select the Omni button, and click anywhere in your scene. Moving the light around
will provide a basic example of how your model will look when lit in-game.
From the Modify panel, check the On box in the Shadows field, and select a shadow
rendering method from the dropdown list box there as well (Adv. Ray Trace work well
enough). By default, 3D Studio Max will shade textures according to how light dances
across your models vertices. By turning shadows on and selecting a rendering method,
we will ensure that additional objects in the scene will have actual shadows cast on them.

52

David J. Sushil

davidjsushil@gmail.com

This may be useful, depending on how youre planning on using the baking technique.
For example, if youre creating a desk object with all sorts of widgets sitting on it, then
we want to make sure that each widget leaves a dark mark on the surface of the desk.
Of course, one light probably isnt enough. Think about when youre getting your portrait
taken at a studio. You have ambient lighting from the room in general, as well as a
spotlight off to the side somewhere, and the flash from the camera. Thats a minimum of
three light sources. Likewise, we may need to light our object from various angles.
When youre finished placing and adjusting lights, were ready to move on to the actual
baking of textures.

Bake at 450 for 20 Minutes


Now comes the process of baking our textures. I highly recommend saving your model at
this point. We want to make sure that if (when?) Torque rejects our attempts, we can
easily revert to a pre-baked model.
Here goes nothing. Select all the objects in your scene that are receiving the baking
treatment. Then, from the Rendering menu, select Render to Texture. A dialog box will
appear with plenty of options. Heres what you need to know:
Under the General Settings rollout, change the Path textbox so it coincides with
the path of your actual textures.
Under the Output rollout, click the Add button, and select Complete Map. This
will add lighting, shadows, and a whole bunch of other details that one day you
might find useful.
Under the Baked Material rollout, select Output into Source. This will overwrite
your original textures, so make sure you have backup copies before you proceed.
Click the Render button at the bottom of the dialog box. This renders the lights
and shadows directly onto your existing textures.
At this point, you can delete (or hide) the lights in your scene. You may also have to
update each material to be visible in the viewports 3D Studio Max may reset them to
the default setting of invisible. Simply click the Show Map in Viewport button for each
material in the Material Editor window.
By the way, make sure those newly baked textures are in a format Torque supports - .JPG
or .PNG.

Allow to Cool 2 Minutes, Serve


As long as youre satisfied with the look of your baked model, now would be a good time
to try exporting it for use in Torque. Import your model into the engine, and notice how
much nicer it looks with pre-rendered shadows!
Baked textures, by the way, pair nicely with a vintage Pinot noir.

53

David J. Sushil

davidjsushil@gmail.com

Simple AI in the Torque Game Engine


Torque excels at creating first-person shooter games. And where would any respectable
FPS be without deadly accurate AI to challenge the player? This tutorial presents a very
basic example of how artificial intelligence can be utilized in the Torque Game Engine.
It takes a least amount of code approach to AI programming, a topic which is covered
in much greater detail in any number of excellent books and websites.

Overview
The code we will work on in this exercise is only one possible way of adding AI to your
project. I state this only to alleviate any future frustrations you might encounter in using
the code provided below. Its a start a jumping off point for your future masterpieces
but its not a total solution. In many cases though, it should work in a pinch.
What we want to create is a system where AI bots can be spawned with a single line of
script, which, for example, could be called when the mission begins, or when the player
passes through a trigger.
We also want to establish a system that allows for multiple AI styles. That is, if all bots
acted the same way, the game would become boring. This tutorial will demonstrate how
we can control (and even switch) AI styles.
Finally, we need a way to periodically update our AI. Thankfully, Torque makes this easy
with the schedule function, which we will utilize in this example.

Adding a Bot
Torque comes with preset dummy characters known as PlayerBodies. These are
represented by Torques poster boy, Kork the Orc (quite a sense of humor there at
GarageGames, eh?). Much of the PlayerBody functionality can be found in aiPlayer.cs, a
file located in the demo/server/scripts/ folder. I recommend looking over this file for
additional help with activites such as pathfinding. Since our AI bots are more of a
deterministic variety, well forego much of this file for a more simplistic approach.
To add a bot, use the following code:
%bot = new AIPlayer(){
datablock = PlayerBody;
position = "100 100 100";
};

In this way, the ID number of the bot will be stored in %bot, we inherit characteristics
from the PlayerBody datablock, and place the bot at 100, 100, 100 on the map. Of
course, that position needs to be updated to reflect your particular level. This will spawn
an instance of Kork in the level, however he wont do much. He just kinda starts there,
all awkward and stuff.
Lets take this code a bit further and add it to a custom function, called addBot. AddBot
takes four arguments, an AI style, and position information.
54

David J. Sushil

davidjsushil@gmail.com

function addBot(%style, %x, %y, %z){


%bot = new AIPlayer(){
datablock = PlayerBody;
position = %x @ " " @ %y @ " " @ %z;
botID = 0;
style = %style;
};
}

Now, if you want to add a bot to your level, you can simply call the addBot function with
a style and position for each bot, like so:
addBot(0, 100, 100, 100);

Still, no action on the part of Kork. But we have added two new properties. The first is
botID, which we will use throughout the exercise. Currently, its set to zero. After the
new block that creates our bot, add the following line:
%bot.botID = %bot;

Now, we can more easily keep track of the bot.


The second property weve added is style, which we will use to control how the bot
behaves.
Finally, lets give Kork a crossbow. Below the new block that creates the bot, add the
following line:
%bot.mountImage(CrossBowImage, 0);

Still, no Kork just sits there. Thats where the updateBot function comes in handy. Well
write the function in the next section, but for now, add the following line:
updateBot(%bot.botID);

Updating the AI
The updateBot function takes one argument, the ID number of an AI bot. In this function,
well make sure the agent always has ammunition for the crossbow. Also, well
determine how far the bot is from the player. Then, well execute an IB behavior based
on style. Finally, well schedule the updateBot function to be called sometime in the near
future.
First, lets create a new function called updateBot, like so:
function updateBot(%id){
// CODE GOES HERE
}

Within the function, you can give the bot ammunition for the crossbow by calling:
%id.incInventory(CrossbowAmmo, 1);

This ensures at least one shot per update, however depending on your implementation,
you may want to adjust the number of shots between executions.

55

David J. Sushil

davidjsushil@gmail.com

Next, we need to determine how far away the player and the bot are from each other.
This is sadly more complicated than it needs to be in Torque. The engine stores position
information as a single string, instead of three separate numerical values. To parse out
each x-, y-, and z-coordinate, we have to use the getword function, like so:
%botX = getword(%id.getTransform(),0);
%botY = getword(%id.getTransform(),1);
%botZ = getword(%id.getTransform(),2);
%playerX = getword($gspPlayer.getTransform(),0);
%playerY = getword($gspPlayer.getTransform(),1);
%playerZ = getword($gspPlayer.getTransform(),2);

Finally, we can use the values stored here to determine a distance:


%distance = mSqrt((%playerX - %botX)*(%playerX - %botX) + (%playerY
- %botY)*(%playerY - %botY));

For the moment, well skip executing AI behaviors, and instead look at how we can recall
this function automatically. We do so by using the schedule function, like so:
schedule(200, 0, updateBot, %id);

The first argument in this function represents how many milliseconds to wait before
calling the third argument, which in our case is the name of our updateBot function. Any
arguments after the third represent arguments for the function to be called (hence %id,
which is the sole argument for updateBot). So, a translation of this statement in plain
English would read In 200 milliseconds, call updateBot for the bot indicated by %id.
So now we have a function that gives the bot ammo, determines its distance from the
player, and schedules another update in the future. In the next section, well explore AI
behaviors.

Styles
After we determine a distance from the player, we will steer the behavior of the bot
according to its style. We will add three styles of AI to this example a grunt, which
pursues the player, and when in close range, stops to fire; a sniper, which remains
stationary and fires if the player is within a wide range; and a berserker, who always
pursues the player, firing as it goes regardless of distance.
Within the updateBot function, we will execute these behaviors using a switch statement,
which looks like this:
switch (%id.style){
// CASES GO HERE
}

Within the switch statement, the property %id.style will be evaluated, and a case will be
selected. Each case represents a particular style of bot AI. Going in reverse order, the
berserkers case looks like this:
case 2: // BERSERKER AI
%id.fire(true);

56

David J. Sushil

davidjsushil@gmail.com

%id.setMoveDestination($gspPlayer.getTransform());
%id.setAimObject($gspPlayer);

The fire function, which takes a Boolean value for an argument, determines whether the
bot is firing or not. It is not a request for a single shot, but rather a toggle switch that sets
the bot to fire indefinitely, or remain passive. The setMoveDestination function takes the
players position as an argument, and tells the bot to move towards that spot on the map.
Finally, the setAimObject function tells the bot to always aim towards the player.
This is a very simple AI bot, which always follows the player, and always shoots.
Though simply, hes pretty darn lethal, and you might want to consider going easy on the
number of berserkers in your game!
A more realistic opponent is the grunt:
case 0: // GRUNT AI
if (%distance < 15){
%id.fire(true);
%id.setMoveDestination(%id.getTransform());
}else if (%distance > 30){
%id.fire(false);
%id.setMoveDestination($gspPlayer.getTransform());
}
%id.setAimObject($gspPlayer);

As you can see, here we are utilizing the distance variable we created previously. If the
player is more than 30 units away, put your gun away and chase him; if he is less than 15
units away, stop and shoot.
Finally, we have the sniper, who would do well to stay out of range of the player
perhaps in on the top of a building somewhere:
case 1: // SNIPER AI
if (%distance < 100){
%id.fire(true);
}else{
%id.fire(false);
}
%id.setAimObject($gspPlayer);

This case tells the AI, if the player is within 100 units, fire; otherwise, put the gun away
and wait.

The Players ID
Finally, you may have noticed a global variable in there called $gspPlayer. We need to
add this variable ourselves. Although there are other ways of tracking the players ID, I
find this method most useful.
Open the demo/server/scripts/ folder, and edit the file named game.cs. Find the
createPlayer function, and add the following boldfaced line, just below the new Player
command, and before the call to MissionCleanup:
// Create the player object
%player = new Player() {

57

David J. Sushil

davidjsushil@gmail.com

dataBlock = PlayerBody;
client = %this;

};
$gspPlayer = %player;
MissionCleanup.add(%player);

Now, whenever you want to refer to the player, you can use the global $gspPlayer
variable.

Complete Code
Because were dealing with quite a bit of code, heres the total package. I would
recommend placing it in a single .cs file, and adding a reference to it in the
onServerCreated function, within demo/server/scripts/game.cs.
// FUNCTION FOR ADDING A SINGLE BOT AT (X,Y,Z) ON THE MAP
function addBot(%style, %x, %y, %z){
%bot = new AIPlayer(){
datablock = PlayerBody;
position = %x @ " " @ %y @ " " @ %z;
botID = 0;
style = %style;
};
%bot.mountImage(CrossBowImage, 0);
%bot.botID = %bot;
updateBot(%bot.botID);
}
// UPDATES THE BOT AI
function updateBot(%id){
%id.incInventory(CrossbowAmmo, 1);
%botX = getword(%id.getTransform(),0);
%botY = getword(%id.getTransform(),1);
%botZ = getword(%id.getTransform(),2);
%playerX = getword($gspPlayer.getTransform(),0);
%playerY = getword($gspPlayer.getTransform(),1);
%playerZ = getword($gspPlayer.getTransform(),2);
%distance = mSqrt((%playerX - %botX)*(%playerX - %botX) + (%playerY
- %botY)*(%playerY - %botY));
switch (%id.style){
case 0: // GRUNT AI
if (%distance < 15){
%id.fire(true);
%id.setMoveDestination(%id.getTransform());
}else if (%distance > 30){
%id.fire(false);
%id.setMoveDestination($gspPlayer.getTransform());
}
%id.setAimObject($gspPlayer);
case 1: // SNIPER AI
if (%distance < 100){
%id.fire(true);
}else{
%id.fire(false);
}
%id.setAimObject($gspPlayer);
case 2: // BERSERKER AI
%id.fire(true);
%id.setMoveDestination($gspPlayer.getTransform());

58

David J. Sushil

davidjsushil@gmail.com

%id.setAimObject($gspPlayer);
}
schedule(200, 0, updateBot, %id);

59

David J. Sushil

davidjsushil@gmail.com

Appendix A: Modeling Torque Interiors with 3D Studio


Max
1. Download the following programs from Doc Sharing to your desktop:
a. Map2DIF Plus
b. QuArK 6.3
c. Game Level Builder 2.22
2. Install QuArK this is fairly easy
3. Install GLB 2.2 this is easily unfair
a. Move the GLB2 folder from the max4-8 folder to the Scripts folder in 3D
Studio Maxs directory.
b. Move Spline_24a.bmp and Splines_24i.bmp to the GLB2 folder in Maxs
directory.
c. Move macroscripts folder from the max4-8/UI folder to the UI folder in
Maxs directory.
d. Open 3D Studio Max, and select Customize User Interface from the
Customize menu.
e. Select the Menus tab.
f. In the Category dropdown list, select Maple3D.
g. Click the New button to create a new menu. Label it Maple3D.
h. Drag the Maple3D menu from the Menus listbox on the left into the menu
hierarchy on the right.
i. Drag all four actions from the Action listbox into the Maple3D menu hierarchy.
j. Close the Customize User Interface dialog box and take a victory lap.
4. Select GLB 2.22 from the Maple3D menu.
5. From the main toolbar, select the Snaps Toggle button (indicated by a magnet and
a number).
6. From the GLB interface, click on the line tool in the Draw and Input field.
7. In Maxs top view, draw the exterior walls using the line tool. Close the spline
object when prompted.
8. Create rooms by adding additional lines to the scene. (Right click to finish each
wall).
9. When you are finished, click the Select All Splines button in the GLB interface.
10. Click the *Add to Plan* button.
11. To give the walls height and depth, click the Select All button in the Edit Walls
field.
12. To the right of the Height and Width fields, click the large S button. You should
see walls in your Perspective view.
13. This might be a good time to turn off your Snaps Toggle tool. Do so by unselecting it from Maxs main toolbar.
14. Create floors by clicking the Create Floors button in the Floors field of the GLB
interface.
15. To lay a floor, click all unfloored spaces within your interior model. When you
are finished, right click to exit the Create Floors tool.
60

David J. Sushil

davidjsushil@gmail.com

16. Ceilings are created by cloning your floors and aligning them with the tops of
your walls. Select all floors at once using Maxs Select by Name tool in the main
toolbar.
17. Create doors by clicking on the Create Door-Window button in the GLB interface.
Click on a wall to place a door. When you are finished with the tool, right click to
turn it off.
18. Carefully adjust the position of your doors to your satisfaction.
19. It is very important to note that all extraneous doors must be deleted by first selecting them, and then clicking the Delete key in the GLB interface. Deleting
them using any other method will result in errors during export.
20. Apply material textures in the form of bitmaps to all surfaces in the model.
NOTE: Each material must be named identically to the bitmap it implements (excluding the file extension). You also need to include create a default texture
called notex, which will be applied to all surfaces without a texture. This is important, because when we create door spaces in QuArK, each doorframe will need
the notex texture applied to it.
21. If your interior does not have any doors or windows, you must create omni lights
in 3D Studio Max, or else the interior will be pitch black in Torque.
22. Export the scene to .MAP format by clicking the Export to Map! button in the
GLB interface. (Use all default settings when prompted)
23. Now, we will use QuArK 6.3 to subtract doors and windows from your interiors
walls. Open QuArk. Choose Open from the File menu, and locate your .MAP
file.
24. Your interior file may be very small in the viewports, so click on the Zoom button
in the toolbar.
25. Using your mouse, click on one of the door objects you created in Max. You may
have to click on this door several times before it is selected. This is because you
are cycling through elements from the top of your interior to the bottom, and the
door may be third in line.
26. With the door selected, choose Brush Subtraction from the Command menu. This
will subtract the door space from the wall in which it is embedded.
27. Using Brush Subtraction will deselect your door. Click to reselect your door.
28. Hit the Del key on your keyboard to remove the door object, leaving just the wall
and a new door space.
29. Repeat steps 25 through 28 for each door in your .MAP file.
30. When you are finished, save your .MAP file by choosing Save from the File
menu.
31. Now, we need to convert our interior to .DIF format using Map2DIF Plus. Make
a copy of Map2DIF Plus and place it in the same folder as your .MAP file. This
folder should also contain all textures, including your notex image file.
32. Map2DIF Plus is a command line processor, so we have to manually point it to
our .MAP file. Do this by creating a shortcut to the Map2DIF_plus.exe file.
33. Right click the shortcut and hit Properties.
34. In the Target field, add the name of your file (including the .MAP extension) to
the end of the line (so it should read something like:
C:\myhouse\map2dif_plus.exe myhouse.map
35. Close the Shortcut Properties dialog, and run the shortcut by double-clicking it.
61

David J. Sushil

davidjsushil@gmail.com

36. After a brief pause, you should see two new files, console.log and a .DIF file.
37. Copy the .DIF file and all textures into the Torque file hierarchy (preferably into
the data/interiors folder).
38. Open your .MIS mission file, and add the following code:
new SimGroup(Buildings) {
new InteriorInstance() {
position = "230.8 -200 191.005";
rotation = "1 0 0 0";
scale = "1 1 1";
interiorFile =
"~/data/interiors/exampleroom/exampleroom.dif";
useGLLighting = "0";
showTerrainInside = "0";
};
};

39. Of course, replace the interiorFile pathway to reflect the location of your .DIF interior. Also, the position, rotation, and scale parameters may need to be altered.
40. All subsequent interiors should be created as separate new InteriorInstances within the SimGroup Buildings. That is, the line:
new SimGroup(Buildings)

should only be written one time in your mission file.


41. Save the .MIS file, load Torque, and open the mission. Your interior object
should be located at the specified position.

Troubleshooting
1. If your interior does not appear in Torque, first check that the position and scale
parameters are correct in your .MIS file. A good strategy for testing interiors is to
place them at your players spawn point. Look for the PlayerDropPoints SimGroup in your mission file, and copy the position parameters. Also, try increasing
the scale a larger building is easier to bump into.
2. If your interior structure has giant black blocks where there should be doors, you
most likely forgot to delete the door structures in QuArK. Repeat steps 23
through 30.
3. If your door frames dont have a texture, you most likely forgot to create a notex
texture. This texture should be a .jpg or .png file. You must create it as a material
in 3D Studio Max, and give it the name notex in the Material Editor. The notex
texture should also be located in the same folder as your .MAP file when you convert it to .DIF, and in the same folder as your .DIF when you load it into Torque.
4. If your building is too big or too small, adjust the scale parameter for your InteriorInstance in the .MIS file. A scale of 1 1 1 accurately reflects the size you
specified in 3D Studio Max.

62

Вам также может понравиться