277 lines
8.8 KiB
C#
277 lines
8.8 KiB
C#
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using Animancer;
|
|
using RebootReality.jelycho.Items;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEvent = UnityEngine.Events.UnityEvent;
|
|
|
|
namespace RebootReality.jelycho.Player {
|
|
public struct PlayerLocomotionAnimatorParams {
|
|
public float VelocityForwardNormalized;
|
|
public float VelocityRightNormalized;
|
|
public float TurnVelocity;
|
|
public bool IsGrounded;
|
|
}
|
|
|
|
public class PlayerHandsAnimator {
|
|
enum State {
|
|
None,
|
|
Idle,
|
|
QuickAttack,
|
|
Charging,
|
|
ChargedIdle,
|
|
Charged,
|
|
ChargedUse
|
|
}
|
|
|
|
AnimancerLayer m_AnimancerLayer;
|
|
AnimancerState m_AnimancerState;
|
|
|
|
ItemHandsAnimationClipsSet m_ClipsSet;
|
|
|
|
State m_State;
|
|
|
|
public event Action OnQuickAttackAnimationFinished = delegate { };
|
|
public event Action OnCharged = delegate { };
|
|
|
|
public PlayerHandsAnimator(AnimancerLayer layer) {
|
|
m_AnimancerLayer = layer;
|
|
}
|
|
|
|
public void Tick(float deltaTime) {
|
|
if (m_AnimancerState == null) {
|
|
return;
|
|
}
|
|
|
|
switch (m_State) {
|
|
case State.QuickAttack: {
|
|
if (IsCurrentClipFinished()) {
|
|
// m_AnimancerState.Stop();
|
|
m_AnimancerState = null;
|
|
OnQuickAttackAnimationFinished?.Invoke();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case State.Charging: {
|
|
if (IsCurrentClipFinished()) {
|
|
SetChargedIdle();
|
|
OnCharged?.Invoke();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case State.ChargedUse: {
|
|
if (IsCurrentClipFinished()) {
|
|
SetIdle();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void UpdateClips(ItemHandsAnimationClipsSet clipsSet) {
|
|
m_ClipsSet = clipsSet;
|
|
|
|
if (clipsSet == null) {
|
|
m_State = State.None;
|
|
return;
|
|
}
|
|
|
|
SetIdle();
|
|
}
|
|
|
|
public void PlayQuickAttack(int combo) {
|
|
if (m_ClipsSet == null) {
|
|
return;
|
|
}
|
|
|
|
AnimationClip clip = m_ClipsSet.quickAttacks[combo % m_ClipsSet.quickAttacks.Length];
|
|
m_AnimancerState = m_AnimancerLayer.Play(clip, 0.1f);
|
|
|
|
m_State = State.QuickAttack;
|
|
}
|
|
|
|
public void SetIdle() {
|
|
if (m_ClipsSet == null) {
|
|
return;
|
|
}
|
|
|
|
m_AnimancerState = m_AnimancerLayer.Play(m_ClipsSet.idle, 0.1f);
|
|
m_State = State.Idle;
|
|
}
|
|
|
|
public void SetCharging() {
|
|
if (m_ClipsSet == null) {
|
|
return;
|
|
}
|
|
|
|
m_AnimancerState = m_AnimancerLayer.Play(m_ClipsSet.charging, 0.1f);
|
|
m_State = State.Charging;
|
|
}
|
|
|
|
public void SetChargedIdle() {
|
|
if (m_ClipsSet == null) {
|
|
return;
|
|
}
|
|
|
|
m_AnimancerState = m_AnimancerLayer.Play(m_ClipsSet.chargedIdle, 0.1f);
|
|
m_State = State.ChargedIdle;
|
|
}
|
|
|
|
public void PlayChargedUse() {
|
|
if (m_ClipsSet == null) {
|
|
return;
|
|
}
|
|
|
|
m_AnimancerState = m_AnimancerLayer.Play(m_ClipsSet.chargedUse, 0.1f);
|
|
m_State = State.ChargedUse;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
bool IsCurrentClipFinished() {
|
|
return m_AnimancerState.NormalizedTime >= 1.0f;
|
|
}
|
|
}
|
|
|
|
public class PlayerAnimator : MonoBehaviour {
|
|
[SerializeField] AnimancerComponent m_Animancer;
|
|
[SerializeField] AnimationClip m_IdleClip;
|
|
|
|
[SerializeField] TransitionAsset m_GroundLocomotion;
|
|
[SerializeField] StringAsset m_GroundLocomotionPropertyX;
|
|
[SerializeField] StringAsset m_GroundLocomotionPropertyY;
|
|
SmoothedVector2Parameter m_SmoothLocomotionDirection;
|
|
|
|
[SerializeField] TransitionAsset m_GroundTurn;
|
|
[SerializeField] StringAsset m_GroundTurnProperty;
|
|
SmoothedFloatParameter m_SmoothGroundTurn;
|
|
|
|
[SerializeField] AnimationClip m_InAirClip;
|
|
|
|
[SerializeField] AnimationClip m_KickClip;
|
|
|
|
[SerializeField] AvatarMask m_HandsMask;
|
|
[SerializeField] AvatarMask m_LegsMask;
|
|
|
|
AnimancerLayer m_BaseLayer;
|
|
AnimancerLayer m_LocomotionLegsLayer;
|
|
AnimancerLayer m_HandsLayer;
|
|
AnimancerLayer m_FullBodyLayer;
|
|
PlayerHandsAnimator m_Hands;
|
|
|
|
bool m_IsPlayingKickAnimation;
|
|
|
|
// @TODO: for some reason `SetLocomotionParams` is called before awake
|
|
bool m_IsReady = false;
|
|
|
|
public UnityEvent onQuickAttackFinished = new UnityEvent();
|
|
public UnityEvent onChargeReady = new UnityEvent();
|
|
|
|
void Awake() {
|
|
m_BaseLayer = m_Animancer.Layers[0];
|
|
m_BaseLayer.SetDebugName("Base Layer");
|
|
m_BaseLayer.Play(m_IdleClip);
|
|
|
|
m_LocomotionLegsLayer = m_Animancer.Layers[1];
|
|
m_LocomotionLegsLayer.SetDebugName("Locomotion Legs");
|
|
m_LocomotionLegsLayer.Mask = m_LegsMask;
|
|
m_SmoothLocomotionDirection = new SmoothedVector2Parameter(m_Animancer,
|
|
m_GroundLocomotionPropertyX,
|
|
m_GroundLocomotionPropertyY,
|
|
0.1f);
|
|
m_LocomotionLegsLayer.Play(m_GroundLocomotion);
|
|
|
|
m_SmoothGroundTurn = new SmoothedFloatParameter(m_Animancer,
|
|
m_GroundTurnProperty,
|
|
0.1f);
|
|
|
|
m_HandsLayer = m_Animancer.Layers[2];
|
|
m_HandsLayer.SetDebugName("Hands");
|
|
m_HandsLayer.Mask = m_HandsMask;
|
|
m_HandsLayer.SetWeight(0.0f);
|
|
|
|
m_Hands = new PlayerHandsAnimator(m_HandsLayer);
|
|
m_Hands.OnQuickAttackAnimationFinished += () => onQuickAttackFinished.Invoke();
|
|
m_Hands.OnCharged += () => onChargeReady.Invoke();
|
|
|
|
m_FullBodyLayer = m_Animancer.Layers[3];
|
|
m_FullBodyLayer.SetDebugName("Full body");
|
|
m_FullBodyLayer.SetWeight(0.0f);
|
|
|
|
m_IsReady = true;
|
|
}
|
|
|
|
void OnDestroy() {
|
|
m_SmoothLocomotionDirection.Dispose();
|
|
}
|
|
|
|
void Update() {
|
|
float dt = Time.deltaTime;
|
|
m_Hands.Tick(dt);
|
|
|
|
if (m_IsPlayingKickAnimation &&
|
|
m_FullBodyLayer.CurrentState.NormalizedTime >= 1.0f) {
|
|
m_FullBodyLayer.SetWeight(0.0f);
|
|
m_IsPlayingKickAnimation = false;
|
|
}
|
|
}
|
|
|
|
public void SetLocomotionParams(PlayerLocomotionAnimatorParams locomotionParams) {
|
|
if (!m_IsReady) {
|
|
return;
|
|
}
|
|
|
|
if (!locomotionParams.IsGrounded) {
|
|
m_LocomotionLegsLayer.Play(m_InAirClip, 0.1f);
|
|
return;
|
|
}
|
|
|
|
if (math.abs(locomotionParams.TurnVelocity) > 0.1f) {
|
|
m_SmoothGroundTurn.TargetValue = locomotionParams.TurnVelocity;
|
|
m_LocomotionLegsLayer.Play(m_GroundTurn, 0.1f);
|
|
} else {
|
|
var groundBlendDirection = new float2(locomotionParams.VelocityRightNormalized,
|
|
locomotionParams.VelocityForwardNormalized);
|
|
m_SmoothLocomotionDirection.TargetValue = groundBlendDirection;
|
|
m_LocomotionLegsLayer.Play(m_GroundLocomotion, 0.1f);
|
|
}
|
|
}
|
|
|
|
public void SetHandsAnimationSet(ItemHandsAnimationClipsSet clipsSet) {
|
|
if (clipsSet == null) {
|
|
m_HandsLayer.SetWeight(0.0f);
|
|
return;
|
|
}
|
|
|
|
m_HandsLayer.SetWeight(1.0f);
|
|
m_Hands.UpdateClips(clipsSet);
|
|
}
|
|
|
|
public void PlayQuickAttack(int combo) {
|
|
m_Hands.PlayQuickAttack(combo);
|
|
}
|
|
|
|
public void PlayHandsIdle() {
|
|
m_Hands.SetIdle();
|
|
}
|
|
|
|
public void PlayCharging() {
|
|
m_Hands.SetCharging();
|
|
}
|
|
|
|
public void PlayChargedUse() {
|
|
m_Hands.PlayChargedUse();
|
|
}
|
|
|
|
public void PlayKickAnimation() {
|
|
if (m_IsPlayingKickAnimation) {
|
|
return;
|
|
}
|
|
|
|
m_FullBodyLayer.Play(m_KickClip, 0.1f).Time = 0.0f;
|
|
m_IsPlayingKickAnimation = true;
|
|
}
|
|
}
|
|
} |