- Home /
AI converging on a target - Obstacle avoidance or pathfinding?
Gday all,
=== BACKGROUND ===
I am working on a fairly simple game; one of the core mechanics involves independent AI battles; currently this is functional however I am not using pathfinding. In the interest of keeping it simple the AI move directly to the target. The movement is done via a character controller (SimpleMove) and my own scripts for assigning waypoints, determining movement etc. (This is tied in to the AI decision cycle I have currently)
This is a top down game and will not have any real obstacles so I havent had the need for specific pathfinding as yet... The problem I have encountered though is if there are two groups of enemies converging, the front rows will fight each other with enemies to the rear just running into the back of the front row (until one dies then the gap is filled by one from behind).
=== GOAL ===
What I would like is when AI is not in the front rank to move around the outside until they can get to the enemy.
=== PLAN ===
My basic plan for how to fix this is run a test on the current combat target to see if there is room in melee range (eg. if raycasts to front, left, right and rear out to 3m all hit something then switch targets) and add in a basic obstacle avoidance mechanism... this is the main issue I am working on now.
The basic obstacle avoidance plan (fairly standard I believe) is to cast a ray directly towards the target -- if there is 3m clear in front of the AI then head directly to target. If not, cast one 3m to left -- if it is clear there is a temporary waypoint made at that position and the AI moves there (if it is blocked left, cast right, if blocked right, cast rear, if blocked rear, remain idle for 1.5 seconds)
The temporary waypoint was to prevent jittering in the movement (ie. alternating between moving 10cm towards the target then 10cm to the left etc)
=== QUESTION ===
What is the best way to achieve this behavior? I have looked at some pathfinding and it all seems a bit overcomplicated just to achieve what I am after (I will admit I have not looked into pathfinding theory too much however I understand the BASICS...). Is there a simple method out there to achieve this behavior? An already existing basic obstacle avoidance script/method or should I go down the route of getting a basic easy to implement pathfinding setup?
Assistance/guidance much appreciated!!!
I am trying to achieve this using only free assets too; Simple Path looks ok, as does the A* project (http://arongranberg.com/astar/download - although free version doesnt have local avoidance)
Answer by MickM · Feb 09, 2013 at 01:52 PM
Victory! Far from the most elegant solution I am sure however I have added the below avoidance function and now all AI has a rudimentary obstacle avoidance which works quite well for surrounding enemies in combat!!
BasicMove(); is the function I call to do movement (checks distance, plays animation, moves character etc)
function SetupMove(){
var hit : RaycastHit;
var rayLengthToCast = 0.5f;
var p1 : Vector3 = transform.position + selfController.center + Vector3.up * (-selfController.height*0.3);
var p2 : Vector3 = p1 + Vector3.up * selfController.height;
Debug.DrawRay(transform.position+Vector3.up, transform.forward, Color.yellow);
if (checkPath){ //This imposes a delay that the raycast check is used (framerate killer!!!)
ResetCheckPath(); //See function below
if (Physics.CapsuleCast(p1, p2, selfController.radius, transform.forward, rayLengthToCast)){
Debug.Log("HIT Forward");
clearMove = false; //Trigger to apply lateral movement
if (Physics.Raycast(transform.position, currentMoveMod*transform.right, hit, rayLengthToCast)){
Debug.Log("HIT "+ currentMoveMod);
currentMoveMod = currentMoveMod * -1; //Alternates between left and right
}else {
}
}else {
clearMove = true;
}
}
if (!clearMove){ //If we are blocked forward
selfController.SimpleMove(transform.right*currentMoveMod); //Move left or right based on the movemod (from above)
}
BasicMove(); //Do basic forward move
}
function ResetCheckPath(){
checkPath = false;
yield WaitForSeconds (pathSnooze);
checkPath = true;
}
Needed to add the reset check path because when running every frame with 50+ AI it was causing noticeable lag! The 'pathSnooze' variable is 0.5 + random between 0 and 0.5 because when all AI were calculating in the same frame it was still noticeable!
It is far from 100% perfect but it really works well for what I need to achieve; hopefully this basic idea can help others!!! Also looked at adding a collider front, left and right as triggers instead of capsule casting however this came together easier so it is the one I am rolling with!!
Another trick to avoid the "all check at once" lag is to keep pathSnooze constant, but throw the checks out-of-synch: in Start, each monster waits random 0-pathSnooze before setting checkPath true.
You might still get some pacing back and forth. Can remember who was blocking you. If it is still blocking you next frame, don't flip cur$$anonymous$$ove$$anonymous$$od (you are still trying to walk around the same obstacle.)