|
6.Mar.07 Lecture 6
Networking, Modeling and Animations, Interiors
RAR files
Please follow instructions and upload in zip format.
Motivate
63 Days left, probably less since you will have a
screen shot and marketing materials due the week before so the judges
can prepare...
Torque Networking
In Torque, every game is a server, but we are going
to take a much closer look and the book does a good job of separating
out a server from a single player game.
The most common example is a chat system.
If your code is running on the client, you can call:
CommandToServer('MyCommand',%somedata);
On the server, the following function would get called.
function ServerCmdMyCommand(%client,%data)
{
// do something
}
If your code is running on the server, you can call:
CommandToClient(%client,'Something',%data);
On the client, the following code would get called::
clientCmdSomething(%sender,%data)
{
// do something
}
This is called direct messaging and you can use it
to send messages back and forth.
At some point on the server you will want to send
a message to a specific client, or to all clients. You can iterate
through the clients using the following.
%count = ClientGroup.getCount();
for (%i=0;%i < %count; %i++)
{
%client = ClientGroup.getObject(%i);
CommandToClient(%client,'Broadcast',%sender,%msg);
}
client code looks like this:
clientCmdBroadcast(%sender,%data);
A good time to start looking at C/C++ code.
No time is going to be perfect to start digging into
the engine code, but I think this is a good opportunity to get our
feet wet. The question we are searching for, what is that ClientGroup
object?
Looking through the common directory, can you find
where ClientGroup is declared. If it's a variable, it must be declared
somewhere right???
A search for ClientGroup returns audio.cs, clientConnection.cs,
message.cs, missionLoad.cs and server.cs. Looking at all these files,
they are all just references.
So, let's search through the c code under the engine
directory. This returns: simBase.cc, simBase.h, simManager.cc, aiClient.cc,
aiConnection.cc, debugView.cc, gameConnection.cc, gameProcess.cc, netObject.cc,
pathManager.cc, lightning.cc and weatherLightning.cpp.
Just based on names we can narrow our search to:
simBase.cc, simBase.h, simManager.cc, gameConnection.cc, gameProcess.cc,
and netObject.cc.
Yes, I spent a lot of time on this rabbit hole and
you are going to save some time if you pay attention.
Go search through each of those files for ClientGroup
and you will not find a declaration for the variable. Search all you
want, it doesn't exist.
So, how does a variable get used if it is never declared?
Yes, C and C++ require variables be declared before they are used.
Notice that most of the calls look like this:
Sim::getClientGroup()->addObject(this);
So, if you may want to extend your search for getClientGroup().
A quick note on namespaces since Sim is a name space.
This is a simple C++ way of creating a code group. You could name two
routines getObject in different namespaces and they will not conflict.
Before namespaces, function and variable names had to be unique across
the entire code base. It's nothing fancy, just declare a namespace
MyNameSpace with an open bracket {, write a bunch of code and variable
declarations and close the bracket. That code can be accessed by using
the name space, just like the Sim namespace above. I did find a
good namespace tutorial.
Since we struck out on the declaration of ClientGroup,
maybe it is in the getClientGroup. Did you find it? Nope, me neither.
Search all you want, it doesn't exist. Odd, now we have a variable
and a function that have not been declared.
What is going on!!? The C language can be quite complex
and while that is one of it's strengths, it is also one of it's weaknesses
since it can be hard to learn and manage.
In this case, do you remember our discussion on the
preprocessor and macros? Take a look at simBase.h and the line.
DeclareNamedGroup(ClientGroup);
This should be telling in that you are seeming to
call a function with a variable that has not been declared. So, let's
take a look at that function. In our search we find.
#define DeclareNamedGroup(set) extern SimGroup
*g##set;inline SimGroup *get##set() { return g##set; }
Ah ha! A macro is the culprit! Remember, this does
a substitution before the compiler runs and this would be the result
of that substitution.
extern SimGroup *gClientGroup; inline SimGroup
*getClientGroup() { return gClientGroup;}
There it is, the declaration of getClientGroup, which
was placed into our code with a macro. There is more behind the scenes
which connects up the script side of ClientGroup with getClientGroup,
but this was just to get our feet wet searching the code to come to
a better understanding of the Torque engine. We'll try and come back
to that later.
Back to our regular lecture
The other networking communication is with Player
Event Control Triggers. We saw these last week when digging through
the orc code. There are six Player Event Control Triggers.
Simply setting the variable $mvTriggerCount# = 200;
(where # is the number 0 - 5) will cause the server to receive the
MyAvatarClass::onTriggerEvent 200 times. Triggers 0-3 are pre programmed
(See page 241) for avatar actions, but you are free to change them
or use the optional 4 and 5 triggers. note: I've tried setting the
counter to a large number like the book suggest and could not prove
that the onTrigger method was called more than once. This needs more
investigation, your mileage may vary.
The MyAvatarClass is the name of the class you have
defined in your player avatar's datablock. Do you know what that is
for EMAGA5?
In server.cs
// Create the player object
%player = new Player()
{
dataBlock = MaleAvatar; // defined in players/player.cs
client = %this; // the avatar will have a pointer to its
}; // owner's connection
In player.cs (which has the datablock for MaleAvatar)
datablock PlayerData(MaleAvatar)
{
className = OrcClass;
shapeFile = "~/data/models/avatars/orc/player.dts";
emap = true;
....
}
The answer is: MaleAvatar. It might be a good idea
to add an MaleAvatar::onTrigger method which prints something to the
log. Then to map a key to set $mvTriggerCount5 to some value and see
what happens. This is in player.cs:
function MaleAvatar::onTrigger(%this,%obj,%triggerNum,%val)
{
echo ("MaleAvatar onTrigger obj=" @ %obj @ " trignum=" @ %triggerNum @ " val=" @ %val @ "*********************");
switch$(%triggerNum)
{
case 5:
echo("onTrigger5, val=" @ %val);
return;
}
}
Then in presetkeys.cs
function DoJump(%val)
//----------------------------------------------------------------------------
// momentary upward movement, with character animation
//----------------------------------------------------------------------------
{
$mvTriggerCount2++;
echo ("*********Do Jump");
$mvTriggerCount5++;
}
Since event 0 is fire, why would you want to do this
instead of just creating a bunch of new objects on the client or sending
an Command message? For one, you don't want to send a bunch of commands
for each bullet. Sure, you could send one command that contained a
number, but there are other things that could be at work here. This
mechanism may take a different route than command messages and have
a higher priority. I think we would all agree that weapons fire notification
events would have a much higher network priority than chat. So this
simpler mechanism was created. It also allows you to send a number
that is the number of bullets that fire or some number of iterations
you want the server to perform.
GameConnection
The GameConnection class is how you get your client
to connect to your server. It looks like this.
%conn = new GameConnection(ServerConnection);
%conn.SetConnectArgs(%username);
%conn.Connect();
The Connect() method launches a convoluted process
that you really don't have to know a lot about. The Connect() method
will make calls back the the GameConnection object when events or errors
occur during connection. I have not found a good list of these calls
online, your best bet is pages 243-248 in the textbook. The one we
have seen implemented in all of our game so far is onConnect(). This
is called when the connection is made successfully. This is fine for
our test games, but for a commercial quality game you would need to
come back and implement the other call backs.
Finding Servers
Most lan games just search all the machines on a
specific subnet to find an active game server. They do this by going
through a list of ip address and connecting to a specific port. If
the connection succeeds and the machine exchanges some preset information,
then the server is available. We had a sample of this last year.
There are two types of internet game systesm. A central
directory server which lists all the available servers on the internet
and you would then make connections directly to that server. The second
is a server that manages the directory and all the game to game communications.
The second is easier to implement for users as there will probably
be less firewall issues, but it also requires an expensive infrastructure
of networking equipment and servers. The simple directory server is
much easire to implement for the developer, but requires more work
on the part of the game player in that they will have to do some firewall
or router configuration, ie, setting up port forwarding.
Torque has the capability of all three types of games,
but we will be mostly focused on lan games because they are all that
will be required for the final game and taking that to a directory
or server based system will just be an added layer and not a different
architecture.
Torque has builtin functions to find games on a lan.
This is the function.
QueryLANServers(port,flags,gtype,mtype,minplayers,maxplayers,maxbots,region,ping,cpu,filters,buddycount,buddylist);
More information QueryLANServers
is on TDN. Two variables this uses outside of the actual function
call are.
$Client::GameTypeQuery = "3D2E";
$Client::MissionTypeQuery = "Any";
The GameTypeQuery is a Hexadecimal number and I will
do a quick overview of hexadecimal since I don't think the entire class
has had assembly language or computer architecture yet. A quick explanation
here is that you can use four digits, and the digits are from 0-F.
So, valid numbers are "0000" - "FFFF". Or you could
use any combination of those letters and numbers. "K00K" would
be valid.
TCP/IP and UDP ports. Network traffic works on well
defined ports. Most traffic uses TCP/IP and web traffic is port 80,
while mail traffic is on port 25. For server, you tell it what port
you want to listen on and you will get notifications when connections
are made and from there notifications when information is received
from specific connected clients. For clients, you make a connection
to a specific ip address on a specific port and can send and receive
information to/from that connection. TCP/IP guarantees (in order) delivery
of information written to the network, while UDP information may not
ever arrive. UDP is faster, but you will have packet loss.Ports below
1024 are protected and not always available. For your games you should
always choose a port > 1024. For specific information about what
ports are used for what, logon to a unix/linux machine and look at
the /etc/services file.
The book shows a lot of gui interaction and how to
populate a list of LAN game servers. You should use this for your game,
it is a great example. The dedicated server is interesting and useful,
but you should leave it for reference and save the complexity for a
future exercise when you turn your game into a commercial game.
Power Ups and how they work
I think a good discussion that is not made in the
book is powerups and how they are implemented.
Search for FirstAid in the EMAGA/control directory.
You should find it in: book_ch5.mis, and item.cs. Let's look at item.cs.
//-----------------------------------------------------------------------------
// Health Patchs cannot be picked up and are not meant to be added to
// inventory. Health is applied automatically when an objects collides
// with a patch.
//-----------------------------------------------------------------------------
datablock ItemData(FirstAidKit)
{
// Mission editor category, this datablock will show up in the
// specified category under the "shapes" root category.
category = "Health";
// Basic Item properties
shapeFile = "~/data/models/items/healthPatch.dts";
mass = 1;
friction = 1;
elasticity = 0.3;
respawnTime = 600000;
// Dynamic properties defined by the scripts
repairAmount = 200;
maxInventory = 0; // No pickup or throw
};
function FirstAidKit::onCollision(%this,%obj,%col)
{
// Apply health to colliding object if it needs it.
// Works for all shapebase objects.
if (%col.getDamageLevel() != 0 && %col.getState() !$= "Dead" )
{
echo("!!@@@@@@@@@@@@@ col"@%col);
%col.applyRepair(%this.repairAmount);
%obj.respawn();
if (%col.client)
{
messageClient
(%col.client,'MSG_Treatment','\c2Medical treatment applied');
}
}
This is a very simple item. When it is picked up,
it calls applyRepair on the object that touches it. In this case, Player.
The amount is 200 as listed in the datablock. It then respawns itself
in 60000 milliseconds or 60 seconds.
This is really a good example to try and move to
the GameOne from the beginning tutorial. When you move those two program
blocks to the logoitem.cs file and move the ~data/models/items direcotry
(and match the new name to the datablock, and try and place a shape/Health/FirstAidKit
to the mission what happens. Probably nothing. When you check the log,
you see something like. Cannot find ItemData::create. What does this
mean. It means you should go back to the EMAGA and search for ItemData::create.
That routine is used by the editor to place items on the mission. Without
it, the shape connection to the editor is incomplete. Now you know
exactly how to get non-static items into the mission editors. Static
items are easy, just place the dts file in the models directory, it's
the items that have code behind them that are a little more tricky,
but three or four lines of code isn't a lot to ask.
If there are no more errors, does anything happen
when you collide with the FirstAidKit? Since I know it won't work,
why not?
if (%col.getDamageLevel()
!= 0 && %col.getState() !$= "Dead" )
{
This line limits the effects of the FirstAidKit if
the damage leve is equal to zero. Since there is no damage in the GameOne
game, the health pack will never execute, but the collision is working.
You can see the collision work if you put an:
echo("FirstAidKit collision working");
just before the if statement.
Did you notice that the First Aid Kit spins in the
mission? You didn't add anything extra in the code to do this did you?
Of course not, but ItemData::create looks like this.
function ItemData::create(%data)
{
// The mission editor invokes this method when it wants to create
// an object of the given datablock type. For the mission editor
// we always create "static" re-spawnable rotating objects.
%obj = new Item() {
dataBlock = %data;
static = true;
rotate = true;
};
return %obj;
}
Do you notice the rotate=true; line in the creation
of the ItemData datablock? A simple flag and Torque will automatically
make your powerups spin! Now that's simplicity.
FirstAidKits are one thing, what about a non-standard
powerup that gave your weapon a special bullet (See Think Tanks) or
some sort of shielding from damage (shields in unreal)?
Look at this untested code for a second.
function ExplosiveBulletPowerUp::onCollision(%this,%obj,%col)
{
if ((%col.getDamageLevel() != 0 && %col.getState() !$= "Dead" ) && (%col.getClassName() $= "Player"))
{
echo("Big Bullet Power Up");
%col.turnOnBigBulletPowerup();
%obj.respawn();
if (%col.client)
{
messageClient
(%col.client,'MSG_Treatment','\c2Medical treatment applied');
}
}
function PlayerBody::turnOnBigBulletPowerup(%this)
{
%this.bigBulletPowerUp = true;
%this.schedule( 25000, 0, turnOffBigBulletPowerup, %this);
}
function PlayerBody::turnOffBigBulletPowerup(%this)
{
%this.bigBulletPowerUp = false;
}
Again, this is not tested, but you should then be
able to check the %player.bigBulletPowerUp flag when the weapon is
fired and change the behaviour accordingly. The powerup would turn
off after 25000 milliseconds (25 seconds). It might or might not make
more sense to apply this to the weapon, but you can make it work either
way.
Common folder
I don't have much to add to this chapter. You should
read this and be familiar with it.
More Advanced 3D Modeling
This week we will be creating our own models for
inclusion in our games. Chapter 13 and 14 in the All In One book has
a great reference to Milkshape, textures and creating player models.
I spent about 20 hours going through these two chapters so get started
early. This week we will be building a character model and incorporating
it in our game.
We will be using Milkshape
3D. For $35 you cannot beat this tool.
For the best results when exporting from Milkshape,
I recommend the DTSPlus
exporter written by Chris Robertson. Keep that link it was a really
tough one to find even though everyone seems to recommend it.
The second tool we will be using is UV
Mapper. This is a free tool (for the non-pro version) which will
help us map images to our 3D objects.
The third tool that I like a lot is Blender.
This is a free tool that was once a commercial product. It is much
more robust than Milkshape, but has a bit of a quirky interface. I
made some notes for a Blender lecture that
I may or may not give. For the sake of speed it may just be best to
use Milkshape and UVMapper since they are so well documented in our
books. This IS a class about making games, not modeling and textures
and we need to spend our time wisely.
3D studio max is also installed on the lab machines
and is the tool the Garage Games folks used when building Torque. It
is $3500 a seat and we don't have time to cover it in this class. You
are welcome to use it for this class, but I'm probably not going to
be able to help you if you get stuck.
Milkshape Overview
The book does a much better job of this than I could
here. Read the book.
Viewports
Creating Objects
Selections
Transformations
Exporting to Wavefront .obj for texture mapping.
UV Mapper
Loading an object.
Separating out various objects.
Unwrapping various object.
Saving final object and bitmaps.
What is going on here? The obj now contains uv normals
which are directly related to the bitmap.
Paintshop Pro
Painting the actual texture map
Milkshape
Re-importing the model
Building an avatar
Chapter 14 is a great resource and example for creating
a model. You should go through this in detail, but you should pay attention
to Page 616 before going through this entire tutorial. After it gets
you to spend a ton of time creating a skeleton, it says that it is
next to impossible to create a skeleton yourself that will work with
the preexisting Torque biped animations. For this, Mr. Finney has included
the Torque biped skeleton in the RESOURCES for Chapter 14. I disagree
and think you should start with this and build your model around it
since it will be hard to return later and retrofit your model to the
skeleton. The file is called skeleton.ms3d and you should keep a copy
of this in your game.
If you open this model in Milkshape and only see
large circles, select File/Preferences/Misc and change Joint size to
0.02.
As far as I have read, don't move the joints around
as this will cause a disconnect between Torque and your model. When
you begin animating, this should be your reference position and you
should build your model around this skeleton. The skeleton is tiny
on Milkshape's scale and will cause problems with using the scale function
with the mouse. You may have to study the skeleton as a reference and
build you avatar at a larger size and shrink it down later.
Animation Sequences.
I'm building a hammer bot in class to show how animations
get tied into the game engine. I'm not sure if we'll have time, but
I'm going to try and show this full circle so we have an indepth understanding.
This will be abbreviated, sorry it won't be as much use if you didn't
come to class.

This is an overview of the actual hammer
bot and the joints. First I created the model itself, created a metal
texture with paintshop pro and assigned that texture to all the elements
in the model
The joints from bottom to top are named:
origin, mdpt, neck, leftshoulder, leftelbow, leftwrist, hammer.
- Build the model
- Add the skeleton
- Rig the skeleton to the model.
- Create a hammer animaition. My hammer animation runs from frame
1 to 72 and is too slow at the hammer, but this is just a demo.
I'm using the DTS Plus exporter. The book has a good
follow along around page 208.
- Select File/Export/Torque DTS Plus
- Create the animation sequence.
- Export the dts file.
- next create the dsq animation sequence files by:
- Merging all the groups into one ending in a 0.
- Select File/Export/Torque DTS Plus
- Make sure both Generate cs file and Split DSQ Export boxes are
check.
- Export again and give a file name without an extension.
- The exporter will create a DSQ file for each animation sequence
using and _name in the file name.
You can now load the .cs file in an editor.
datablock TSShapeConstructor(HammerbotDts)
{
baseShape = "./hammerbot.dts";
sequence0 = "./hammerbot_hammer.dsq hammer";
}
See that it has associated the hammer.dsq animation
with the name hammer. This is the name you gave it in the DTS Plus
exporter.
You can use
Now to get it to animate in your game is a completely
different matter. This is a good overview of shape
based animation in Torque. The yellow book also discusses this
a little pn page 169.
You have to create a datablock for your shape. The
sample give is the healtkit.
datablock ItemData(HealthKit)
{
// Mission editor category, this datablock will show up in the
// specified category under the "shapes" root category.
category = "Health";
// Basic Item properties
shapeFile = "~/data/shapes/items/healthKit.dts";
mass = 1;
friction = 1;
elasticity = 0.3;
emap = true;
// Dynamic properties defined by the
scripts
pickupName = "a health kit";
repairAmount = 50;
};
Adding a similar item to my hammerbot.cs file. Mine
is located with the model dts file so may reference the dts files by
shorter path names. You can use either method and this seemed faster
to me, but more dangerous for long term. For code you want to have
around for a long time, keep all the code in the same place and separate
it from the visual elements.
datablock StaticShapeData(Hammerbot)
{
// Mission editor category, this datablock will show up in the
// specified category under the "shapes" root category.
category = "Bot";
// Basic Item properties
shapeFile = "./hammerbot.dts";
mass = 10;
friction = 1;
elasticity = 0.3;
};
I used StaticShapeData because ItemData rotated and
was more geared towards powerups and items than funky animated figures.
Once you've added it, find it's object number and use the console to
type:
1809.playThread(0,"hammer");
This will play the hammer animation and stop. When
it's done, you'll have to stop it by hand.
1809.stopThread(0).
You could schedule this stop with schedule.
The animation name "hammer" is simply appended
to the dts file name when Torque searchs for the dsq (animation) file.
Given the above information, the dsq file is located in hammerbot_hammer.dsq
since the model is in hammerbot.dts.
Read pages 143-190 in the yellow book for reference.
Note to self: we need to start working on an understanding of the difference
between ShapeData, StaticShapeData, ItemData and PlayerData and how they
all interact.
The complete hammerbot
I created in class is available
as a sample.
A good overview resource
The TDN site has a good FAQ
on modeling.
Taking my figure model and importing it into TGE
Using code to play model animations.
Assignment
Create your own model. Import it into TGE and get an
animation working on it. I'll warn you up front, this is a huge task
and most of it requires absolutely no programming.
As an exercise
Use milkshape to open the various ms3d files in the
starter.fps/data/shapes/ directories.
QuArk Notes
This is the best place for downloading a version
of quark that will work with Torque.
http://www.garagegames.com/docs/tge/general/ch09s02.php
it also requires Python 1.5. Python
1.5.2 works and can be downloaded on the Python
website.
Holodeck
QuArk tutorials were written with Torque in mind. A great resource.
To use the setInteriorRenderMode(#) function you will have to rebuild
the Torque_Demo.exe file using Visual Studio. We can talk about how
to do this since this is a great debugging mechanism.
Here is a website with Quark
Documentation and Tutorials.
Installation location makes a difference
To get the exporter to work properly (without editing
the python code), you have to install QuArk in "C:\QuArk 6.3".
If you install it somewhere else, you can still create the "c:\QuArk
6.3\Torque\" directory and copy the contents of your QuArk install
torque director to that location. If you just create the directories,
it will still look for the dif conversion exe file in "c:\Quark
6.3" directory. Make your life easier, just install it there and
work on your game, not on the tools.
Why .dif and .map files?
It would be a whole lot easier to create levels in
your favorite 3D tool (Blender, Milkshare, 3dsMax), wouldn't it? You
could, but the math involved in collision detection with the actual
level would be much more intensive than what is going on with .dif/.map
files. The .dif/.map files use something called BSP
trees. These BSP trees make the mathematics of display and collision
much much easier for the computer and they are used in all current
game engines. While the tools aren't the best, you'll just have to
deal with it or write your own. This is just another one of those cases
where performance has a cost and that cost is added complexity.
Creating .dif files with Max.
For those that use 3dsMax there is a way to use Max
to create .map and .dif levels, but it is beyond the scope of this
class. GLBuilder
for 3dsMax. You'll have to figure it out.
Creating .dif files with Valve Hammer Editor (World
Craft)
Valve
Hammer Editor is another editor besides QuArk that you can use
to create map/dif files. There is also a World
Craft discussion on the Torque site. Again, this will not be
used in class so you'll have to figure it out on your own or use
QuArk. The book uses a beta editor called Constructor from GarageGames,
but since it is beta we will not be using it.
Hard to use tools
If you find that these tools are hard to use and
find a lot of people complaining about them, think of this as an opportunity.
If all the tools are this bad, you would think that there would be
an opportunity to sell a better tool to these same people. So, feel
free to write your own. As with all software projects, tools always
have their odd behavior and take getting used to, but most of the time,
once you get through the hard parts they are almost always 'usable'.
Creating Interriors
At the top of theQuArk explorer is a new Torque Map
button. Click it and you'll see the four view point editor. You only
create maps with simple shapes. They call these brushes, but actually
they are just polygons. You create a bunch of polygons and hook they
together. For those that have used Unreal editor, it maps all the interriors
of the polygons, while Quark/Torque map the outsides of the polygons.
One is better for interriors (Unreal), the other is better for structures
(Torque). You can still create great interriors, they just take a little
extra work.
To make sure you have the tool working, simply save
the simple map (call it roomone.map) that is created when you create
a new Torque map. Since QuArk saves in Map format, you'll have to save
it into Torque .DIF format. Select Torque/Export 220 Map/Build High
Def Detail. This is the highest resolution and the standard dif file
you should use for your games in this class. There is a way to use
LOD and we will discuss it later. You will find a file in c:\quark6.3\torque\tmpQuark\maps\roomone.dir.
The texture files (we'll talk about these in a sec) that were save
in c:\quark6.3\torque\tmpQuark\textures\concrete.jpg. You can see this
is the file by date. You do not need NULL.jpg.
Copy both of those files to the data/interior directory
of your game. Run the game, press F11 to get to the world editor. F4
to get to create mode and place the interior called roomone. This will
place the interior and you can move it around and relight the scene.
Try entering and exiting the room. This is just an exercise to make
sure you understand the basics of the work flow. There are 1000 ways
you can mess up a map file and make it unusable. Polygons typically
need to be lined up perfectly (no gaps) or there will be side effects
in the use of those interiors. It's a serious pain, but QuArk is no
better or worse than any of the other tools I have used to do this.
The use of BSP is a tradeoff between processing speed and complexity.
More complexity on the build for faster executuion. You pay for that
execution speed with a harder build environment.
That said, always save your work and save copies
of your work in a different location than your work area. You should
always be able to go backwards when you really screw up a complicated
map. Yes, you will ruin a lot of perfectly good maps, just be prepared,
it's part of the process to waste some time.
Placing polygons
You can place a polygon on the map by simply clicking
on the new polygon buttons.

The tan cube places a cube (what you will us 99.9%
of the time). The blue cubes have menus of specialized objects you
can place. The one on the left is for general quark polys, the one
on the right is for Torque specific objects.
Once you place a polygone, you move it around (and
resize) on the map using the three viewports (top, left, front).
Moving around in the viewports.
Moving around in the viewports takes getting used
to.
In the 3D view port
Hold down the middle mouse button to rotate left
and right and zoom in and out.
Hold down the right mouse button to change your
viewing angle
In the side/top/front view ports
Hold down the right mouse button to pan.
Hold down the middle mouse button to zoom.
Polygone tree and properties window

In the lower left is a tree view of the various polygons
in your map. This is a tabbed view. The leftmost tab is for the tree
view where you can select the polygons from the list. The second tab
is for properties of the selected object and the third and fourth tabs
are for texturing.
Point of view
When you move around in the 3D view, you will see
your eyepoint change in the side,top and front views. The eyepoint
looks like this.

Grouping polygons
To create a group of polygons, simply select them
and click the new group button. .
It's not in the most obvious place so you'll hav eto hunt for it just
above the treeview.
Creating Hollow Polygons
It is no doubt you will want to create an interior.
You do this by creating a polygon. Make sure it is sized exactly as
you want it to be in the final. After turning it into an interrior,
a change of size becomes very complicated and you would probably be
better rebuilding the polygon. Once you have the poly ready to turn
into an interior, select Commands/Make Hollow. This will turn the polygon
into 6 separate polygones that do not have gaps. Moving individual
polygons at this point will make gapes and render your map file useless.
Be careful.
To create passages through your hollow polygons.
Create another polygone and place it over the area
you would like to hollow you. Turn the polygon into a negative poly.
To do this you select the ploygon, select the properties tab and click
the 'neg' radio button.
To change a polygon's texture
Simply select the polygon, change to the blue cube
tab and click the new texture button .
This will bring up lists of all the available textures. This file will
then be output into the tmpTorque/textures directory when you save
the .dif file, you will have to remember to make sure this texture
file makes it into your interiors directory for your game.
A BUG. Not that I have found that the preview 3D
window stops working when I change textures. You will have to change
it back to wireframe by right clicking in the window. At some point
it will work again, but I have not figured out when or why. A bit annoying,
but life in general.
The use of portals
Portals are important elements in building interiors.
You should learn to use them. They allow the engine to optimize the
drawing. When you are inside a portal (and the interior has no gaps!),
the engine will be able to only draw elements that are directly inside
that portal area and speed up processing. If you don't use portals,
it will still have to consider elements that are no where near being
visible when it draws the canvas.
To create a portal, select the add torque object,
Brush-based entities, portal. Any polygone created under that group
will be a portal. The portal should cover an existing hole (cannot
be used with a neg poly) and should overlap by a one or two unit margin.
If your map has holes, this will not work correctly.
The use of lights
You will have to place lights in your level or it
will be especially dark. Click the add torque object menu and choose
light entities/light_omni. Omni directional lights will be your easiest
option. If the interior is still dark after loading it into torque,
look where the light is, in the room. You may be able to see it, it
is just not strong enough. On the light's properties are are falloff1
and falloff2. Fall off 1 is where the light begins to drop off, falloff2
is where it stops shining at all. You will have to use trial and error
to get it right. This is a time buster so be prepared.
There are other types of lights we will talk about
in class.
|