Torque/Script/Tutorials/Using Basic AI Commands

From TDN

Introduction

This tutorial will walk you through using the basic AI script commands that are built into stock TGE and TGEA.


The code for AI tends to be very specific to your game and its genre which makes it hard for Torque to implement anything general purpose.


The built-in script commands cover moving the bots from one place to another in a straight line, following a pre-made path, aiming at a moving object, aiming at a static position, and firing on that object.

There is a great deal that you can do with these basic commands and they can give you a jumping off point for writing far more complicated behaviors.

Contents


How to get Started

Load up Torque and load a mission. At this point you should be standing in the mission as an ork holding a crossbow. Let's detach the camera from the Player so that we can fly around. You can do this either by hitting F8 (will drop the camera at the player) or Alt-C (will drop the camera at the original spawn point). Fly the camera around a bit until you find an open patch of ground.

Now hit the ~ key (the key beside the 1 key on most keyboards) to bring down the console window. We are going to be copy/pasting script commands into this and observing the results.

Let the Fun Begin!

Welcome !!!!!!!!!

First, let's actually spawn a bot. Copy the following line of code into the text input field at the bottom of the console window and hit enter:

new AIPlayer(Bob) { datablock = "DefaultPlayerData"; position = LocalClientConnection.camera.getPosition(); };

You should have seen an ork AIPlayer spawn where your camera is and drop to the ground. Let's break down what exactly this script command did a little more:

new AIPlayer(Bob)

This piece of the script command is creating a new object of the type AIPlayer and giving it the name bob so that we can access the new bot by name.

datablock = "DefaultPlayerData";

This is telling the engine that the new AIPlayer will be using the PlayerData datablock named "PlayerBody". Basically, the datablock set up a bunch of static parameters that is going to be shared among all of the Players/AIPlayers that use this datablock. This includes things like which model to use, how fast they move, which weapons they can pick up, how high they can jump, and what sounds to use for collision. For the purpose of this tutorial we are simply using the same datablock as the default Player that you spawned in as.

position = LocalClientConnection.camera.getPosition();

Okay, this is going to dip a little bit into the underlying networking of Torque and touch on a few higher level scripting concepts. If you don't completely follow along don't sweat it. It'll make sense in time.

LocalClientConnection is a global script variable that gets created whenever you host a server. Since "singleplayer" in Torque is done by creating a server and then connecting a local-only client to that server we still have access to that variable. The variable is actually a GameConnection object which handles your connection to the server and can be a handy place to store data that is specific to a client. A client/connection is distinct from a Player or a Camera or WheeledVehicle since you can actually delete/recreate those without reconnecting to the server. By default, when a client joins a Torque game it creates a free flying camera that can be used until a Player or some other control object is created for the client to run around as. The script id for this camera is then stored in a dynamic script field on the client's connection object (i.e. LocalClientConnection.camera). When we detached from the Player before and started flying around as a camera what we were really doing was switching back to that camera. One thing to keep in mind here is that LocalClientConnection is only available if you are the host (which you are in singleplayer). For multiplayer you will have to access the client connections a different way (covered elsewhere).

We are using getPosition() to get the 3d coordinates of the camera that we are flying around as (try echo(LocalClientConnection.camera.getPosition()); to see what it is) and creating the AIPlayer at that position (position isn't part of the datablock parameters because it obviously varies from Player to Player).

Come chase me little Bob

Now, how do we get our new AIPlayer to run around? Torque has the most basic form of pathfinding possible built-in: move in a straight line from point A to point B and don't worry about running into things. You can see an example of this by flying the camera away from the bot (use ~ to hide and unhide the console window), pasting the following script command into the console, and hitting enter:

Bob.setMoveDestination(LocalClientConnection.camera.getTransform());

Bob should come running over to stand below wherever your camera was when you ran the command. Fly the camera around to a new position and run the command again (you can hit the up arrow in the console input field and it will cycle through your previous commands).

getTransform() is similar to getPosition() except that it also includes rotation information. We could use either in this case but it is often useful to have this extra information (for example: orienting a barrel to match your camera's rotation). Try running echo(LocalClientConnection.camera.getTransform()); to see what it is returning.

Fun with guns

Okay, time to give Bob a crossbow. Simply run this command:

Bob.mountImage(CrossBowImage, 0);

This uses the ShapeBaseImage system to mount a Crossbow image on your AIPlayer (in slot/mount 0). The image/weapon system can get a little complicated so I won't go into it here beyond showing you how to give one to the player.

This is great except that poor Bob doesn't have any ammo. So now run this command:

Bob.incInventory(CrossbowAmmo, 5);

Again, the inventory system can get pretty complicated but this is how you go about giving a Player/AIPlayer 5 crossbow bolts.

Target Practice


We need something for Bob to shoot at so let's fly over a little ways from Bob create a second bot named Dirk:

new AIPlayer(Dirk) { datablock="PlayerBody"; position=LocalClientConnection.camera.getPosition(); };

How do we get Bob to aim his crossbow at Dirk? Simple enough:

Bob.setAimObject(Dirk);

This is a pretty interesting command. It means that wherever Dirk moves to, Bob will automatically track him. The tracking code is run in C++ so it is quite quick and accurate. To see this in action fly the camera over to a new position where you can see Bob clearly and are pretty far away from Dirk and run:

Dirk.setMoveDestination(LocalClientConnection.camera.getTransform());

You should see Bob automatically turn to follow Dirk's movements (even up and down the hills).

Time to shoot at Dirk!

Bob.setImageTrigger(0,1);

This command tells the weapon/image in slot 0 that it is being "triggered" (same as when you push the mouse button). This causes the Crossbow to fire and to reload. Once all 5 bolts have been shot then Bob will be out of ammo and we will have to give him some more:

Bob.incInventory(CrossbowAmmo, 5);

Since the Crossbow is still in a "triggered" state, Bob will start firing right away. By default PlayerBody is limited to a maximum of 50 crossbow bolts (set in the datablock).

If Dirk dies just spawn a new one with the new AIPlayer(Dirk) command from above. You will have to reset Bob's AimObject also.

Bob has pretty poor aim


Unless you have just the right angle on Dirk, Bob is most likely shooting at Dirk's feet and isn't doing much damage. The problem is that the Dirk's position that Bob is tracking is centered at the pivot point of his bounding box which is located between the bottom of his boots. There are a couple of ways to fix this:

The first one is to use the setAimLocation() command to tell Bob to aim at a specific location rather than tracking Dirk directly. This can be done with this command:

Bob.setAimLocation(VectorAdd(Dirk.getPosition(), "0 0 1"));

The only problem with this command is that if Dirk (or a human controlled Player) moves then Bob will still be shooting at the old position and not the new one. You could counter this by setting up a schedule to reset the aim location but this is going to kill your performance. Be sure to note that we couldn't do Dirk.getPosition() + "0 0 1". We had to use the VectorAdd() script function to add two vectors together (+ will just add the first numbers of the two vectors).

Fortunately, there is an addition to TGE 1.4 that allows you to specify an offset to add to the setAimObject's position:

Bob.setAimObject(Dirk, "0 0 1");

Bob will now track any of Dirk's movements and shoot at 1 unit above his current position (essentially in the middle of Dirk's torso). You can use this offset variable to do some pretty cool things with leading a moving target or effecting the bot's accuracy dynamically.

Goodbye Bob


Time to say goodbye to Bob:

bob.kill();


Wrap up


You can do quite a lot with just these simple script commands. For example, I wrote an entirely script driven AI for a soccer game using the schedule() command and leveraging just the stock AI commands. You could also get pretty far into an fps shooter with these commands or do a simplistic rts. I did not cover using pre-defined paths in this tutorial with the bots because that requires a bit more setup to demonstrate but you can find an example of that in the starter.fps example. The Improved AI Guard Unit and the Killer Kork resources show a number of ways to expand upon these basic commands and can be useful references.