Stuck with AI

Hi Guys,

I have a problem with my simple AI script. My AI NPC’s sometimes get stuck between objects and i’m looking for a way to know when they get stuck, back them up a little and then randomly choose a direction (other than the way it was moving) and move on.

my code so far:

private var direction : int;		//Sets direction of NPC
private var speed = 10;				//Sets speed of NPC

function Awake()
{
	direction = Random.Range(0, 3);
}

function Update () {

	switch(direction)
	{
		case 0: gameObject.transform.position += gameObject.transform.forward * Time.deltaTime * speed;	
				stuck();
				break;
				
		case 1: gameObject.transform.position -= gameObject.transform.forward * Time.deltaTime * speed;	
				stuck();
				break;
		
		case 2: gameObject.transform.position += gameObject.transform.right * Time.deltaTime * speed;	
				stuck();
				break;
				
		case 3: gameObject.transform.position -= gameObject.transform.right * Time.deltaTime * speed;	
				stuck();
				break;
	}

}

function OnCollisionEnter(col : Collision)
{
	if(col.gameObject.tag == "Building")
	{
		setDirection();
	}
	
}

function setDirection()
{
	var way = Random.Range(0 ,3);
	Debug.Log(way);
	if(direction != way)
	{
		direction = way;
	}
	else
	{
		setDirection();
	}
}

function stuck()
{
	
}

As you noticed the stuck function checks if the NPC gets stuck. But i currently have no idea how to do this.

Idea: put some traces in front, and both sides, and if they ALL are touching anything, have the NPC rotate 180. If that works, you can get more complicated checking you surroundings.

you remember the last position (every 1-2 seconds) and if your npc is considered to move and the distance to the last position is smaller than a treshold its probably stuck.

even easier… put a check in to see if the character has moved more than 2 units in the past 5 seconds… if it did not, then it is stuck.

var lastPosition : Vector3;
var timeCheck : float = Time.time;

function stuck(){
	if(!lastPosition) lastPosition = transform.position;
	if((transform.position - lastPosition) > 2.0){
		timeCheck = Time.time;
		lastPosition = transform.position;
	}
	if(Time.time - timeCheck > 5.0){
		// we are stuck so lets move.
		// reset code here:
		
		
		timeCheck = Time.time;
		lastPosition = transform.position;
	}
}

Ways to prevent the NPC from getting stuck:

You can use a bigger collider for the NPC, so when the collider triggers a collision, you change the NPC’s movement to 90 degrees or something like that.

I think you can also use a sphere raycasting, with pretty much the same effect. You’d have to use layers for the ground and other NPC’s though.

Ways to get unstuck:

Check to see if we have traveled the distance we should have traveled in the direction we were headed in the last 1 or 2 seconds. If not, then a 90 to a 270 degree turn would work best, imo.

You could implement this by caching the position every 2 seconds, for example, and then comparing if the distance traveled in the last 2 seconds was smaller that what it should have been.

Hi,

I used your code but i get an error on:
if((transform.position - lastPosition) > 2.0)

error:
Operator ‘>’ cannot be used with a left hand side of type ‘UnityEngine.Vector3’ and a right hand side of type ‘float’

Does that mean i have to change the 2.0 in a vector3 ?

I also forgot the mention that this script is gonna be used on more than a hundred NPC’s moving through my city.

Don’t do 2 in a Vector3, just make (transform.position-lastPosition).magnitude that’ll convert it into a float

Hmm that doesn’t seem to work error i get now:

Statement: if((transform.position - lastPosition).magnitude() > 2.0)

Error:
It’s not possible to invoke an expression of type ‘float’

.magnitude

not

.magnitude()

thx for the help, the script seems to be working!