Game Development Community

dev|Pro Game Development Curriculum

AI Guard Unit

by Mark Holcomb · 11/27/2004 (5:18 pm) · 335 comments

Download Code File

This is my second attempt at making an AI controlled character. The first was an
AIPlayer that would follow paths. This character is a guard unit. The guard will
wait at it's post (spawn point) until it sees a target. It will then attack that
target while trying to close with it.

If the target is lost the bot will wait at the last place it saw the character and
look around for a little bit, and then it will try to return to it's post.

There is a chance the bot will get stuck trying to return, but there is a simple
routine that has the bot try to move in random directions to try and clear itself
of any obstacles between it and it's post. It's not perfect.

The thinking routine is a simple state machine - which can be expanded on to give the bot more responses and actions.

As with my first ai character, I am using a simple system that allows the designer to drop
markers in the game map that will mark where the bots will start out. When the mission is loaded, the markers are detected and bots are spawned at the marker locations. The markers are then hidden from view. (The markers can be left visible to help in map editing.)

The markers for the guards can be given a dynamic variable called respawn. (Assigned to the marker during map editing.) 'Respawn' will determine whether a bot respawns or not upon death.

The bots have an attention setting. How often they scan is determined by their attention level. The bots get more sluggish (freeing up processor time) when targets are too far away. Conversely, the bot becomes incrementally more attentive as targets come within range, and further aware as targets come into sight.

When a target is found in range and in sight the bot will shoot at the target. The firing sequence is a step of scheduled calls that call for a firing cycle, a trigger down cycle, and a firing delay to control bot rate of fire.

When a bot is attacked it will attempt to sideatep and it's field of vision is temporarily increased to a 360deg field of vision - to emulate looking around to see what happened. The bot's attention level is also set to make it think at it's fastest rate when attacked.

To use the AIGuard...the following changes need to be made.

1. Back up your original game.cs, player.cs, and your current build of Torque. To install AIGuard will require a recompile, since I have created a new class cloned by copying AIPlayer.cc and AIPlayer.h and renaming all references to AIPlayer to AIGuard.
(I did this because I wanted to be able to run both my AIPatroller and AIGuards in the same maps and did not want to have any confusion between them.)

2. Add the files AIGuard.cc and AIGuard.h to your Torque project. (In my instance I saved them to my c:\Torque\engine\game directory and then added them into my project.)

3. Recompile your project and copy your new executable to the appropriate directory for your app.

4. Copy the file AIGuard.cs into your server/scripts directory.

5. Modify game.cs to add the line

exec("./aiGuard.cs");

to the function onServerCreated().

6. Also in game.cs: The section for function StartGame needs to modified the following ways:

Below the lines that read:

// Start the AIManager
new ScriptObject(AIManager) {};
MissionCleanup.add(AIManager);
AIManager.think();

add this:

AIGuard::LoadEntities();

(If you followed my previous resource you may not have any reference to AImanager. Don't fret... just look for the place in game.cs where you have

AIPlayer::LoadEntities

and put in

AIGuard::LoadEntities();

right underneath it.

7. In player.cs in the code for Armor::Damage modify the lines

// Deal with client callbacks here because we don't have this
// information in the onDamage or onDisable methods
   %client = %obj.client;
   %sourceClient = %sourceObject ? %sourceObject.client : 0;
   if (%obj.getState() $= "Dead")
      %client.onDeath(%sourceObject, %sourceClient, %damageType, %location);

to read:

// Deal with client callbacks here because we don't have this
   // information in the onDamage or onDisable methods
   %client = %obj.client;
   %sourceClient = %sourceObject ? %sourceObject.client : 0;   if (%obj.isbot == true)
   {
     %obj.attentionlevel=1;
     %obj.enhancefov(%obj);
   }
 
  if (%obj.getState() $= "Dead")
 {
     if (%obj.isbot == true)
    {
        if (%obj.respawn == true)
          {
           %obj.delaybeforerespawn(%obj.botname, %obj.markerpos, %obj.marker);
           %this.player=0;
           }
    }
   else
  {
     %client.onDeath(%sourceObject, %sourceClient, %damageType, %location);
  }
  }


*** If you followed my previous resource there should be no need to change this code.

8. Load your map - Stronghold as an example.
9. Go into the map editor. (F11) Then go into the Editor Creator (F4)
10. Under Shapes there should be a drop down called AIMarker, under that a new item called AIGuard.
11. Create a new AIGuard marker.
12. Select your marker, position it where you like and hit (F3) to modify the marker.
13. If you want to override the default respawn value - create a dynamic variable called respawn and set it's value to true or false.
14. Update your item by clicking 'APPLY'- very important and easy to miss step.
15. Save your mission and reload it.

A bot called Guard1 should appear at the spot of your marker.
If you come within range of the guard he should shoot at you and try to hunt you down.
If you get away, or when you die, he should return to his post.

I hope the resource helps other people get up and running with some AI code in their game.

And again, I'd like to thank the other members of this website whose code has been used in several places in the scripting to make this all work.

Mark H.

P.S. I've also included my AIPatrol class files with this - to install it follow the same instructions as for AIGuard, just substitute AIPatrol where AIGuard appears in the instructions. They can both be run at the same times with no problems.

P.S.S. 11/28/04 - I modified the AIPatrol.cs file to correct for a couple of typos.

P.S.S.S 12/3/04 - Added ammo and health seeking capabilities and fixed some errors. (Read posts below - or file in .zip for full details.)
#121
09/14/2005 (10:48 am)
how do you stop things being displayed above the players head like dead or attacking? I cant find how to remove it in the code, just how to change it.
#122
10/03/2005 (11:29 pm)
very useful resources .i want to implement scoring system when bot killed player the score is updating
(server/game.cs) onDeath . but where to write to update the score when player kill bot
i try to write this in (player.cs) damage function but its not working. and should we have to include onDeath function in AIGuard.cs . Since when my bot get killed i get this warning message
starter.fps/server/scripts/player.cs (833): Unable to find object: '' attempting to call function 'onDeath'
#123
10/15/2005 (4:52 am)
how do the bot know who to fire at?
(want to change it so I can have two teams)
#124
10/15/2005 (11:10 am)
James, the bots fire at whoever gets in range.
#125
10/16/2005 (10:36 am)
matt, I placed 2 together and they ganged up on me without even looking at each other, I was miles away.
#126
10/16/2005 (4:06 pm)
Nice Resource,

thanks

I got it working without too much difficulty
#127
10/19/2005 (8:07 pm)
I've just added this resource in and I've placed the bot in okay. However, when I reload the mission, the bot doesn't appear at all. I've read previous posts on this and I've tried deleting all the .dso files in starter.fps. Didn't work out. How do I solve this problem?
#128
10/30/2005 (3:25 am)
ok so im a TOTAL newbie to the programming side of this... bear with me please, and thank you.
so i tried implimenting this without success 4 times, 2 times the last 2 nights for 20+ hours... searched for what i may be doin wrong

in the steps above i followed them word for word, got the marker in the game... but upon reload i see an image of the ork player just staning there, no animations...

only line that confuses me is:
2. Add the files AIGuard.cc and AIGuard.h to your Torque project. (In my instance I saved them to my c:\Torque\engine\game directory and then added them into my project.)

how do i add the files to the project in Eclipse???

i copied the files to the directory, refreshed Eclipse, and thought that was all to do....
....my search-foo brought up a targets.torque.mk, thingie/file/whatthehellovasonofa-yupthatmustbesumthin....

soo i added the game/aiGuard.cc to the end of the other 'game' files... maybe a recompile will work this time.....

i did a make -k clean all

(back to reinstalling it all from scratch again....)


fyi: new install of current SDK (whatever the version) download on fresh install of TBE (eclipse)
#129
10/30/2005 (5:06 am)
MOUHAHAHAHAHA!
I win...

well, i got it to work.
unfortunatly, i lost all the other code i'd worked on... oh well.
after four days of work and 30+ hours, it's great to see them shoot at me.
i noticed that after death the bots do a respawn in conjuction with the errors in the log. time to follow this area, and fix the respawn too, but that's for another night.

to all other newbs- to add the .cc and .h files in the compile (eclipse) you must add the aiGuard.cc to the list in:

C:\Torque\SDK\engine\targets.torque.mk

scroll down, you'll see the area with:

SOURCE.GAME=\
game/main.cc \
game/debris.cc \
game/debugView.cc \
game/gameFunctions.cc \
game/ambientAudioManager.cc \
game/audioEmitter.cc \
game/banList.cc \
...
...
game/aiConnection.cc \
game/aiPlayer.cc \
game/version.cc \
game/aiGuard.cc \ //<---------------------------- (add it here, but don't put this text.)

Thanks again for a great BUNCH of coding!
#130
11/04/2005 (4:10 am)
ok, i got a huge problem and i dont know where to start.
First off, the code works great when im using the starter.fps ork
but, when i change the Player to my character, by replacing the files, my character imports 'properly', runs, plays animations,
and i have no errors about the character. (im using the orks code, just renaming my dts to Player, and all its sequences)

BUT the bots dont detect my figure when on guard.
If i get close to them and Jump, the detect me while in the air, or when im uphill from them. so there is something they are detecting that dissappears under ground.
If i shoot one of them, they stay locked onto me properly and can suddenly "see" me properly.

It sounds like it could be a bounding box issue, but its showing up in Show tool properly. Does the ai use the LOSCollision to detect players?

any ideas to check?

ok, it looks like the ai can see me fine when im facing AWAY from them, they shoot me in the back fine, but if i stand looking at them the little numbers above their heads show that their rate slows down (goes to 5, 1 means fast thinking). so they are not detecting me from the front??? i remember seeing a post somewhere else about this but for the life of me i cant find it....

after manipulating the collision box, now the only way the bot detects the player is when i jump...
what does the bot draw line of sight to on the player?

Thanks in advance for your help.
#131
11/04/2005 (4:11 pm)
ok, im at a total loss.
i deleted the collision box, to let torque default to it own.
i can walk up to the ai and it does increase its thinking, but doesnt attack.
if i jump in front of him he detects me, but upon landing he looses me agian and returns to spawn point.
if i move right up to him (so our models are overlapping) then he detects me also. but i just move away and he looses me again.

but if i shoot him, he locks on and doesnt lose me, until i die, or he dies. makes it too easy if you can walk past em all.
#132
11/07/2005 (8:51 am)
Hi,

I have purchased TankPack and would like to customize this great AI code for yes.. whatelse Tank! Needless to mention.. it was unsuccesful! What I did was changed the datablock to AbramTank (or Sherman) and that's it which I really thought was not enough.. please help me.. simply guidance will do.

TIA

Edit: I have got it running with starter.fps already.
#133
11/07/2005 (1:15 pm)
you have aiguard working with starter.fps? Whats the problem then?
#134
11/07/2005 (5:52 pm)
Okay.. thanks for the reply James Thompson..

I have got it down to one simple question: how do I change from one shape to another? AIGuard spawns a new player shape by the following code:

// Create the demo player object
   %player = new AIGuard() {
   dataBlock = GuardPlayer;
   
   //The marker is the AIGuard marker object that the guard is associated with.
   //The marker object is kept with the player data because it's location, and
   //dynamic variable values are used in several functions. This also allows the addition
   //of future dynamic variables without having to change the spawn/respawn functions to
   //access them.
   marker = %obj;
   botname = %name;
  //Sets whether the bot is AI or not
   isbot=true;
   //Sets the bots field of vision
   fov=$AI_GUARD_FOV;
      
   //Thinking variables
   //Firing tells whether or not we're in the midst of a firing sequence.
   firing = false;
   //The 'action' variable holds the state of the bot - which controls how it
   //thinks.
   holdcnt=$AI_GUARD_HOLDCNT_MAX-1;
   action = "Holding";
   //The bots starting attention level is set to half of it's range.
   attentionlevel = $AI_GUARD_MAX_ATTENTION/2;
   
   //Oldpos holds the position of the bot at the end of it's last 'think' cycle
   //This is used to help determine if a bot is stuck or not.
   oldpos = %obj.getposition();
   };

I changed the second line which is
dataBlock = GuardPlayer;

to

dataBlock = AbramsTank;

p/s: I have checked AbramsTank declaration and it is okay.

and it gave the following error:
starter.racing/server/scripts/aiGuard.cs (439): Register object failed for object (null) of class AIGuard.
Set::add: Object "0" doesn't exist
starter.racing/server/scripts/aiGuard.cs (455): Unable to find object: '0' attempting to call function 'EquipBot'
starter.racing/server/scripts/aiGuard.cs (457): Unable to find object: '0' attempting to call function 'setShapeName'
starter.racing/server/scripts/aiGuard.cs (459): Unable to find object: '0' attempting to call function 'setTransform'
starter.racing/server/scripts/aiGuard.cs (461): Unable to find object: '0' attempting to call function 'schedule'

TIA

Edit: I am searching this forum for some clues/hints and still searching. Will post the solution once gotten it right.
#135
11/12/2005 (9:28 am)
If I want the bots to attack other bots. Like if one chases me and comes into range of another bot amd start to shoot each other. How Do change the code. Thanks
#136
11/14/2005 (1:28 pm)
I think your resource is amazing. It's working perfectly to me, but the bot's moviment is a bit strange. It's turn to many directions all the time and fast. I don't know why, I think it's triyng to find the player position, but this kind of moviment aren't much natural. I wondering if is possible just play the root animation and walk around instead of rotanting all the time like a crazy.

Thanks for your resource Mark and thanks in advance for some help.
#137
11/14/2005 (9:25 pm)
I have a question.
I love this AI and have been using it as well as a few others.
After lots of changes I'm finally happy with my new Guards.
Now, I'm out to create more type of Guards for my game.
Normally this wouldn't seem hard, but there are 2 parts that are stumping me.
$AI_GUARD_ENABLED and the other $AI_GUARD_ variables are global.
I assume I can just create $AI_BUNKERGUARD_ENABLED, etc. (ugly but works).
Or would moving these to the datablock be better?
My other puzzle is the usage of functions like AIGuard::Think.
These functions reference the engine code and are part of a class(? I'm still new to and learning C).
That means I can't copy/paste/rename/mod the aiguard.cs because these function use globals such as $AI_GUARD_SEEK_HEALTH_LV.
I realize I could copy, rename and paste the .cc and .h and change all the names and re-add them to my VC project.
That's just dirty and a waste because the class is really great and doesn't need to be changed for my game.
My only guess is to move the globals to values inside the datablock and replace the usage of globals with datablock.value inside the AIGuard functions.
I really need to solve this so I can have various types of guards.
Am I going in the right direction?
Any help?
#138
11/29/2005 (8:44 am)
Ainul - its the:

shapeFile = "insert path to dts here";


line in aiguard.cs
(sorry its been so long)

EDIT: that would change the shape from the orc to the tank shape but control may still be a problem, I am working on this
#139
12/02/2005 (6:49 am)
James,

Okay thanks for the pointer. I have been doing other programming task.. and will be doing the modification as told by you :)

Thanks again.
#140
12/11/2005 (7:20 pm)
Does anyone know if this resouce works with 1.4?

I have compiled the game and made changes but never got it to work. I was able to get the bot markers but nothing.

So before I got to far into it, just curious if anyone has this working on 1.4

Thanks