179 lines
4.7 KiB
C#
179 lines
4.7 KiB
C#
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
|
|
[RequireComponent(typeof(Animator))]
|
|
public class EnemyAnimationController : MonoBehaviour
|
|
{
|
|
[Header("State Names")]
|
|
public string idleState = "monster_idle_1";
|
|
public string walkState = "monster_Walking";
|
|
public string runState = "monster_Run";
|
|
public string walkBackState = "monster_Walk_Back";
|
|
public string[] attackStates = { "monster_attack_1", "monster_attack_2", "monster_attack_3" };
|
|
public string[] hitStates = { "monster_hit_1", "monster_hit_2" };
|
|
public string angerState = "monster_anger";
|
|
public string deathState = "monster_Death";
|
|
|
|
[Header("Locomotion")]
|
|
public int layerIndex = 0;
|
|
public float walkSpeed = 0.15f;
|
|
public float runSpeed = 2.0f;
|
|
public float crossFade = 0.08f;
|
|
|
|
[Header("Stability")]
|
|
public float walkToIdleDown = 0.08f;
|
|
public float runToWalkDown = 1.7f;
|
|
public float speedSmoothTime = 0.1f;
|
|
|
|
|
|
public float minActionLock = 0.15f;
|
|
|
|
Animator anim;
|
|
NavMeshAgent agent; CharacterController cc; Rigidbody rb;
|
|
|
|
string currentState = "";
|
|
float smoothedSpeed, speedVel;
|
|
|
|
bool inAction;
|
|
float actionUnlockTime;
|
|
string actionState;
|
|
|
|
void Awake()
|
|
{
|
|
anim = GetComponent<Animator>();
|
|
agent =transform.parent.GetComponent<NavMeshAgent>();
|
|
cc = transform.parent.GetComponent<CharacterController>();
|
|
rb = transform.parent.GetComponent<Rigidbody>();
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
|
|
if (inAction) TryAutoUnlockFromAction();
|
|
|
|
UpdateLocomotion();
|
|
}
|
|
|
|
void UpdateLocomotion()
|
|
{
|
|
if (inAction) return;
|
|
|
|
float rawSpeed = GetHorizSpeed();
|
|
smoothedSpeed = Mathf.SmoothDamp(smoothedSpeed, rawSpeed, ref speedVel, speedSmoothTime);
|
|
|
|
string target = string.IsNullOrEmpty(currentState) ? idleState : currentState;
|
|
|
|
if (currentState == idleState || string.IsNullOrEmpty(currentState))
|
|
{
|
|
if (smoothedSpeed > walkSpeed) target = walkState;
|
|
else target = idleState;
|
|
}
|
|
else if (currentState == walkState)
|
|
{
|
|
if (smoothedSpeed > runSpeed) target = runState;
|
|
else if (smoothedSpeed < walkToIdleDown) target = idleState;
|
|
}
|
|
else if (currentState == runState)
|
|
{
|
|
if (smoothedSpeed < runToWalkDown) target = walkState;
|
|
}
|
|
else
|
|
{
|
|
|
|
if (smoothedSpeed <= walkToIdleDown) target = idleState;
|
|
}
|
|
|
|
if (target != currentState && !anim.IsInTransition(layerIndex))
|
|
{
|
|
anim.CrossFade(target, crossFade, layerIndex);
|
|
currentState = target;
|
|
}
|
|
}
|
|
|
|
float GetHorizSpeed()
|
|
{
|
|
if (agent) return agent.velocity.magnitude;
|
|
if (cc) return cc.velocity.magnitude;
|
|
if (rb) return new Vector3(rb.velocity.x, 0f, rb.velocity.z).magnitude;
|
|
return 0f;
|
|
}
|
|
|
|
|
|
|
|
void BeginAction(string stateName)
|
|
{
|
|
if (!anim.IsInTransition(layerIndex))
|
|
{
|
|
anim.CrossFade(stateName, crossFade, layerIndex);
|
|
currentState = stateName;
|
|
inAction = true;
|
|
actionState = stateName;
|
|
actionUnlockTime = Time.time + minActionLock;
|
|
}
|
|
}
|
|
|
|
void TryAutoUnlockFromAction()
|
|
{
|
|
if (Time.time < actionUnlockTime) return;
|
|
|
|
var info = anim.GetCurrentAnimatorStateInfo(layerIndex);
|
|
|
|
if (!info.IsName(actionState))
|
|
{
|
|
inAction = false;
|
|
currentState = "";
|
|
return;
|
|
}
|
|
|
|
|
|
if (!info.loop && info.normalizedTime >= 0.99f && !anim.IsInTransition(layerIndex))
|
|
{
|
|
inAction = false;
|
|
currentState = "";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void PlayAttack(int index = -1)
|
|
{
|
|
if (attackStates == null || attackStates.Length == 0) return;
|
|
if (index < 0) index = Random.Range(0, attackStates.Length);
|
|
index = Mathf.Clamp(index, 0, attackStates.Length - 1);
|
|
BeginAction(attackStates[index]);
|
|
}
|
|
|
|
public void PlayHit()
|
|
{
|
|
if (hitStates == null || hitStates.Length == 0) return;
|
|
BeginAction(hitStates[Random.Range(0, hitStates.Length)]);
|
|
}
|
|
|
|
public void PlayAnger()
|
|
{
|
|
if (!string.IsNullOrEmpty(angerState))
|
|
BeginAction(angerState);
|
|
}
|
|
|
|
public void PlayWalkBack(bool enable)
|
|
{
|
|
if (enable && !string.IsNullOrEmpty(walkBackState))
|
|
{
|
|
BeginAction(walkBackState);
|
|
}
|
|
}
|
|
|
|
public void PlayDeath()
|
|
{
|
|
if (!string.IsNullOrEmpty(deathState))
|
|
BeginAction(deathState);
|
|
}
|
|
|
|
|
|
public void OnActionFinished()
|
|
{
|
|
inAction = false;
|
|
currentState = "";
|
|
}
|
|
}
|