Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections;
- [RequireComponent(typeof(NavMeshAgent))]
- public class ZombieController : MonoBehaviour {
- NavMeshAgent agent; //Agent component reference
- LookAt lookAt; //lookAt script reference
- MoveToPoint movementController; //Reference to the MoveToPoint script
- ZombieAnimationController animationController; //Reference to the ZombieAnimationController script
- PlayerDetector playerDetector; //Reference to the playerDetector script
- public float maxSpeed; // Maximun speed the character can reach
- float hSpeedSmoothing; //Smoothing factor of the character speed
- private float nextAttackTime; //Time to wait until the character can attack again
- public float timeBetweenAttacks; //Time gap between attacks
- public float alertDistance; //Distance where the character detecs the player
- private float transitionTimer; //random timer for different state transitions
- //FSM
- private int currentState;
- public enum STATES { IDLE, MOVETOPLAYER, WANDER, RANDOMBEHAVIOUR, ATTACK}
- void Start() {
- //Setting up references
- agent = GetComponent<NavMeshAgent>();
- lookAt = GetComponent<LookAt>();
- movementController = GetComponent<MoveToPoint>();
- animationController = GetComponent<ZombieAnimationController>();
- playerDetector = GetComponentInChildren<PlayerDetector>();
- //Character starts in idle state
- agent.speed = 0;
- currentState = (int)STATES.IDLE;
- }
- void Update() {
- // Finite state machine manager
- FSMmanager();
- //Motion animations
- animationController.motionAnimationsHandler(agent.speed, maxSpeed);
- //Look at the next navmesh destination point
- if (lookAt)
- lookAt.lookAtTargetPosition = agent.steeringTarget + transform.forward;
- }
- private void calculateSpeed(float targetSpeed, float acceleration) {
- agent.speed = Mathf.SmoothDamp(agent.speed, targetSpeed, ref hSpeedSmoothing, acceleration);
- }
- private void FSMmanager() {
- switch (currentState) {
- case (int)STATES.IDLE:
- idleState();
- Debug.Log("IDLE");
- break;
- case (int)STATES.MOVETOPLAYER:
- moveToPlayerState();
- Debug.Log("MOVE TO PLAYER");
- break;
- case (int)STATES.WANDER:
- wanderState();
- Debug.Log("WANDER");
- break;
- case (int)STATES.RANDOMBEHAVIOUR:
- randomBehaviourState();
- Debug.Log("RANDOMBEHAVIOUR");
- break;
- case (int)STATES.ATTACK:
- attackState();
- Debug.Log("ATTACK");
- break;
- }
- }
- private void idleState() {
- //Set the idle state target speed
- calculateSpeed(0, 1f);
- //Transition to Move To Player
- if (Vector3.Distance(transform.position, movementController.target.transform.position) < alertDistance) {
- //player is close enough to detect the character
- currentState = (int)STATES.MOVETOPLAYER;
- }
- else {
- if (Time.time > transitionTimer) {
- /* Randomize the transitions, so the character can
- goes to randomBehaviour or to wander state */
- currentState = (Random.Range(0, 100) < 80) ? (int)STATES.WANDER : (int)STATES.RANDOMBEHAVIOUR;
- transitionTimer = Time.time + Random.Range(5, 30);
- }
- }
- }
- private void moveToPlayerState() {
- //Set the character speed to maximum speed
- calculateSpeed(maxSpeed, 5f);
- //Transition to Attack
- if (agent.remainingDistance <= agent.stoppingDistance + agent.radius) {
- //Character is close enough to the target, so attack
- currentState = (int)STATES.ATTACK;
- }
- }
- private void attackState() {
- //Stop the player
- calculateSpeed(0, 1f);
- // If the enemy has waited enough to attack again
- if (Time.time > nextAttackTime && playerDetector.playerInRange && !animationController.anim.GetCurrentAnimatorStateInfo(0).IsTag("attack")) {
- animationController.triggerAttackAnimation();
- // time to wait to the next Attack
- nextAttackTime = Time.time + timeBetweenAttacks;
- }
- //player out of attack range and no attack animation currently playing
- if (agent.remainingDistance >= agent.stoppingDistance + agent.radius && !animationController.anim.GetCurrentAnimatorStateInfo(0).IsTag("attack") && !playerDetector.playerInRange) {
- /* Randomize the transitions, so the character can
- goes to randomBehaviour or to move to Player state */
- currentState = (Random.Range(0, 100) < 70) ? (int)STATES.MOVETOPLAYER : (int)STATES.RANDOMBEHAVIOUR;
- }
- }
- private void wanderState() {
- //Walk speed
- calculateSpeed(2, 0.5f);
- movementController.randomTarget = true;
- //Transition to move to player
- if (Vector3.Distance(transform.position, movementController.target.transform.position) < alertDistance) {
- movementController.randomTarget = false;
- //player is close enough to detect the character
- currentState = (int)STATES.MOVETOPLAYER;
- }
- else {
- if (Time.time > transitionTimer) {
- /* Randomize the transitions, so the character can
- * keep in this state or transit to idle state */
- if (Random.Range(0, 100) < 70) {
- movementController.randomTarget = false;
- currentState = (int)STATES.IDLE;
- }
- transitionTimer = Time.time + Random.Range(5, 30);
- }
- }
- }
- private void randomBehaviourState() {
- //Stop the player
- calculateSpeed(0, 1f);
- animationController.triggerRandomBehaviourAnimation();
- //Transition to Move To Player
- if (Vector3.Distance(transform.position, movementController.target.transform.position) < alertDistance) {
- //player is close enough to detect the character
- currentState = (int)STATES.MOVETOPLAYER;
- }
- // If the animation has finished
- if (!animationController.anim.GetCurrentAnimatorStateInfo(0).IsTag("randomBehaviour")) {
- if (Time.time > transitionTimer) {
- /* Randomize the transitions, so the character can
- * keep in this state or transit to idle state */
- if (Random.Range(0, 100) < 80) {
- currentState = (int)STATES.IDLE;
- }
- transitionTimer = (int)Time.time + Random.Range(5, 30);
- }
- }
- }
- void OnAnimatorMove() {
- // Update position based on animation movement using navigation surface height
- Vector3 position = animationController.anim.rootPosition;
- position.y = agent.nextPosition.y;
- transform.position = position;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement