364 lines
13 KiB
C#
364 lines
13 KiB
C#
|
|
using UnityEngine;
|
|
|
|
namespace Invector.vCharacterController
|
|
{
|
|
using System.Collections;
|
|
using vEventSystems;
|
|
public class vThirdPersonAnimator : vThirdPersonMotor
|
|
{
|
|
#region Variables
|
|
|
|
[HideInInspector]
|
|
public Transform matchTarget;
|
|
|
|
private float randomIdleCount;
|
|
public const float walkSpeed = 0.5f;
|
|
public const float runningSpeed = 1f;
|
|
public const float sprintSpeed = 1.5f;
|
|
private bool triggerDieBehaviour;
|
|
public Vector3 lastCharacterPosition { get; protected set; }
|
|
|
|
#endregion
|
|
|
|
#if UNITY_EDITOR
|
|
[ContextMenu("Enable AnimatorStateInfos Debug")]
|
|
void EnableAnimatorStateInfosDebug()
|
|
{
|
|
if (animatorStateInfos != null)
|
|
{
|
|
animatorStateInfos.debug = true;
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Disable AnimatorStateInfos Debug")]
|
|
void DisableAnimatorStateInfosDebug()
|
|
{
|
|
if (animatorStateInfos != null)
|
|
{
|
|
animatorStateInfos.debug = false;
|
|
}
|
|
}
|
|
#endif
|
|
protected override void Start()
|
|
{
|
|
base.Start();
|
|
RegisterAnimatorStateInfos();
|
|
}
|
|
|
|
protected virtual void RegisterAnimatorStateInfos()
|
|
{
|
|
animatorStateInfos = new vAnimatorStateInfos(GetComponent<Animator>());
|
|
animatorStateInfos.RegisterListener();
|
|
}
|
|
|
|
protected virtual void OnEnable()
|
|
{
|
|
if (animatorStateInfos.animator != null)
|
|
{
|
|
animatorStateInfos.RegisterListener();
|
|
}
|
|
}
|
|
|
|
protected virtual void OnDisable()
|
|
{
|
|
|
|
animatorStateInfos.RemoveListener();
|
|
}
|
|
|
|
public virtual void UpdateAnimator()
|
|
{
|
|
if (animator == null || !animator.enabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AnimatorLayerControl();
|
|
ActionsControl();
|
|
|
|
TriggerRandomIdle();
|
|
|
|
UpdateAnimatorParameters();
|
|
DeadAnimation();
|
|
}
|
|
|
|
public virtual void AnimatorLayerControl()
|
|
{
|
|
baseLayerInfo = animator.GetCurrentAnimatorStateInfo(baseLayer);
|
|
underBodyInfo = animator.GetCurrentAnimatorStateInfo(underBodyLayer);
|
|
rightArmInfo = animator.GetCurrentAnimatorStateInfo(rightArmLayer);
|
|
leftArmInfo = animator.GetCurrentAnimatorStateInfo(leftArmLayer);
|
|
upperBodyInfo = animator.GetCurrentAnimatorStateInfo(upperBodyLayer);
|
|
fullBodyInfo = animator.GetCurrentAnimatorStateInfo(fullbodyLayer);
|
|
}
|
|
|
|
public virtual void ActionsControl()
|
|
{
|
|
// to have better control of your actions, you can assign bools to know if an animation is playing or not
|
|
// this way you can use this bool to create custom behavior for the controller
|
|
|
|
// identify if the rolling animations is playing
|
|
isRolling = IsAnimatorTag("IsRolling");
|
|
// identify if a turn on spot animation is playing
|
|
isTurningOnSpot = IsAnimatorTag("TurnOnSpot");
|
|
// locks player movement while a animation with tag 'LockMovement' is playing
|
|
lockAnimMovement = IsAnimatorTag("LockMovement");
|
|
// locks player rotation while a animation with tag 'LockRotation' is playing
|
|
lockAnimRotation = IsAnimatorTag("LockRotation");
|
|
// ! -- you can add the Tag "CustomAction" into a AnimatonState and the character will not perform any Melee action -- !
|
|
customAction = IsAnimatorTag("CustomAction");
|
|
// identify if the controller is airborne
|
|
isInAirborne = IsAnimatorTag("Airborne");
|
|
}
|
|
|
|
public virtual void UpdateAnimatorParameters()
|
|
{
|
|
if (disableAnimations)
|
|
{
|
|
return;
|
|
}
|
|
|
|
animator.SetBool(vAnimatorParameters.IsStrafing, isStrafing);
|
|
animator.SetBool(vAnimatorParameters.IsSprinting, isSprinting);
|
|
animator.SetBool(vAnimatorParameters.IsSliding, isSliding && !isRolling);
|
|
animator.SetBool(vAnimatorParameters.IsCrouching, isCrouching);
|
|
animator.SetBool(vAnimatorParameters.IsGrounded, isGrounded);
|
|
animator.SetBool(vAnimatorParameters.IsDead, isDead);
|
|
animator.SetFloat(vAnimatorParameters.GroundDistance, groundDistance);
|
|
animator.SetFloat(vAnimatorParameters.GroundAngle, GroundAngleFromDirection());
|
|
|
|
if (!isGrounded)
|
|
{
|
|
animator.SetFloat(vAnimatorParameters.VerticalVelocity, verticalVelocity);
|
|
}
|
|
|
|
//if (!lockAnimMovement)
|
|
{
|
|
if (isStrafing)
|
|
{
|
|
animator.SetFloat(vAnimatorParameters.InputHorizontal, horizontalSpeed, strafeSpeed.animationSmooth, Time.fixedDeltaTime);
|
|
animator.SetFloat(vAnimatorParameters.InputVertical, verticalSpeed, strafeSpeed.animationSmooth, Time.fixedDeltaTime);
|
|
}
|
|
else
|
|
{
|
|
animator.SetFloat(vAnimatorParameters.InputVertical, verticalSpeed, freeSpeed.animationSmooth, Time.fixedDeltaTime);
|
|
animator.SetFloat(vAnimatorParameters.InputHorizontal, 0, freeSpeed.animationSmooth, Time.fixedDeltaTime);
|
|
}
|
|
|
|
animator.SetFloat(vAnimatorParameters.InputMagnitude, Mathf.LerpUnclamped(inputMagnitude, 0f, stopMoveWeight), isStrafing ? strafeSpeed.animationSmooth : freeSpeed.animationSmooth, Time.fixedDeltaTime);
|
|
|
|
if (useLeanMovementAnim && inputMagnitude >= 0.1f)
|
|
{
|
|
animator.SetFloat(vAnimatorParameters.RotationMagnitude, rotationMagnitude, leanSmooth, Time.fixedDeltaTime);
|
|
}
|
|
else if (useTurnOnSpotAnim && inputMagnitude < 0.1f)
|
|
{
|
|
animator.SetFloat(vAnimatorParameters.RotationMagnitude, (float)System.Math.Round(rotationMagnitude, 2), rotationMagnitude == 0 ? 0.1f : 0.01f, Time.fixedDeltaTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void SetAnimatorMoveSpeed(vMovementSpeed speed)
|
|
{
|
|
Vector3 relativeInput = transform.InverseTransformDirection(moveDirection);
|
|
verticalSpeed = relativeInput.z;
|
|
horizontalSpeed = relativeInput.x;
|
|
|
|
var newInput = new Vector2(verticalSpeed, horizontalSpeed);
|
|
|
|
if (speed.walkByDefault || alwaysWalkByDefault)
|
|
{
|
|
inputMagnitude = Mathf.Clamp(newInput.magnitude, 0, isSprinting ? runningSpeed : walkSpeed);
|
|
}
|
|
else
|
|
{
|
|
var mag = newInput.magnitude;
|
|
sprintWeight = Mathf.Lerp(sprintWeight, isSprinting ? 1f : 0f, (isStrafing ? strafeSpeed.movementSmooth : freeSpeed.movementSmooth) * Time.fixedDeltaTime);
|
|
inputMagnitude = Mathf.Clamp(Mathf.Lerp(mag, mag + 0.5f, sprintWeight), 0, isSprinting ? sprintSpeed : runningSpeed);
|
|
}
|
|
}
|
|
|
|
public virtual void ResetInputAnimatorParameters()
|
|
{
|
|
animator.SetBool(vAnimatorParameters.IsSprinting, false);
|
|
animator.SetBool(vAnimatorParameters.IsSliding, false);
|
|
animator.SetBool(vAnimatorParameters.IsCrouching, false);
|
|
animator.SetBool(vAnimatorParameters.IsGrounded, true);
|
|
animator.SetFloat(vAnimatorParameters.GroundDistance, 0f);
|
|
animator.SetFloat("InputHorizontal", 0);
|
|
animator.SetFloat("InputVertical", 0);
|
|
animator.SetFloat("InputMagnitude", 0);
|
|
}
|
|
|
|
protected virtual void TriggerRandomIdle()
|
|
{
|
|
if (input != Vector3.zero || customAction)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (randomIdleTime > 0)
|
|
{
|
|
if (input.sqrMagnitude == 0 && !isCrouching && _capsuleCollider.enabled && isGrounded)
|
|
{
|
|
randomIdleCount += Time.fixedDeltaTime;
|
|
if (randomIdleCount > 6)
|
|
{
|
|
randomIdleCount = 0;
|
|
animator.SetTrigger(vAnimatorParameters.IdleRandomTrigger);
|
|
animator.SetInteger(vAnimatorParameters.IdleRandom, Random.Range(1, 4));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
randomIdleCount = 0;
|
|
animator.SetInteger(vAnimatorParameters.IdleRandom, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void DeadAnimation()
|
|
{
|
|
if (!isDead)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!triggerDieBehaviour)
|
|
{
|
|
triggerDieBehaviour = true;
|
|
DeathBehaviour();
|
|
}
|
|
|
|
// death by animation
|
|
if (deathBy == DeathBy.Animation)
|
|
{
|
|
int deadLayer = 0;
|
|
|
|
var info = animatorStateInfos.GetStateInfoUsingTag("Dead");
|
|
if (info != null)
|
|
{
|
|
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.99f && groundDistance <= 0.15f)
|
|
{
|
|
RemoveComponents();
|
|
}
|
|
|
|
}
|
|
}
|
|
// death by animation & ragdoll after a time
|
|
else if (deathBy == DeathBy.AnimationWithRagdoll)
|
|
{
|
|
int deadLayer = 0;
|
|
var info = animatorStateInfos.GetStateInfoUsingTag("Dead");
|
|
if (info != null)
|
|
{
|
|
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.8f)
|
|
{
|
|
onActiveRagdoll.Invoke(null);
|
|
}
|
|
}
|
|
}
|
|
// death by ragdoll
|
|
else if (deathBy == DeathBy.Ragdoll)
|
|
{
|
|
onActiveRagdoll.Invoke(null);
|
|
}
|
|
}
|
|
|
|
#region Generic Animations Methods
|
|
|
|
public virtual void SetActionState(int value)
|
|
{
|
|
animator.SetInteger(vAnimatorParameters.ActionState, value);
|
|
}
|
|
|
|
public virtual bool IsAnimatorTag(string tag)
|
|
{
|
|
if (animator == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (animatorStateInfos != null)
|
|
{
|
|
if (animatorStateInfos.HasTag(tag))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
if (baseLayerInfo.IsTag(tag))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (underBodyInfo.IsTag(tag))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (rightArmInfo.IsTag(tag))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (leftArmInfo.IsTag(tag))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (upperBodyInfo.IsTag(tag))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (fullBodyInfo.IsTag(tag))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public virtual void MatchTarget(Vector3 matchPosition, Quaternion matchRotation, AvatarTarget target, MatchTargetWeightMask weightMask, float normalisedStartTime, float normalisedEndTime)
|
|
{
|
|
if (animator.isMatchingTarget || animator.IsInTransition(0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
float normalizeTime = Mathf.Repeat(animator.GetCurrentAnimatorStateInfo(0).normalizedTime, 1f);
|
|
|
|
if (normalizeTime > normalisedEndTime)
|
|
{
|
|
return;
|
|
}
|
|
|
|
animator.MatchTarget(matchPosition, matchRotation, target, weightMask, normalisedStartTime, normalisedEndTime);
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
public static partial class vAnimatorParameters
|
|
{
|
|
public static int InputHorizontal = Animator.StringToHash("InputHorizontal");
|
|
public static int InputVertical = Animator.StringToHash("InputVertical");
|
|
public static int InputMagnitude = Animator.StringToHash("InputMagnitude");
|
|
public static int RotationMagnitude = Animator.StringToHash("RotationMagnitude");
|
|
public static int TurnOnSpotDirection = Animator.StringToHash("TurnOnSpotDirection");
|
|
public static int ActionState = Animator.StringToHash("ActionState");
|
|
public static int ResetState = Animator.StringToHash("ResetState");
|
|
public static int IsDead = Animator.StringToHash("isDead");
|
|
public static int IsGrounded = Animator.StringToHash("IsGrounded");
|
|
public static int IsCrouching = Animator.StringToHash("IsCrouching");
|
|
public static int IsStrafing = Animator.StringToHash("IsStrafing");
|
|
public static int IsSprinting = Animator.StringToHash("IsSprinting");
|
|
public static int IsSliding = Animator.StringToHash("IsSliding");
|
|
public static int GroundDistance = Animator.StringToHash("GroundDistance");
|
|
public static int GroundAngle = Animator.StringToHash("GroundAngle");
|
|
public static int VerticalVelocity = Animator.StringToHash("VerticalVelocity");
|
|
public static int IdleRandom = Animator.StringToHash("IdleRandom");
|
|
public static int IdleRandomTrigger = Animator.StringToHash("IdleRandomTrigger");
|
|
}
|
|
} |