Introduction

Torque 3D's stock demos and templates are setup for first person shooter (FPS) games. However, the engine has multiple camera modes that can change the perspective and how the game is controlled. In this tutorial, we are going to modify the camera and mouse controls to emulate different game types: Hack & Slash and RTS.


This guide will be working with the stock Full Template, created from Toolbox. If you have not done so, create a new project using this template. All of the code provided in this tutorial can be applied to this project with ease. You will also be provided with new assets (models and textures) you can import into the project.


Some of the topics that will be covered are:

  • Advanced scripting
  • Camera manipulation
  • Simple AI
  • Object spawning
  • Mouse and keyboard input
  • Basic RTS and Hack & Slash mechanics


Before you begin, you should be familiar with the following guides. Make sure you have read these before proceeding:


  • TorqueScript Syntax
  • Camera Modes
  • World Editor Interface
  • Adding 3D Shapes
  • Material Editor
  • Decal Editor
  • Datablock Editor


The Full Template used for this tutorial project should contain base art and scripts needed to run the game, but we want to use some custom models. Start by CLICKING HERE to download a zip file containing the sample assets.

 

Copy the art folder in the zip file on top of your project's art file. This will add the models, their datablocks, and their materials to your project if they do not exist. When you are ready, continue reading to configure your mouse controls.


The zip file adds two new models to the project. One is a simple, static building. The other is a custom player model called Boom Bot. While you can simply drag and drop these models in via the World Editor, we need to hook up a script file prepared specifically for Boom Bot.


To get Boom Bot fully working, open game/art/datablocks/datablockExec.cs Scroll down until you see the following code:


exec("./player.cs");

Just below that line, add the following:


exec("./BoomBot.cs");

Mouse Setup

The following code will change the way mouse input affects movement and click interaction.


Mouse Cursor Toggling

Normally, the camera is controlled by an actor in FPS (aim) mode. To focus on just mouse and camera work, we need to change how the default camera is controlled. Open game/scripts/server/gameCore.cs. In function GameCore::preparePlayer(%game, %client), locate the following line:

%game.spawnPlayer(%client, %playerSpawnPoint);


Change this code by adding a third argument to the function call:

%game.spawnPlayer(%client, %playerSpawnPoint, false);


The function being modified is GameCore::spawnPlayer(%game, %this, %spawnPoint, %noControl), located in game/core/scripts/server/gameCore.cs. The last two arguments determine the location of spawning (%spawnPoint) and whether or not the actor object controls the camera (%noControl). We need to address that next.

Immediately below the %game.spawnPlayer() function, add the following code:

   if (%client.getControlObject() == %client.player)  
   {  
      %client.camera.setVelocity("0 0 0");  
      %control = %client.camera;  
   }  
   else  
   {  
      %client.player.setVelocity("0 0 0");  
      %control = %client.player;  
   }  
   %client.setControlObject(%control);  

This sets us up to correctly control the camera from the new fly mode.


If you run the game, you will now be using a free fly camera instead of an FPS view controlled by the actor. Next, we need to be able to control the on/off state of the in game mouse cursor. Open game/scripts/client/default.bind.cs. At the end of the file, add the following:

// Turn mouse cursor on or off
// If %val is true, the button was pressed in
// If %val is false, the button was released
function toggleMouseLook(%val)
{
   // Check to see if button is pressed
   if(%val)  
   {
      // If the cursor is on, turn it off.
      // Else, turn it on
      if(Canvas.isCursorOn())
         hideCursor();
      else
         showCursor();
   }
}

// Bind the function toggleMouseLook to the keyboard 'm' key
moveMap.bind(keyboard, "m", "toggleMouseLook");


Next, open your file browser and delete scripts/client/config.cs, if it exists. This file contains custom keybinds created for your game. It will override the variables and functions you add to default.bind.cs. However, if you delete this file and run your game, a new one will be regenerated with your updated.


If you start the game now, it will still default to a free flying (mouse look)camera. By hitting the 'm' key you will be able to toggle "mouse look" mode. If mouse look is on, you can control your view direction by moving the mouse. If it is off, you can move your cursor around on the screen. You can switch back to an actor controlled camera by pressing Alt + C.


We will go ahead and force the cursor to be on as soon as the level loads. Open game/art/gui/playGui.gui. You can edit .gui files just like any other script file. Look for the noCursor field. Make the following change to this field:

noCursor = "0";


Now that you've freed up the mouse from aiming duties, it's time to put it to other uses.


Mouse Click Reaction

Open game/scripts/gui/playGui.cs. Add the following function at the end of the file:

// onRightMouseDown is called when the right mouse button is clicked in the scene
// %pos is the screen (pixel) coordinates of the mouse click
// %start is the world coordinates of the camera
// %ray is a vector through the viewing 
// frustum corresponding to the clicked pixel
function PlayGui::onRightMouseDown(%this, %pos, %start, %ray)
{
   // find end of search vector
   %ray = VectorScale(%ray, 2000);
   %end = VectorAdd(%start, %ray);
   
   // only care about terrain objects
   %searchMasks = $TypeMasks::TerrainObjectType;

   // search!
   %scanTarg = ContainerRayCast( %start, %end, %searchMasks );
   
   // If the terrain object was found in the scan
   if( %scanTarg )
   {
      // spawn a new object at the intersection point
      %obj = new TSStatic()
      {
         position = getWords(%scanTarg, 1, 3);
         shapeName = "art/shapes/building/orcburrow.dts";
         collisionType = "Visible Mesh";
         scale = "0.5 0.5 0.5";
      };

      // Add the new object to the MissionCleanup group
      MissionCleanup.add(%obj);
   }
}


If you run the game now, it should place a building on the terrain wherever you right-click. We will implement other GameTSCtrl::onMouseDown and GameTSCtrl::onMouseUp methods later in this tutorial.


Mouse-Driven Input

Without FPS controls and player aiming, we need a new way to control the Player object. The best examples of a mouse driven game genre are RTS and Hack & Slash. Typically, these game types allow you to move and attack using the mouse buttons. Let's start with movement.


Player Spawning

At this point, we can spawn an AI player to stand in for the stock player. This AI will be controlled by our mouse inputs. Torque 3D uses a simple spawn system, which can be easily modified to spawn any kind of object (of any class).


Open Toolbox, select the empty terrain level, then click the World Editor button.


Once you are in the editor, locate the spawn sphere in the scene. It is represented by a green octahedron, which will turn into green sphere when you click on it:


(click to enlarge)




You can also locate a spawn sphere by browsing the Scene Tree, under the PlayerDropPoints SimGroup:


Image:RTS_SpawnSphere2.jpg


If you have multiple spawn spheres, delete all except for one. We can control what type of actor is spawned by changing the properties of the remaining spawn sphere. Select the sphere, then change the spawnClass to AIPlayer and spawnDatablock to BoomBotData. Also, change the name of the spawn sphere to PlayerSpawn.


Image:RTS_SpawnProperties.jpg


Movement

Now that we have an AI player spawning in the game, we can send it commands. Open game/scripts/gui/playGui.cs. In the function onRightMouseDown, select the following lines:

// If the terrain object was found in the scan
if( %scanTarg )
{
   // spawn a new object at the intersection point
   %obj = new TSStatic()
   {
      position = getWords(%scanTarg, 1, 3);
      shapeName = "art/shapes/building/orcburrow.dts";
      scale = "0.5 0.5 0.5";
   };

   // Add the new object to the MissionCleanup group
   MissionCleanup.add(%obj);
}


Replace that code with this:

if( %scanTarg )
{
   ClientGroup.getObject(0).player.setMoveDestination( getWords(%scanTarg, 1, 3) );
}


The new command you are using is quite complex and is calling multiple functions at once. We can break this down:


ClientGroup - Special SimGroup that keeps track of all client game connections

.getObject(0) - Accesses (by 0 index) the first client connection stored in the SimGroup. Since this is tutorial is not intended to be a full, multiplayer RTS game, you can always use the 0 index to access your connection.

.player - Accesses the player object (AIPlayer, in this case) of the current client connection. Without using a global variable assigned to this this player reference, you always want to go through the game's connection to access the object. This goes for other similar objects, such as the camera.

.setMoveDestination(getWords(...)) - Calls AIPlayer member function which will move the actor to an (X,Y,Z) location in the world

getWords(%scanTarg, 1, 3) - Grabs the coordinates from the object found during the scan, in string format


Save your script and run the game. You should now be able to direct the AI player to wherever you right-click on the terrain. This only works if you have mouse look disabled, and your cursor is present on screen.


Spawning Enemy Targets

Our player looks lonely and bored. We should give him some targets, and the means of disposing them. Open game/scripts/client/default.bind.cs, and add the following to the bottom of the file:

// Spawn an AI guy when key is pressed down
function spawnAI(%val)
{
   // If key was pressed down
   if(%val)
   {
      // Create a new, generic AI Player
      // Position will be at the camera's location
      // Datablock will determine the type of actor
      new AIPlayer() 
      {
         position = LocalClientConnection.camera.getPosition();
         datablock = "DefaultPlayerData";
      };
   }
}

// Bind the function spawnAI to the keyboard 'b' key
moveMap.bind(keyboard, b, spawnAI);


In the above code, a new example of accessing a client connection is shown. Instead of ClientGroup, the code uses LocalClientConnection. In a "single player" environment, you can use these two interchangeably. Due to Torque 3D's architecture, there will always be a server and at least one client connection.


The common practice for choosing which to use is as follows:

  • Accessing From A Client - Use LocalClientConnection. This will always access your connection, player, camera, etc.
  • Accessing From Server - Use ClientGroup.getObject(%index). Multiple connections to choose from. This is good for applying the same functionality to all connections, or isolating specific ones based on ID.


Again, do not forget to delete game/scripts/client/config.cs. You can run the game, then press the 'b' key to spawn stationary AI targets in the same position as your camera. If gravity is enabled, they will fall until they hit the terrain.


Attacking

Currently, we have a player we can control, and targets that can die. Let's give the player some combat skills. In game/scripts/gui/playGui.cs, add the following function to the bottom of the script:

// onMouseDown is called when the left mouse
// button is clicked in the scene
// %pos is the screen (pixel) coordinates of the mouse click
// %start is the world coordinates of the camera
// %ray is a vector through the viewing 
// frustum corresponding to the clicked pixel
function PlayGui::onMouseDown(%this, %pos, %start, %ray)
{   
   %ray = VectorScale(%ray, 1000);
   %end = VectorAdd(%start, %ray);

   // Only care about players this time
   %searchMasks = $TypeMasks::PlayerObjectType;

   // Search!
   %scanTarg = ContainerRayCast( %start, %end, %searchMasks );

   // Get our player/actor
   %ai = LocalClientConnection.player;
   
   // If an enemy AI object was found in the scan
   if( %scanTarg )
   {
      // Get the enemy ID
      %target = firstWord(%scanTarg);

      // Don't shoot at yourself
      if( %target != %ai )
      {
         // Cause our AI object to aim at the target
         // offset (0, 0, 1) so you don't aim at the target's feet
         %ai.setAimObject(%target, "0 0 1");
         
         // Tell our AI object to fire its weapon
         %ai.setImageTrigger(0, 1);
         return;
      }
   }

   // If no valid target was found, or left mouse
   // clicked again on terrain, stop firing and aiming
   %ai.setAimObject(0);
   %ai.setImageTrigger(0, 0);
}


Now, your player will continuously shoot at any other player you left click on (accuracy not guaranteed). Press the 'b' key to spawn targets to shoot at and blast away. The AI player will be locked in auto-fire mode until you left click on the terrain or on another target.


We now have the base functionality for moving the player and the camera, selecting a target, and attacking is now complete.


Tweaking Attacks

You might have noticed some flaws with the base code:

  • The first shot usually misses
  • AI keeps shooting after enemy is dead
  • Enemy does not appear to "die" when health reaches 0


We are going to try and correct these one at a time using TorqueScript and the editors. Let's start by making our first shot be on target. The reason the first shot may miss entirely is because the AI is firing before it has fully turned to aim at the target.


To fix this, open scripts/gui/playGui.cs., scroll down to the PlayGui::onMouseDown function, and locate the following line of code:

// Tell our AI object to fire its weapon
%ai.setImageTrigger(0, 1);


Replace the above code with the following:

// Tell our AI object to fire its weapon in 100 milliseconds
%ai.schedule(100, "setImageTrigger", 0, 1);
                


Remember, the %ai variable contains a handle to our AI player object. The AIPlayer object, which is a child class of SimObject, can make use of a method named schedule. Instead of calling the setImageTrigger function immediately, we can schedule it to go off in delayed manner.


Schedule (ConsoleMethod) Parameters

simObject.schedule(time, command, arg1...argN)
  • time - Number of milliseconds to wait before calling the command.
  • command - Member function (belonging to the simObject using schedule) to call
  • arg1...argN - Parameters, comma separated, to pass into the command.


The AI we control should now have time to turn and face the target before firing off the first shot. The code is currently delayed by 100 milliseconds, so you can adjust that number based on desired performance.


Next, we will change the auto-fire behavior. Instead of having the AI constantly attack a target, even after it is dead, we are going to modify the code to only cause our player to attack when a mouse button is clicked. In the same function we were just working in, locate the first schedule line we created

// Tell our AI object to fire its weapon in 100 milliseconds
%ai.schedule(100, "setImageTrigger", 0, 1);


Then add the following directly under it:

// Stop firing in 150 milliseconds
%ai.schedule(150, "setImageTrigger", 0, 0);


If you have not been saving after every script change, you should definitely do so. Save, then run your game to test the changes made to the attack routine. Your AI should now be facing the target on the first shot, and only attack when you click on the target.


There is one more change we can make to make the combat provide more feedback. Each enemy AI starts with health, which is diminished each time it gets shot. The Full template this tutorial is based on is originally intended for a FPS deathmatch game. When an actor dies, a death animation is played.


The death animation code can be found in game/scripts/server/player.cs. Open this file, then scroll down to the following function:


function Player::playDeathAnimation(%this)
{
if (isObject(%this.client))
   {
      if (%this.client.deathIdx++ > 11)
         %this.client.deathIdx = 1;
      %this.setActionThread("Death" @ %this.client.deathIdx);
   }
   else
   {
      %rand = getRandom(1, 11);
      %this.setActionThread("Death" @ %rand);
   }
}


The template uses Gideon as the stock actor. The model ships with 11 death animations, which are labeled as "death#" (where # is 1 - 11). This works well for a Player constantly dying, but for an AIPlayer in this tutorial, we only need 1 death animation. This tutorial also mainly works as a client side (single player) prototype.


In simpler terms, we do not need to use the death index (.deathIdx) or %client variables. We can simply call the first death animation available. Change the ::playDeathAnimation(...) function to the following:

function Player::playDeathAnimation(%this)
{
   if (isObject(%this.client))
   {
      if (%this.client.deathIdx++ > 11)
         %this.client.deathIdx = 1;
      %this.setActionThread("Death" @ %this.client.deathIdx);
   }
   else
   {
      %rand = getRandom(1, 11);
      %this.setActionThread("Death" @ %rand);
   }
}

Now, when the target AI loses all its health it will play a death animation and eventually disappear.


Destination Markers

In most RTS or Hack & Slash games, some kind of marker is placed on the ground where you clicked. This is usually a visual aid to let you know the move assignment was given, the destination has been set, and the AI is moving.


We are going to add this functionality to our prototype to make it easier to track our AI player using the Material Editor, Decal Editor, and TorqueScript. First, we need to create a material for the marker.


Creating a Material

To get started on our marker creation, run your project in the World Editor. Next, open the Material Editor and click on the Create New Material button.


Image:MarkerNewMaterialButton.jpg


At this point, the current material will be switched to an orange warning texture signifying that no diffuse map has been applied. Change the Material name to "gg_marker" and press enter to apply the change. Next, click on the Diffuse Map box to open the file browser. Navigate to the game/art/decals folder and select the g_marker.png file. This asset was given to you at the beginning of this guide:


(click to enlarge)



Your new material is nearly complete. However, you should notice that the marker file and the material do not look the same. Compare the two:


Marker File

Image:g_marker.png


Material

Image:gMaterialBefore.jpg


This is easy to fix. While editing the gg_marker material, go to the very bottom in the Advanced Properties section and turn on Alpha Threshold:


Image:toggleAlphaThreshold.jpg


This will immediately toggle alpha visibility of the material:


Image:alphaToggled.jpg


Move the threshold slider until you get to a smooth GarageGames icon circle, which should be around 80:


Image:gMaterialAfter.jpg


You are finished with the material. Click save the save button, which will write out the following data to game/art/material.cs:

singleton Material(gg_marker)
{
   mapTo = "unmapped_mat";
   diffuseMap[0] = "art/markers/g_marker.png";
   alphaTest = "1";
   alphaRef = "80";
};


This is the benefit of using the visual editor to create your materials and decals, instead of manually writing them out in TorqueScript. Let's move on to creating the decal.


Creating a Decal

To create a marker decal, run the World Editor and then open the Decal Editor. Click on the New Decal Data button, next to the garbage bin , and name your new entry "gg_decal".


Image:MarkerNewDecal.jpg


Next, click on the box in the Material Field of the decal properties, as shown below:


This should open the Material Selector. Locate the gg_maker material we created earlier, click on it, then press the Select button:


(click to enlarge)



The Decal Editor's preview box will display what your new decal will look like in the scene.


(click to enlarge)



That's all that needs to be done to create the decal. Save your level, and your decal data will automatically be written out to game/art/decals/managedDecalData.cs:

datablock DecalData(gg_decal)
{
   textureCoordCount = "0";
   Material = "gg_marker";
};

Spawning the Marker

Now that we have a destination marker, we need to add it upon clicking on the terrain and then delete it when our player reaches its destination. Start by opening game/scripts/gui/playGui.cs. Find the PlayGui::onRightMouseDown function. Inside of this function, replace everything inside this code block:

if( %scanTarg )
{
   // Replace everything in here
}


With the following code:

// Get access to the AI player we control
%ai = LocalClientConnection.player;
      
// Get the X,Y,Z position of where we clicked
%pos = getWords(%scanTarg, 1, 3);
      
// Get the normal of the location we clicked on
%norm = getWords(%scanTarg, 4, 6);
      
// Set the destination for the AI player to
// make him move
%ai.setMoveDestination( %pos );

// If the AI player already has a decal (0 or greater)
// tell the decal manager to delete the instance of the gg_decal
if( %ai.decal > -1 )
   decalManagerRemoveDecal( %ai.decal );

// Create a new decal using the decal manager
// arguments are (Position, Normal, Rotation, Scale, Datablock, Permanent)
// AddDecal will return an ID of the new decal, which we will
// store in the player
%ai.decal = decalManagerAddDecal( %pos, %norm, 0, 1, "gg_decal", true );


Save your script, then run the game. When you right click on the terrain, the GarageGames symbol should render as a decal at the destination.


(click to enlarge)




Erasing the Marker

The last thing we need to do is erase the destination marker when our AI player gets to it. Open the game/art/datablocks/BoomBot.cs file, then add the following:

// This is a callback function
// This is automatically called by the engine as part 
// of the AI routine
// %this - The BoomBotData datablock
// %obj - The instance of this datablock (our AI Player)
function BoomBotData::onReachDestination(%this, %obj)
{
   // If there was a decal placed, then it was
   // stored in this %obj variable (see playGui.cs)
   // Erase the decal using the decal manager
   if( %obj.decal > -1 )
      decalManagerRemoveDecal(%obj.decal);
}


Now, when the AI player reaches its destination the marker will be deleted.


Camera Modes

Now that you've got control of your character, it's time to improve on the camera controls. By default, the Full Template starts observers in "Fly" mode - as if you were an insect flying around the level. This is fine for observing an FPS match, but not very easy to control for a top-down style game.


Fortunately, there are other camera modes that may be better suited to this type of game play.


Orbit Camera


Open the Torque Toolbox, select the empty terrain level, then click the World Editor button. Once you are in the editor, locate the spawn sphere in the scene, we previously named it PlayerSpawn, and select it.

Add the following to the spawnScript field:

// OrbitObject mode requires an object to orbit
LocalClientConnection.camera.setOrbitObject($SpawnObject, mDegToRad(50) @ " 0 0", 0, 30, 30);


Lets break this command down. LocalClientConnection.camera.setOrbitObject() puts the camera into OrbitObject mode. The first argument is the object to orbit around. When the spawn script is called, the $SpawnObject variable is automatically created for you in the engine. Since our AI player is what is being spawned, that is what we need to orbit.


The second argument is a vector representing the angle of the camera in (x, y, z) or (pitch, roll, yaw) if you prefer. Here it is pitched 50 degrees down, with 0 roll and 0 yaw.


The next three arguments are the allowed distances from the target: min distance, max distance and current distance: here 0, 30 and 30 respectively. This function may take additional optional parameters: an ownership flag denoting if the object orbited by the camera belongs to the camera's client, an offset if the camera should focus somewhere other than the object's center, and a flag specifying if the camera should be locked.


If you were to start the game now, the camera would be locked on to your character. Pressing 'm' will allow you to reposition the camera angle, although it will still follow the player.


Overhead Camera

Cameras used by RTS games are slightly different from the Hack & Slash or Fly cameras. They are characterized by a camera that moves laterally along the x and y axis, but generally not in z. This can be realized in T3D by using the "Overhead" camera mode:


Earlier in this tutorial, you were told to name your spawn sphere PlayerSpawn. The following code will not work if you have not performed this step. Add the following to the spawn script field in the spawn sphere properties.


Open the Torque Toolbox, select the empty terrain level, then click the World Editor button.


Once you are in the editor, locate the spawn sphere in the scene, we previously named it PlayerSpawn, and select it.


Add the following to the spawnScript field (Replacing the code we added in the last section)s:

LocalClientConnection.camera.position = VectorAdd(PlayerSpawn.position, "0 0 30");
LocalClientConnection.camera.lookAt(PlayerSpawn.position);
LocalClientConnection.camera.controlMode = "Overhead";


With this setup, the camera will be free to move around with the standard "wasd" controls, but it will not move vertically in the world. This lets you pan around the battlefield more easily than in the Fly mode.


To enable vertical movement, open game/scripts/client/default.bind.cs. Locate the line following line:

moveMap.bind(keyboard, b, spawnAI);


Just below it, add below the following:

moveMap.bind( keyboard, e, moveup );
moveMap.bind( keyboard, c, movedown );


If you are a traditional RTS player and wish to use the mouse wheel, there is an alternative solution to adjusting camera elevation. At the bottom of default.bind.cs, add this function:

// Adjusts the height of the camera using the mouse wheel
function mouseZoom(%val)
{
   // If wheel was scrolled forward
   // move camera closer to the ground
   if(%val > 0)
   {
      commandToServer('adjustCameraHeight', -3);
   }
   // If wheel was scrolled back
   // move camera away from the ground
   else
   {
      commandToServer('adjustCameraHeight', 3);
   }
}


Next, open game/scripts/server/commands.cs. We will add the server command to adjust the camera height at the bottom of the script file:

// Server command that adjusts camera height
function serverCmdadjustCameraHeight(%client, %adjustment)
{
   // Take the current camera position (a vector)
   // Then add or subtract from the Z element, based on
   // the %adjustment value passed in
   %client.camera.position = VectorAdd(%client.camera.position, "0 0 " @ %adjustment);
}


A new method of calling functions has been introduced. In the above code, we are sticking to the client/server architecture of Torque 3D. Typically, actions such as navigating through GUIs, rendering, and input are handled on the client. However, when actions have an effect on the game, they should be performed on the server.


Camera location can usually be handled as a client operation, but this is a good opportunity to show off the client/server communication. The default.bind.cs is a client script, which contains the client function mouseZoom(...). This is only called when there is a client action, such as the mouse wheel input.


Once the client action has been performed, a message is sent to the server to act on it: commandToServer('adjustCameraHeight', -3);. The first parameter is the name of the server command/function to call, and the rest of the parameters are arguments used by the command. In this situation, based on the direction of the mouse wheel rotation a positive or negative 3 will be sent to the server command which adjusts the camera elevation by the value.


Now that the functions are set up, all that is left is creating a key bind to call them. Back in default.bind.cs, add the following to the bottom of the script:

moveMap.bind( mouse, zaxis, mouseZoom );

You should be able to zoom in and out on your actor using your mouse's scroll wheel


If you want to play around with the camera settings created in this tutorial, add the following code to the bottom of game/scripts/server/commands.cs.

function serverCmdRTSOrbit(%client)
{
   %client.camera.setOrbitObject(%client.player, mDegToRad(30) @ " 0 0", 0, 25, 25);
}

function serverCmdRTSOverhead(%client)
{
   %client.camera.position = VectorAdd(%client.camera.position, "0 0 5" );
   %client.camera.lookAt(%client.player.position);
   %client.camera.controlMode = "Overhead";
}


You can call these functions using the usual commandToServer syntax. Just type the following in the console (press ~)

commandToServer('RTSOrbit');

commandToServer('RTSOverhead');

Conclusion

The purpose of this tutorial was to show you some of the more advanced capabilities of TorqueScript, and combine the language with Torque 3D's visual editors to create a prototype game. As you just experienced, getting a non-FPS prototype game started does not take long.


Make sure you have read through all the comments accompanying the new code, as they are part of the tutorial. At this point you can move on to other tutorials, or improve upon the code to create something more unique. There is always room for improvement, such as:

  • Changing the projectile behavior by adjusting the velocity, damage, and explosion radius
  • Make the targets move around and attack the player
  • Add key bindings to change camera modes on the fly
  • Handle building placement along with the player controls

You can download the completed scripts by CLICKING HERE.

If you wish to download the scripts and assets in a single file, CLICK HERE.