Previous Blog Next Blog
Prev/Next Blog
by date

Squad Based Movement Explained

Squad Based Movement Explained
Name:Steve YorkshireRifles Acaster
Date Posted:May 02, 2008
Rating:Not Rated
Public:YES
Comments:YES
RSS Feed:GarageGames Blog feedor Subscribe with .
Profile Page:View profile page for Steve YorkshireRifles Acaster

Blog post
As a few people have asked for an explanation of how the squad based AI from my demo works, this is a simplistic overview of the concept. I'm keeping it as simple as possible, in the hope that the most people will understand the concept and be able to modify it to suit their own needs and gameplay style. A lot of my scripts are very much project specific and won't work "out of the box" with other peoples' AI scripts.

The whole basis is for a team of friendly AI to move with the player, as occurs in various FPS games such as Call of Duty, Medal of Honor, Quake4, Rainbow6, etc, etc. This is done by dividing the areas that the player can move through with triggers which will - when entered by the player - give the friendly AI an order to move to a new position. If you have a level which is a linear progression (like the snaking maze in my demo) triggers are fairly easy to layout. The player can go forwards or backwards through the maze (think of this as moving along the X axis of a level). However if you have a large, open level that allows a lot of freedom of player movement, you'll need many more triggers (X and Y axis). I used some 15 different movement triggers in my short, linear demo level.

Positions or goals for the friendly AI to move to are best defined by the location of an object of some kind - that way you call the GetLocation function (or GetTransform) of the object rather than having to work out the XYZ position. I used stock Waypoint Markers.

Now all of this moving back and forth with goals, triggers and AIs can get a little complicated, so I found that it was useful to come up with a system of naming objects which made instant sense to me. For example: Trig1 caused AiPlayer1 to move to WayPointA1 and AiPlayer2 to move to WayPointB1. So AiPlayer1 uses all the WayPointA# and AiPlayer2 uses all the WayPointB# goals. The identifying number (#) of the goals increase with the number of the triggers, so Trig4 leads to WaypointA4 and WayPointB4.



In the end, the actual movement order boils down to the Setmovedestination function. This is of course only good for straight lines, if you want your AI to avoid obstacles you'll need to integrate a pathfinding resource. There are a number of good pathfinding resources avaible from the GG site or you could write your own if know how. I don't understand the technicalities of C++, so I used Gabriel Notman's here.

There are a lot of tests that could be run when an AI receives a movement order from a trigger:
What is the distance to the goal?
Is the AI close enough to be already there?
Is there a clear LOS or will pathfinding be needed to avoid obstacles?
Is there any other factor which may override the trigger to move? (like a man-eating beastie at the goal and the AiPlayer is unarmed - not a good idea to go charging in)
Is the AiPlayer actually alive?

------------------------
Brief Walk Through
------------------------

The player enters Trig1, which sends an order for Ai1 to move to goal A1 and for Ai2 to move to goal B1. First check that only the player is activating this trigger, if you allow any and every AI to fire triggers they'll be a lot of conflicting orders. Using the getClassName is a good way of doing this.

Then check that the AiPlayers actually exist and give them orders using the isObject function. If the AiPlayers do not exist (isObject returns false because it can't find an object of that name) you might want to spawn them now.


function trig1::onTickTrigger(%this,%trigger)
{

Parent::onTickTrigger(%this,%trigger);

for(%x=0; %x < %trigger.getNumObjects(); %x++)
{
%obj = %trigger.getObject(%x);

%checkclass = %obj.getclassname();
if(%checkclass $= "player")
{

if(isObject(AI1))
{
Ai1.setmovedestination(A1.getposition());
//or pathfinding function if you have it integrated
}
else
{
//Script a spawn function
}

//===========================

if(isObject(AI2))
{
Ai2.setmovedestination(B1.getposition());
//or pathfinding function if you have it integrated
}
else
{
//Script a spawn function
}
}
}
}


And that, is the basis of it.
Each trigger has it's own orders for the AiPlayers, following the above example. The player enters Trig2, which sends an order for Ai1 to move to goal A2 and for Ai2 to move to goal B2.

If you are using this style of triggered goals for AiPlayer movement and are making a squad based FPS, it will help to put the WayPoint Markers (or whatever you are using for the goals' locations) in places which you'd expect someone to move to in a battle. Place them near bushes, besides walls, or near objects which provide cover. That way when the player activates the movement triggers the AI will run from cover-to-cover, not simply keep standing out in the open presenting an obvious target.

Another good tactic for placing goals and triggers, is to set some of the AI's goals slightly inside the next trigger. That way the AI will be ahead of the player and it won't look as though the player is constantly leading the charge or that the AI is just following in the player's footsteps all the time. This all helps to give the AI the feeling of being a lot more intelligent than they actually are.

I hope the concept I tried to explain here is clear (cos I did manage to lose myself halfway through!).

To recap:
1. Player moves into trigger.
2. Trigger tells AI which goal to move to.
3. Loop 1.
_____
Steve.

Recent Blog Posts
List:05/02/08 - Squad Based Movement Explained
04/26/08 - Dubious Demo Released
04/03/08 - Cooking AI on Gas
03/13/08 - First Blog: Intro, Plan and Progress

Submit ResourceSubmit your own resources!

Daniel Allessi   (May 02, 2008 at 05:42 GMT)
Fun demo. Very interesting stuff, thanks for sharing!

Mark Dynna   (May 02, 2008 at 14:40 GMT)
Any particular reason you used onTickTrigger rather than onEnterTrigger? From the sound of your description you only want your code to fire when the Player actually enters the trigger, whereas onTickTrigger will be called every X ms (500 by default).

Steve YorkshireRifles Acaster   (May 02, 2008 at 15:28 GMT)
Using OnTickTrigger allows for checks to see if the AiPlayer exists, and then respawn them if they are not alive/in-game. I used a higher tick value than default, about 3000 I think, and also had my AI check to see if they were already at the correct position with DistVector.

Using onEnterTrigger would only issue the move order once, and AI could get killed in the meantime and thus not respawn, leaving the player without company until they moved into a new trigger.

Mark Dynna   (May 02, 2008 at 16:09 GMT)
Ah, I didn't realize you wanted to respawn dead AI. Ok then.

Florian   (May 04, 2008 at 02:36 GMT)
I played the demo, pretty cool.
The thing I liked most was that it felt very good killing enemys.
Also the animations helped in that.
I was fun to play, but some things kinda bothered me, One was the performance. I ran the game on high resolution on 13FPS en a bit lower at 30FPS, pretty low for such a simple game... Normaly I would get let's say 50-70FPS in such a simple scene. So i would advise you to optimise your AI better.
And some times my friends were pretty dumb :p shooting at the enemy, but then my own guys got hit because he ran in front of the bullet xD. Kinda amusing to see, but not really helpfull in the long run.

(Btw, add some recoil to your weapons!)

You must be a member and be logged in to either append comments or rate this resource.