Game Development Community

dev|Pro Game Development Curriculum

Artificial Intelligence Beginning

by Mark Holcomb · 11/24/2004 (6:00 pm) · 72 comments

Download Code File

I was looking for a way to make Kork a little more responsive and aggressive. To which end I have come up with the following AI scheme in scripting.

I have created a simple system that allows the designer to drop markers in the game map that will mark where patrolling 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 themselves can be given two dynamic variables in the map editor. The first is 'respawn' which will determine whether a bot respawns or not. The second variable is 'pathname' which should be set to a valid path on the map. (If no path is set the bot acts as a stationary guard.)

The bots will patrol the paths, routinely scanning for nearby clients to target.

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'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.

In my code I wiped out using AIManager, and placed all of the AIManager code in a seperate file called AIManger.cs - which I don't load. I don't use it - because each bot thinks individually based on it's attention level.

To implement this version of AIPlayer the following changes need to be made.

1. Back up your original game.cs, player.cs, and AIPlayer.cs

2. In game.cs: The section for function StartGame needs to modified the following ways:
Delete the following lines.
// Start the AIManager
   new ScriptObject(AIManager) {};
   MissionCleanup.add(AIManager);
   AIManager.think();

and add this in it's place:

AIPlayer::LoadEntities();

3. 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.getState() $= "Dead")
{
   if(%obj.isbot == false)
   {
     %client.onDeath(%sourceObject, %sourceClient, %damageType, %location);
   }
}


4. Replace AIPlayer.CS with the code from the file newaiplayer.cs
5. Load your map - Stronghold as an example. Kork should be missing.
6. Go into the map editor. (F11) Then go into the Editor Creator (F4)
7. Under Shapes there should be a new drop down called AIMarker, under that a new item called AIPlayer.
8. Create a new AIPlayer marker.
9. Select your marker, position it where you like and hit (F3) to modify the marker.
10. Create a new dynamic variable called 'pathname' and set its value to 'path1'
11. If you want to override the default respawn value - create another dynamic variable called respawn and set it's value to true or false.
12. Update your item by clicking 'APPLY' - very important and easy to miss step.
13. Save your mission and reload it.

A bot called Kork1 should appear and be following the usual path. Kork1 should shoot at you if you are in front of him, and within range.

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

I'd like to thank the other members of this website whose code has been used in several places in the script above.

About the author

Recent Blogs

• Scripted Doors
• AI Guard Unit
#41
04/03/2006 (4:20 pm)
Thanks Mark. Great resource.
#42
04/05/2006 (12:21 pm)
Thanks a lot :D
#43
04/18/2006 (9:26 am)
I got a problem. I lost some of my work with this implementation along with it. I've been peicing my work together again. My problem is that I've been having problems getting the ai to follow a path.

this is how my path looks like in the .mis file

new Path(path1) {
      isLooping = "1";

      new Marker(marker0) {
         position = "-170.446 -705.673 112.477";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "1";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Spline";
      };
      new Marker(marker1) {
         position = "-148.267 -684.779 112.583";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "2";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Spline";
      };
      new Marker(marker2) {
         position = "-103.551 -694.558 112.076";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "4";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Spline";
      };
      new Marker(marker3) {
         position = "-80.7855 -726.009 110.933";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "3";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Spline";
      };
      new Marker(marker4) {
         position = "-144.253 -766.646 112.652";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "5";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Spline";
      };
   };

everything else is as is. the bot appears well enough but just stands there doing nothing. Help please.
#44
06/25/2006 (12:22 pm)
Thanks a lot for the resource =) VERY useful tool!

It worked beautifully the first time I tried it, except I haven't been able to get it to respawn. I've tried adding the dynamic variable and setting it to true (even false) and I haven't noticed any difference. I have hit Apply, he just doesn't respawn after he dies =P

Thanks again =)
#45
08/19/2006 (9:29 am)
Excellent! Thanks for sharing :)
#46
08/28/2006 (5:46 am)
hi
i tried it but have a little problem
it gives me the following error when i try to start the game

Loading compiled script fps/server/scripts/aiPlayer.cs.
fps/server/scripts/aiPlayer.cs (0): Unable to find parent object PlayerBody for
PlayerData.

can anybody please guide me through this
help most appreciated
thanking you
#47
11/26/2006 (6:24 am)
Another old thread that I have bumped into which is GREAT. This will help a great deal, good comments on the code too ;o)

Thanks for your help!
RT
#48
12/18/2006 (3:23 pm)
Ok, I figured out how to make the aiPatrols follow you if they see you.



function AIPatrol::GetClosestHumanInSightandRange(%this, %obj)
{
%dist=0;
%index = -1;
%botpos = %this.getposition();
%count = ClientGroup.getCount();
for(%i=0; %i < %count; %i++)
{
%client = ClientGroup.getobject(%i);
if (%client.player !$= "" || %client.player >0)
{
%tgt = %client;
%playpos = %client.player.getposition();


%tempdist = vectorDist(%playpos, %botpos);

//Is target in range? If not bail out of checking to see if its in view.
if (%tempdist <= $AI_PATROL_DETECT_DISTANCE)
{
//Lower attentionlevel to increase response time...
%this.attentionlevel--;
if(%this.attentionlevel < 1) %this.attentionlevel=1;

//Is the target within the fov field of vision of the bot?
if(%this.Istargetinview(%obj, %tgt, %obj.fov))
{



//This change by LS to make the bots follow you!
%this.setMoveDestination(%playpos);


//Lower attentionlevel to increase response time...
%this.attentionlevel--;
if(%this.attentionlevel < 1) %this.attentionlevel=1;
if(%this.CheckLOS(%obj, %tgt))
{
%this.attentionlevel--;
if(%this.attentionlevel < 1) %this.attentionlevel=1;

if(%tempdist < %dist || %dist== 0)
{
%dist = %tempdist;
%index = %i;
}

}
}
}
}
else
{
%this.attentionlevel = %this.attentionlevel + 0.5;
if(%this.attentionlevel > $AI_PATROL_MAX_ATTENTION) %this.attentionlevel=$AI_PATROL_MAX_ATTENTION;

}
}
return %index;
}
#49
12/30/2006 (6:05 pm)
I'm having a weird issue with this terrific resource, and as a novice scripter I'm having a bit a trouble even trying to decide where to look for the problem. I'm using it in conjunction with the "Flight Compendium" resource, only with a wheeled vehicle (which is supported by that resource). In other words, I'm trying to get my bots to drive on a path.

When I use a "regular" bot they drive the path reasonably well. But when I use the bots generated by this resource, they drive in circles. It's as though they drive only full tilt left or full tilt right. He walks the path hunky dory, it's only when I throw a car in front of him and he starts driving that the trouble begins.

It occurs to me that he could be trying to strafe? Where would I go to examine how the bot tries to move? Any ideas? I hope this is reasonably clear.
#50
02/01/2007 (7:18 pm)
hey everyone!

@Mark: Man...! You rule!

@Tasty Green Pees :-, : Try to put your aiMarker inside your pathMarker group, here is your code redone:

new Path(path1) {
      canSaveDynamicFields = "1";
      isLooping = "1";

      new Marker(marker0) {
         canSaveDynamicFields = "1";
         position = "-170.446 -705.673 0.1";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "1";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Linear";
      };
      new Marker(marker1) {
         canSaveDynamicFields = "1";
         position = "-148.267 -684.779 0.1";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "2";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Linear";
      };
      new Marker(marker2) {
         canSaveDynamicFields = "1";
         position = "-103.551 -694.558 0.1";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "3";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Linear";
      };
      new Marker(marker3) {
         canSaveDynamicFields = "1";
         position = "-80.7855 -726.009 0.1";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "4";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Linear";
      };
      new Marker(marker4) {
         canSaveDynamicFields = "1";
         position = "-144.253 -766.646 0.1";
         rotation = "1 0 0 0";
         scale = "1 1 1";
         seqNum = "5";
         type = "Normal";
         msToNext = "1000";
         smoothingType = "Linear";
      };
   };
   new Item() { //AIMarker inside the pathMarker group.
      canSaveDynamicFields = "1";
      position = "-150.504 -716.515 0.238988";
      rotation = "1 0 0 0";
      scale = "1 1 1";
      dataBlock = "AIPlayerMarker";
      collidable = "0";
      static = "0";
      rotate = "1";
         onGroup = "Default Value";
         respawn = "true";
         pathName = "path1";
   };

Hope it works for you, now its time to kill the bastard!!

great resource!
#51
03/13/2007 (9:17 pm)
im assuming this is for the starter fps? and not the starter rts?

can someone confirm this before i waste my time
#52
03/14/2007 (12:02 pm)
It is, but I doubt you'd be wasting your time by studying the resource. It's actually a very simple, elegant way of adding AI, and I suspect it wouldn't take much modification to use elsewhere. In fact, if you get it working, the necessary changes would make a wonderful post, here! :-)
#53
06/16/2007 (12:31 pm)
nevermind
#54
08/02/2007 (9:57 am)
I followed this tutorial exactly but my AI did not spawn, whats wrong?
#55
08/03/2007 (8:04 am)
i found the problem but i dont know how to fix it.

Loading AIPlayer entities...
rw/server/scripts/aiPlayer.cs (226): Unable to instantiate non-conobject class AIPlayer.
Set::add: Object "0" doesn't exist
rw/server/scripts/aiPlayer.cs (248): Unable to find object: '0' attempting to call function 'EquipBot'
rw/server/scripts/aiPlayer.cs (250): Unable to find object: '0' attempting to call function 'setShapeName'
rw/server/scripts/aiPlayer.cs (251): Unknown command getTransform.
Object AIPlayerMarker(358) AIPlayerMarker -> ItemData -> ShapeBaseData -> GameBaseData -> SimDataBlock -> SimObject
rw/server/scripts/aiPlayer.cs (251): Unable to find object: '0' attempting to call function 'setTransform'
rw/server/scripts/aiPlayer.cs (252): Unable to find object: '0' attempting to call function 'followPath'
rw/server/scripts/aiPlayer.cs (256): Unable to find object: '0' attempting to call function 'schedule'
rw/server/scripts/aiPlayer.cs (117): Unknown command sethidden.
Object (1473) Item -> ShapeBase -> GameBase -> SceneObject -> NetObject -> SimObject
#56
01/29/2008 (3:04 am)
z
#57
03/05/2008 (12:00 pm)
Thank you for this resource Mark. I can't get back to working on my game because I am having too much fun placing and killing Korks lol.
#58
05/12/2008 (6:47 am)
this don't work for me :( (i may have done it wrong..im new :3)

Compiling starter.fps/server/scripts/player.cs...
starter.fps/server/scripts/player.cs Line: 826 - parse error
>>> Advanced script error report. Line 826.
>>> Some error context, with ## on sides of error halt:
%sourceClient = %sourceObject ? %sourceObject.client : 0;



if (%obj.getState() $= "Dead")

{

if(%obj.isbot == false)

{

%client.onDeath(%sourceObject, %sourceClient, %damageType, %location);

}

}



function Armor::onDamage(%this, %obj, %delta)

##{##

// This method is invoked by the ShapeBase code whenever the

// object's damage level changes.

if (%delta > 0 && %obj.getState() !$= "Dead") {



// Increment the flash based on the amount.

%flash = %obj.getDamageFlash() + ((%delta / %this.maxDamage) * 2);
>>> Error report complete.
#59
05/12/2008 (12:33 pm)
@Oliver: This is the key messsage: "starter.fps/server/scripts/player.cs Line: 826 - parse error"

It means you've got a simple syntax error in your script. Unfortunately, Torque only gives you a general area, but the error should be _before_ the line indicated by hash marks.

Most likely you don't have matched {} or () somewhere up there. If you use an IDE like Torsion it will help you to find those.
#60
05/13/2008 (4:56 am)
So that's what it means :D