codesamples >> projectdemon enemycontroller class

Project Demon: EnemyController

Project:

ProjectDemon

Engine:

Unity

Code language:

C#

Class description:

The enemycontroller class handles the actions of the AI. If the player comes in the FOV of the enemy the pathfinding of the AI is enabled and he will navigate towards the player.

EnemyController.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

// The various states of an Enemy
public enum EnemyStates
{
	Idle,
	Patrolling,
	Alerted,
	Pursuing,
	Dead
}

public class EnemyController : MonoBehaviour 
{
	// The target the AI is looking at in Idle state
	public Vector3 TargetPosition;
	
	// The speed of the AI
	public float MovementSpeed = 18.5f; 
	
	// The speed of the AI when Patrolling
	public float PatrollingSpeed = 12.0f;
	
	// The distance the AI can detect the player
	public float ViewingDistance = 10.0f;
	
	// The Fov angle of the AI
	public float FovAngle = 120.0f;
	
	// The state the AI is currently in
	public EnemyStates CurrentState = EnemyStates.Idle;	
	
	// The patrollocation of the AI
	private int _currentPatrolLocation = 0;
	private bool _isPatrolReturning = false;
	public List<Transform> PatrolLocations = new List<Transform>();

	// Use this for initialization
	void Start () 
	{
	}
	
	// Update is called once per frame
	void Update () 
	{
		// Determines the State of the AI
		DetermineState();
		
		// Handles the execution of the AI's actions based on it's State
		HandleState();

		// (Debug) Draw the frontal vector of the AI
		DebugDrawFrontalViewVector();

		// (Debug) Draw the side vectors of the AI indicating his FOV
		DebugDrawSideViewVectors();
	}
	
	// Calculates the distance between the AI and the Player
	private Vector3 CalculatePlayerDistance()
	{
		// Calculate the position of the Player to the AI
		Vector3 playerDistance = GetPlayerPosition() - transform.position;
		return playerDistance;
	}
	
	// Calculates the angle between the AI and the Player
	private float CalculatePlayerAngle()
	{
		// Calculate & normalize the target position of the AI
		Vector3 targetVector = TargetPosition - transform.position;
		targetVector.Normalize();
		
		// Calculate & normalize the position of the AI to the Player
		Vector3 playerDistance = CalculatePlayerDistance();
		playerDistance.Normalize();

		// Calculate the Angle between the AI and the Player
		float dotProduct = Vector3.Dot(targetVector, playerDistance);
		float radiansAngle = Mathf.Acos(dotProduct);
		
		// Convert the angle from Radians to Degrees
		float degreesAngle = radiansAngle * Mathf.Rad2Deg;
		return degreesAngle;
	}
	
	// (Debug) Draw the frontal vector of the AI
	private void DebugDrawFrontalViewVector()
	{
		Vector3 targetVector = TargetPosition - transform.position;
		targetVector.Normalize();
		targetVector *= ViewingDistance;
		Debug.DrawRay(transform.position, targetVector, Color.red);
	}
	
	// (Debug) Draw the side vectors of the AI indicating his FOV
	private void DebugDrawSideViewVectors()
	{
		Vector3 targetVector = TargetPosition - transform.position;
		
		Vector3 rotateTarget1 = targetVector;
		Vector3 rotateTarget2 = targetVector;
		
		Quaternion quaternion1 = Quaternion.AngleAxis(FovAngle/2,Vector3.up);
		Quaternion quaternion2 = Quaternion.AngleAxis(-FovAngle/2,Vector3.up);
		
		rotateTarget1 = quaternion1 * rotateTarget1;
		rotateTarget2 = quaternion2 * rotateTarget2;
		
		Debug.DrawRay(transform.position, rotateTarget1, Color.blue);
		Debug.DrawRay(transform.position, rotateTarget2, Color.blue);
	}
	
	// Determines the state the AI should be in
	private void DetermineState()
	{
		switch(CurrentState)
		{
		case(EnemyStates.Idle):
			// If the Player is in Line of Sight of the AI (cast a Ray to check if 
			// the AI can see the player)
			if(CalculatePlayerDistance().magnitude < ViewingDistance && 
			CalculatePlayerAngle() < FovAngle/2)
			{
				CurrentState = EnemyStates.Pursuing;
			}
			break;
			
		case(EnemyStates.Patrolling):
			break;
			
		case(EnemyStates.Alerted):
			break;
			
		case(EnemyStates.Pursuing):
			break;
			
		case(EnemyStates.Dead):
			break;
		}
	}
	
	// Handles the actions of the state the AI is currently in
	private void HandleState()
	{
		switch(CurrentState)
		{
		case(EnemyStates.Idle):
			// Look at the original guarding position
			LookAtTargetPosition();
			break;
			
		case(EnemyStates.Patrolling):
			// Patrol between the various PatrolPoints
			PatrolPath();
			break;
			
		case(EnemyStates.Alerted):
			// Go to the place that alerted the AI
			break;
			
		case(EnemyStates.Pursuing):
			// Look at the movement direction
			LookAtMovementDirection();
			
			// Move the Character
			MoveCharacter();
			break;
			
		case(EnemyStates.Dead):
			// Enemy is Dead
			break;
		}
	}
	
	// Makes the AI look at it's original TargetPosition
	private void LookAtTargetPosition()
	{
		transform.LookAt(TargetPosition, new Vector3(0, 1, 0));
	}
	
	// Makes the AI look at the position where it's going
	private void LookAtMovementDirection()
	{
		Vector3 lookTarget = GetComponent<NavMeshAgent>().nextPosition;

		// Lookat the next node in the NavigationPath
		transform.LookAt(lookTarget, new Vector3(0, 1, 0));
	}
	
	// Returns the position of the Player
	private Vector3 GetPlayerPosition()
	{
		return GameObject.Find("Player").transform.position;
	}
	
	// Makes the AI move towards the Player using NavigationPathfinding
	private void MoveCharacter()
	{
		GetComponent<NavMeshAgent>().destination = GetPlayerPosition();
		GetComponent<NavMeshAgent>().speed = MovementSpeed;
	}
	
	// Makes the AI patrol it's set PatrolPath
	private void PatrolPath()
	{
		Debug.Log((PatrolLocations[_currentPatrolLocation].position - transform.position).magnitude);
		GetComponent<NavMeshAgent>().destination = PatrolLocations[_currentPatrolLocation].position;
		GetComponent<NavMeshAgent>().speed = PatrollingSpeed;
		
		if((PatrolLocations[_currentPatrolLocation].position - transform.position).magnitude <= 1.5f)
		{
			Debug.Log("Patrol node:" + _currentPatrolLocation + "/" + PatrolLocations.Count);
			
			if(_currentPatrolLocation == PatrolLocations.Count - 1)
			{
				_isPatrolReturning = true;
				Debug.Log("Returning!");
			}
			else if(_currentPatrolLocation == 0)
			{
				_isPatrolReturning = false;
				Debug.Log("Advancing!");
			}
			
			if(!_isPatrolReturning)
			{
				++_currentPatrolLocation;
				Debug.Log("Increased Path index");
			}
			else
			{
				--_currentPatrolLocation;
				Debug.Log("Decreased Path index");
			}
		}
	}
}

EnemyTrigger.cs

using UnityEngine;
using System.Collections;

public class EnemyMeleeTrigger : MonoBehaviour 
{
	float AttackTimer = 0.05f;
	
	// Use this for initialization
	void Start () 
	{
	
	}
	
	// Update is called once per frame
	void Update () 
	{
	
	}
	
	void OnTriggerStay(Collider other) 
	{
        if (other.gameObject.name == "Player")
		{	
			Debug.Log(other.gameObject.name);
			AttackTimer -= Time.deltaTime;
			
			if(AttackTimer < 0.0f)
			{
				Destroy(other.gameObject);
			}
		}
    }
}