Enemy AI Problem: Dancing?

Edit: The actual movement of the enemy has now been fixed with this script update. Now, the buggy, dance-like rotation needs to be fixed. Suggestions?

I have created an “AI” script for a third person game that is somewhat functional, but is buggy. I want the enemy to rotate to “look” at the player, go up to the player when the player has come within a certain distance, and attack the player at a certain distance. The enemy rotates properly at a distance, but moves crazily when closer. The movement is like a quick, erotic, jumpy dance that circles the player… It looks cool, but it isn’t what I want.

Here is the AI script:

//    #pragma strict

// Set variables related to movement and individual states.

var idleTime : float = 3.1;
var marManMoveSpeed : float;
var marManRotateSpeed : float;
var gravity : float;
var attackTarget : Transform;
var chaseDistance : float;
var attackDistance : float;
private var moveDirection : Vector3 = Vector3.zero;
private var wait : boolean = false;

// Set variables for the states.
private var idle : int = 0;
private var walk : int = 1;
private var attack : int = 2;
private var status : int = idle;
var controller : CharacterController;
controller = GetComponent(CharacterController);


function Update(){
	var controller : CharacterController = GetComponent(CharacterController);
    moveDirection.x = 0;
    moveDirection.z = 0;

    var aggro : float = Vector3.Distance(attackTarget.position,transform.position);	
	//print(aggro);	
	//Define what causes the states.

	if (aggro < chaseDistance && aggro > attackDistance){
		status = walk;
	}

	else if(aggro < attackDistance * 0.8){
		status = attack;
	}

	else if(aggro > chaseDistance){

		status = idle;

	}	
    
	
	
	//State what to do in each of the states.	
	if (controller.isGrounded){
		switch(status){
			case idle:
				//Currently does nothing, but will hopefully have animation here.
				break;

			case walk:
				//Insert animation later.
				//Rotation handled later in script.				
				//Set the direction for movement.
				moveDirection = Vector3(attackTarget.position.x - transform.position.x,0,attackTarget.position.z - transform.position.z);
                            moveDirection.Normalize();
				break;
			case attack:
				//Insert "attack" animation later. Required for end use.
				//Rotation handled later in script.
				break;

			default:
				return;
		}

	}

    //Always apply gravity.	
	moveDirection[1] -= gravity * Time.deltaTime;
    
    Move();
}


    function Move(){
    	if(!wait){
    		//Handle all movement in here.
    		transform.LookAt(attackTarget);
    		controller.Move(moveDirection * marManMoveSpeed * Time.deltaTime);
	}

	else{
	//Wait for assigned time and do nothing!
	Debug.LogWarning("Current status - waiting for "+idleTime);
    	yield WaitForSeconds(idleTime);
    	return;
    	}
    }
    @script RequireComponent(CharacterController)

Here are the settings for this script in the inspector:

Idle Time = 3.1
Mar Man Move Speed = 5.291004
Mar Man Rotate Speed = 360
Gravity = 50
Attack Target = Player (Transform)
Chase Distance = 5
Attack Distance = 1.75
Controller = Enemy (Character Controller)

Your enemy is still moving when it gets within attack range. Sure, you only set moveDirection when you’re walking, but you call Move() every frame. So, when you’re close, you use the old value of moveDirection, which skitters you a little off to one side.

I’d prefer to split into Move and Turn. Or you could have attack zero-out moveDirection x and z.

attackDistance seems pretty small. The measurement is center-to-center, and 0.25 is 10 inches (25 centimeters.) Two standard Unity cubes (for example) are touching when they are 1 unit apart. But if you really are scaled that small (radius 0.08 colliders,) then 0.25 for attackDistance is fine.

When you compute moveDirection you should probably normalize it. Right now, your speed is based on distance – you move faster the further you are away. If you raised chase distance to 15, you’d see the enemy blast towards you at triple speed, then slow down.

Another trick is to walk until you are at maybe 80% of attack range, but don’t go from attack back to walk until you’re out of range. That way the player can shift a little and you won’t make unrealistic tiny steps to keep up.