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
#21
12/05/2004 (8:48 pm)
I fixed that problem in my newer code as well, but never went back and changed the AIPlayer.cs file.

I'm pretty sure this will fix the problem, but back up your file just in case I'm wrong.

Look in the GetClosestHumanInSightandRange function for the line...

if (%client.player $= "" || %client.player ==0)

change that line to read:

if (%client.player !$= "" && %client.player > 0)   {

(Be sure to add the { at the end of the line.

Now drop down through the function until you find

%index = %i;
	}
              }
            }
          }
        }
else
    {
      //If there are no targets in view, then the bots attention will slowly lapse and increase
     //This will slow down how fast the bot thinks and how often it checks for threats.
    %this.attentionlevel = %this.attentionlevel + 0.5;
    if(%this.attentionlevel > $AI_PLAYER_MAX_ATTENTION) %this.attentionlevel=$AI_PLAYER_MAX_ATTENTION;
  }
}
    return %index;
}

This is at the end of 'GetClosestHumanInSightandRange.

Right above the word else, add 1 more } -closed bracket to the list of them.

I think this should fix your problem.

If you have any more issues post them here, and I'll look into them tomorrow evening.

Hope this helps, but yeah it would be easier if you'd just stay alive... :)


- I believe this also fixes the problem of the bots not looking for targets when one of the clients was dead. Before the code would drop out with a -1 - no target if it encountered a dead client.
#22
12/06/2004 (7:11 pm)
tried that and it gives some error..

I will keep plugging away at it tho, and look forward to any updates.. :)
#23
12/17/2004 (8:32 pm)
I only have one word. OUTSTANDING!!!

Having just started with Torque, this has been by far the easiest change to implement.
Not only did this work the first time out, but the documentation was right on the button.
If the rest of the documentation was this well done, I'd be halfway done by now.

Keep up the great work!!

Gratefully,

Radhat
#24
12/17/2004 (8:49 pm)
Thanks, if you liked this one you might want to check out my other resource on AI. it's a much more robust bot.
#25
03/05/2005 (6:56 am)
how can i monitor the ai player movement, i tried adding 'AIPlayer::onMove' and 'DemoPlayer::onMove' but none of them seems to be called when the player moves.

thanks for the useful resource
#26
03/05/2005 (8:45 am)
I don't have a function to monitor "onmove" in my class for the AI. The reason being that the state engine controls everything the player does. If you could tell me what it is you're trying to accomplish by monitoring the bots motion, then maybe I can help you figure out how to adapt the code.

As it is right now, the bot is pretty much in motion all the time, so it's kind of a moot point.

But it you're just needing to know if the bot has moved a certain distance so it can trigger an action, then you could add a variable at the end of the 'Think' cycle that would check the bots position and store it, then the next time through do a comparison of the bot's position against that and see how far the bot has moved. If the bot has moved far enough to warrant it, then you would call your function - or even create a new 'state' for the bot to go into.
#27
03/05/2005 (10:16 am)
Thanks for the reply Mark.

Basically I
#28
03/05/2005 (1:19 pm)
I noticed when dumping the ai player object it has the 'onMove' method, could it do the task?
#29
03/29/2005 (10:05 pm)
Hello all , i am a new user of torque and i guess i am just repeating what all the other post are saying Great Script !!!!!!!!!!

to quote Rom Hartfield "OUTSTANDING!!"



mike g www.lcogsite.com
#30
03/31/2005 (1:37 am)
Hi, this is a great script but at the moment I'm having a problem...
when my bot dies i get this error:

Object 'PatrolPlayer' is not a member of the 'GameBaseData' data block class
IT/server/scripts/AIPlayer.cs (316): Register object failed for object (null) of class AIPlayer.
Set::add: Object "0" doesn't exist
IT/server/scripts/AIPlayer.cs (318): Unable to find object: '0' attempting to call function 'setShapeName'
IT/server/scripts/AIPlayer.cs (319): Unable to find object: '0' attempting to call function 'EquipBot'
IT/server/scripts/AIPlayer.cs (320): Unable to find object: '0' attempting to call function 'setTransform'
IT/server/scripts/AIPlayer.cs (321): Unable to find object: '0' attempting to call function 'followPath'
IT/server/scripts/AIPlayer.cs (335): Unable to find object: '0' attempting to call function 'schedule'

Is this because I've stuffed around with some code somewhere as i get this error when my player dies:

IT/server/scripts/player.cs (811): Unable to find object: '' attempting to call function 'onDeath'

Any help would be appreciated
#31
03/31/2005 (5:41 pm)
I'd suggest going back through the instructions and trying it again.

It looks like there's something screwy in the initial datablock declaration for the object - because it can't seem to create the player object.

If you still can't get it to work then let me know - but it looks like a step got missed somewhere.
#32
03/31/2005 (11:12 pm)
Yeah, I've still got the problem. I kind of fixed the player dieing problem but when the AI dies i still get those errors. Is this supposed to be ran on a certain pack or a licensed copy of torque? I've only got the demo and lighting pack demo :P hehe which im pratically just using content from.
I'm going to buy pretty soon but I want to learn heaps about scripting before I start learning how the C++ engine works.
Thanks for the reply
#33
04/10/2005 (6:30 pm)
Works great! I am getting the same console errors listed above. Actually starts a few lines above with:

starter.fps/server/scripts/game.cs (274): Unable to find object: ' ' attempting to call function 'incScore'

everything else works though, bot fires, causes damage to client, and client can damage bot....I didn't add a respawn dynamic variable, and he hasn't respawned yet, no surprise.

note on the 'name' given to the bot when spawn...I edited any Kork reference to be...say, BadBart, and the engine appended the name with a 1?? No biggie...just wondering and giving feedback on the steps I followed. I am not getting the last error referencing onDamage, I got damage working...I used non curly bracket inside the function and forgot the closing brace...;), D'oh. After that, damage was working...


and found the solution to the respawning issue...and the non GameBaseData error...:)

near line 300:
function AIPlayer::respawn(%this, %name, %obj)
{
   // Create the demo player object

   %player = new AIPlayer() {
   dataBlock = DemoPlayer; // [b]old value= PatrolPlayer[/b], found nowhere else referenced as a datablock
   isbot=true;
   attentionlevel = $AI_PLAYER_MAX_ATTENTION/2;
   fov=$AI_PLAYER_FOV;

   marker = %obj;
   path = %obj.pathname;

   botname = %name;
   };

I think between adding the new Guard class and the first NewAIPlayer[PatrolPlayer], the reference in the linked file didn't get edited if only using the first Resource...works great; now, if I can only get the bots to appear on the Score box and increment their scores...
#34
05/01/2005 (8:55 am)
Ok I'm pretty new at all this Torque stuff but I'm getting stuck with something. When I click on AIMarker, nothing happens. No object gets placed down, the AIMarker word just sits there and glows. When I click other built in things like SpawnShere, they get laid down into the world, but not AIMarker (The octahedron.dts is in the correct spot...)
#35
05/03/2005 (4:22 am)
Hey all. First of all: Thanks a lot for an extremly brilliant resource! This has really kick started the adding of AI functionality to my game.

Now for a question that I have been struggling with:

In my small game, I have implemented a 'Kills Counter' that show how many AI the player has killed. It works fairly ok in the single player setting, but I have a problem regarding multiplayer, where I have a hard time getting a reference to which player actually fired the killing shot. I also have a related problem in that my player gets credited all AI deaths, even when an AI kills another AI.

My code is as follows:

In game.cs I have added the following variable:

$Game::Kills = 0; //(will put this in as an inventory item later to make code cleaner and working for multiplayer. This is only for testing so far)

Then I have added the following function:

function GameConnection::onAIDeath(%this)
{
$Game::Kills += 1;
%this.setKillsAmountHud($Game::Kills); // The KillsAmountHud is added in the players GUI
}

In the aiPlayer.cs I have extended the function

function DemoPlayer::OnDamage(%this, %obj, %delta)

with the lines

if(%obj.getState() $= "Dead")
{
%playerclient = ClientGroup.getobject(0); //hard coded for SP game... very naughty...
%playerclient.onAIDeath();
}

It works fine, but as you may see:

a) My player gets credited all deaths
b) In not having a reference to the shooting player here, I can only update the HUD for one player

What I want, of course, is a reference to the player (or AI) who fired the killing shot. If I could get a hold of that, I could easily disregard any AI killing other AI, and also segregate between players in a future multiplayer option. As a bonus, I also think this would enable chat logging of players killing of AI, something that is not working in the current version.

I am very new to Torque, and I bet the answer is simple, but I can't seem to figure out where DemoPlayer::OnDamage gets called, and whether I can get hold of a reference to the shooting player (sourceobject?) there to extend the function further.

Any help would be appreciated!
#36
06/08/2005 (11:25 pm)
if change my dts player i found this error
starter.fps/server/scripts/aiPlayer.cs (537): Unable to find object: '0' attempting to call function 'getType'
plz help
#37
06/25/2005 (9:54 am)
Mark,

I could not find your EMail address so I will post this here.

I want to thank you for your postings, particularly the CBT set of programs.

I took a slightly different tack since I am creating this for my grandchildren and want a non violent game.

I used CBTBot as a base and created a herd of cattle which are shy of the player and head away when he approaches. They maintain separation from each other as well. Each bot is operates independently of the others.

At the moment, the objective is to round up the cattle and herd them through an obstacle course.

Pretty tame compared to the original CBT game but I've learned a lot about Torque by solving the problems in making the bots respond to the movements of other bots and the player.

Thanks again for the helpful postings.

Norm
#38
01/29/2006 (4:09 pm)
started over with 1.4 torque, this ai only seems to fire at the server player and ignors the lan players, i will look into this more later as i want to check out ai guard
o course we want the ai to fire at every one
#39
02/22/2006 (7:24 am)
Can someone help me out with this...

When I'm in world editor and I click to add AIPlayerMarker nothing appears.

In the console i get
<input> (0): Unable to find function ItemData::create
#40
02/22/2006 (8:58 am)
Don't trouble yourselves. I've figured this out.

Mark, what a great resource!