animations refactor

This commit is contained in:
2025-08-04 09:33:19 +02:00
parent 064268e049
commit c17ce42700
32 changed files with 1791 additions and 1207 deletions

View File

@@ -1,6 +1,7 @@
using System;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Events;
namespace RebootReality.jelycho.Beacons {
public class BeaconGraphics : MonoBehaviour {
@@ -9,10 +10,10 @@ namespace RebootReality.jelycho.Beacons {
[Range(0.0f, 1.0f)] public float growAmount = 0.5f;
[SerializeField] public float growSpeed = 0.5f;
[SerializeField] public ParticleSystem m_GrowParticleSystem;
float m_CurrentGrowAmount = 0.0f;
public UnityEvent onGrowCalled = new UnityEvent();
void Update() {
if (m_CurrentGrowAmount >= 1.0f) {
foreach (BeaconElement beaconElement in m_BeaconElements) {
@@ -84,7 +85,7 @@ namespace RebootReality.jelycho.Beacons {
UpdateElements(m_CurrentGrowAmount);
growAmount = 1.0f;
m_GrowParticleSystem.Play();
onGrowCalled?.Invoke();
}
[Serializable]

View File

@@ -1,9 +1,12 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using RebootKit.Engine.Main;
using RebootKit.Engine.Network;
using RebootKit.Engine.Simulation;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using Logger = RebootKit.Engine.Foundation.Logger;
namespace RebootReality.jelycho.Feedbacks {
@@ -12,7 +15,7 @@ namespace RebootReality.jelycho.Feedbacks {
public float radius;
public float intensity;
public float timer;
public static int GetMaxBytes() {
return sizeof(float) * 3 + sizeof(float) * 3;
}
@@ -21,8 +24,33 @@ namespace RebootReality.jelycho.Feedbacks {
public class FeedbacksManagerActor : Actor {
static readonly Logger s_Logger = new Logger(nameof(FeedbacksManagerActor));
[SerializeField] Volume m_Volume;
[SerializeField] float m_QuickAttackIndicatorDuration = 0.3f;
[SerializeField] float m_QuickAttackIndicatorPaniniAppearSpeed = 2.0f;
[SerializeField] float m_QuickAttackIndicatorChromaticAppearSpeed = 2.0f;
[SerializeField] float m_QuickAttackIndicatorPaniniDisappearSpeed = 2.0f;
[SerializeField] float m_QuickAttackIndicatorChromaticDisappearSpeed = 2.0f;
[SerializeField] float m_QuickAttackIndicatorPaniniIntensity = 0.1f;
[SerializeField] float m_QuickAttackIndicatorChromaticIntensity = 1.0f;
PaniniProjection m_PaniniProjection;
ChromaticAberration m_ChromaticAberration;
float m_QuickAttackTimer;
List<CameraShakeFeedback> m_ActiveCameraShakes = new List<CameraShakeFeedback>();
void Awake() {
if (!m_Volume.profile.TryGet(out m_PaniniProjection)) {
s_Logger.Error($"Failed to find PaniniProjection on volume: {m_Volume.name}");
}
if (!m_Volume.profile.TryGet(out m_ChromaticAberration)) {
s_Logger.Error($"Failed to find ChromaticAberration on volume: {m_Volume.name}");
}
}
//
// @MARK: Camera shake
//
@@ -31,7 +59,7 @@ namespace RebootReality.jelycho.Feedbacks {
s_Logger.Error("ShakeCamera can only be called on the server.");
return;
}
FeedbacksCameraShakeEvent ev = new FeedbacksCameraShakeEvent {
Feedback = new CameraShakeFeedback {
center = center,
@@ -40,7 +68,7 @@ namespace RebootReality.jelycho.Feedbacks {
timer = duration
}
};
SendActorEvent((byte)FeedbacksManagerActorEvents.CameraShake, ref ev);
SendActorEvent((byte) FeedbacksManagerActorEvents.CameraShake, ref ev);
}
public float GetShakeIntensityForPosition(Vector3 position) {
@@ -70,14 +98,21 @@ namespace RebootReality.jelycho.Feedbacks {
return intensity;
}
//
// @MARK: Local only
//
public void ShowQuickAttackIndicator() {
m_QuickAttackTimer = m_QuickAttackIndicatorDuration;
}
//
// @MARK: Actor
//
protected override IActorData CreateActorData() {
return new NoActorData();
}
public override void OnClientTick(float deltaTime) {
for (int i = m_ActiveCameraShakes.Count - 1; i >= 0; i--) {
CameraShakeFeedback feedback = m_ActiveCameraShakes[i];
@@ -90,13 +125,40 @@ namespace RebootReality.jelycho.Feedbacks {
m_ActiveCameraShakes[i] = feedback;
}
m_QuickAttackTimer -= Time.deltaTime;
if (m_QuickAttackTimer <= 0.0f) {
float chromaticIntensity = m_ChromaticAberration.intensity.value;
chromaticIntensity = Mathf.MoveTowards(chromaticIntensity,
0.0f,
deltaTime * m_QuickAttackIndicatorChromaticDisappearSpeed);
m_ChromaticAberration.intensity.value = chromaticIntensity;
float paniniIntensity = m_PaniniProjection.distance.value;
paniniIntensity = Mathf.MoveTowards(paniniIntensity,
0.0f,
deltaTime * m_QuickAttackIndicatorPaniniDisappearSpeed);
m_PaniniProjection.distance.value = paniniIntensity;
} else {
float chromaticIntensity = m_ChromaticAberration.intensity.value;
chromaticIntensity = Mathf.MoveTowards(chromaticIntensity,
m_QuickAttackIndicatorChromaticIntensity,
deltaTime * m_QuickAttackIndicatorChromaticAppearSpeed);
m_ChromaticAberration.intensity.value = chromaticIntensity;
float paniniIntensity = m_PaniniProjection.distance.value;
paniniIntensity = Mathf.MoveTowards(paniniIntensity,
m_QuickAttackIndicatorPaniniIntensity,
deltaTime * m_QuickAttackIndicatorPaniniAppearSpeed);
m_PaniniProjection.distance.value = paniniIntensity;
}
}
protected override void OnActorEventClient(ActorEvent actorEvent) {
FeedbacksManagerActorEvents feedbackEvent = (FeedbacksManagerActorEvents)actorEvent.EventID;
FeedbacksManagerActorEvents feedbackEvent = (FeedbacksManagerActorEvents) actorEvent.EventID;
switch (feedbackEvent) {
case FeedbacksManagerActorEvents.CameraShake: {
FeedbacksCameraShakeEvent ev = new FeedbacksCameraShakeEvent();
DataSerializationUtils.Deserialize(actorEvent.Data, ref ev);
@@ -106,11 +168,11 @@ namespace RebootReality.jelycho.Feedbacks {
}
break;
}
}
}
}
enum FeedbacksManagerActorEvents : byte {
None = 0x00,
CameraShake = 0x01,

View File

@@ -15,19 +15,25 @@ namespace RebootReality.jelycho.Items {
void Attack(Actor attacker, ItemActor itemActor);
}
[Serializable]
public class ItemHandsAnimationClipsSet {
public AnimationClip idle;
public AnimationClip charging;
public AnimationClip chargedIdle;
public AnimationClip chargedUse;
public AnimationClip[] quickAttacks;
public AnimationClip block;
}
[Serializable]
public class ItemConfig {
public Sprite icon;
[MaxLength(32)] public string characterEquippedMountSlotName = "hand_right";
[Header("Character Animations Names")]
public string idleAnimation;
public string chargingAnimation;
public string chargedUseAnimation;
public string[] quickAttacksAnimations;
public string blockAnimation;
[Header("Character Animations")]
public ItemHandsAnimationClipsSet handsAnimationClipsSets;
[Header("Quick Attack")]
public bool canQuickAttack = false;

View File

@@ -0,0 +1,11 @@
using UnityEngine;
namespace RebootReality.jelycho.Player {
public class FootstepSfxPlayer : MonoBehaviour {
[SerializeField] AudioSource m_AudioSource;
public void PlayFootstep() {
m_AudioSource.Play();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fd9bb0d58ecf466d8fe6d4cd19b51e5c
timeCreated: 1754291034

View File

@@ -16,7 +16,7 @@ namespace RebootReality.jelycho.Player {
public class PlayerActor : Actor {
static readonly Logger s_Logger = new Logger(nameof(PlayerActor));
[SerializeField] Animator m_Animator;
[SerializeField] PlayerAnimator m_PlayerAnimator;
[Header("Movement")]
[SerializeField] PlayerFPPLocomotion m_Locomotion;
@@ -84,6 +84,16 @@ namespace RebootReality.jelycho.Player {
bool m_IsCharging;
float m_ChargeTimer;
[SerializeField] float m_QuickAttackComboMaxDelay = 0.5f;
enum QuickAttackState {
None,
PlayingAnimation,
WaitingForNextAttack
}
QuickAttackState m_QuickAttackState;
int m_QuickAttackComboCounter;
float m_QuickAttackComboTimer;
@@ -122,11 +132,15 @@ namespace RebootReality.jelycho.Player {
void OnEnable() {
Inventory.OnItemPickedUp += OnItemPickedUp;
Inventory.OnItemDropped += OnItemDropped;
m_PlayerAnimator.onQuickAttackFinished.AddListener(OnQuickAttackFinishedAnimation);
}
void OnDisable() {
Inventory.OnItemPickedUp -= OnItemPickedUp;
Inventory.OnItemDropped -= OnItemDropped;
m_PlayerAnimator.onQuickAttackFinished.RemoveListener(OnQuickAttackFinishedAnimation);
}
//
@@ -193,10 +207,6 @@ namespace RebootReality.jelycho.Player {
m_IsCharging = false;
m_ChargeTimer = 0.0f;
if (m_QuickAttackComboTimer <= 0.0f) {
m_QuickAttackComboCounter = 0;
}
}
public void HoldingPrimaryAction() {
@@ -264,12 +274,35 @@ namespace RebootReality.jelycho.Player {
m_IsCharging = false;
} else if (m_EquippedItem.Config.canQuickAttack) {
PlayQuickAttackAnimation(m_QuickAttackComboCounter);
m_QuickAttackComboCounter += 1;
m_QuickAttackComboTimer = 2.0f;
if (m_QuickAttackState == QuickAttackState.None) {
m_QuickAttackComboCounter = 0;
PlayQuickAttackAnimation(m_QuickAttackComboCounter);
m_QuickAttackState = QuickAttackState.PlayingAnimation;
} else if (m_QuickAttackState == QuickAttackState.PlayingAnimation) {
m_QuickAttackComboCounter = 0;
} else if (m_QuickAttackState == QuickAttackState.WaitingForNextAttack) {
m_QuickAttackComboCounter += 1;
PlayQuickAttackAnimation(m_QuickAttackComboCounter);
m_QuickAttackState = QuickAttackState.PlayingAnimation;
if (m_EquippedItem.Config.quickAttackAction != null) {
m_EquippedItem.Config.quickAttackAction.Attack(this, m_EquippedItem);
if (m_EquippedItem.Config.quickAttackAction != null) {
m_EquippedItem.Config.quickAttackAction.Attack(this, m_EquippedItem);
}
}
}
}
void OnQuickAttackFinishedAnimation() {
if (m_QuickAttackState != QuickAttackState.PlayingAnimation) {
return;
}
m_QuickAttackComboTimer = m_QuickAttackComboMaxDelay;
m_QuickAttackState = QuickAttackState.WaitingForNextAttack;
if (m_IsSetupAsOwner) {
if (RR.World.Context is WorldContext context) {
context.FeedbacksManager.ShowQuickAttackIndicator();
}
}
}
@@ -306,60 +339,51 @@ namespace RebootReality.jelycho.Player {
// @MARK: Hands animations
//
void PlayHandsAnimation(string animationName) {
int hash = Animator.StringToHash(animationName);
if (!m_Animator.HasState(m_HandsLayerIndex, hash)) {
s_Logger.Error($"Animator does not have state with name {animationName}");
return;
}
PlayHandsAnimation(hash);
// int hash = Animator.StringToHash(animationName);
//
// if (!m_Animator.HasState(m_HandsLayerIndex, hash)) {
// s_Logger.Error($"Animator does not have state with name {animationName}");
// return;
// }
//
// PlayHandsAnimation(hash);
}
void PlayHandsAnimation(int animationHash) {
m_Animator.CrossFade(animationHash, 0.0f, m_HandsLayerIndex);
if (RR.IsServer()) {
PlayerPlayHandsAnimationEvent handsAnimationEvent = new PlayerPlayHandsAnimationEvent {
AnimationHash = animationHash
};
SendActorEvent((byte)PlayerActorEvents.PlayHandsAnimation, ref handsAnimationEvent);
} else {
PlayerActorRequestHandsAnimationCommand handsAnimationCommand =
new PlayerActorRequestHandsAnimationCommand {
AnimationHash = animationHash
};
SendActorCommand((byte) PlayerActorCommands.RequestHandsAnimation, ref handsAnimationCommand);
}
// m_Animator.CrossFade(animationHash, 0.0f, m_HandsLayerIndex);
//
// if (RR.IsServer()) {
// PlayerPlayHandsAnimationEvent handsAnimationEvent = new PlayerPlayHandsAnimationEvent {
// AnimationHash = animationHash
// };
// SendActorEvent((byte)PlayerActorEvents.PlayHandsAnimation, ref handsAnimationEvent);
// } else {
// PlayerActorRequestHandsAnimationCommand handsAnimationCommand =
// new PlayerActorRequestHandsAnimationCommand {
// AnimationHash = animationHash
// };
// SendActorCommand((byte) PlayerActorCommands.RequestHandsAnimation, ref handsAnimationCommand);
// }
}
void SetHandsIdleAnimation() {
if (m_EquippedItem != null) {
PlayHandsAnimation(m_EquippedItem.Config.idleAnimation);
} else {
PlayHandsAnimation(m_HandsIdleStateName);
}
m_PlayerAnimator.PlayHandsIdle();
}
void SetChargingAnimation() {
if (m_EquippedItem != null) {
PlayHandsAnimation(m_EquippedItem.Config.chargingAnimation);
// PlayHandsAnimation(m_EquippedItem.Config.chargingAnimation);
}
}
void SetChargedUseAnimation() {
if (m_EquippedItem != null) {
PlayHandsAnimation(m_EquippedItem.Config.chargedUseAnimation);
// PlayHandsAnimation(m_EquippedItem.Config.chargedUseAnimation);
}
}
void PlayQuickAttackAnimation(int combo) {
if (m_EquippedItem == null || m_EquippedItem.Config.quickAttacksAnimations.Length == 0) {
return;
}
string animationName = m_EquippedItem.Config.quickAttacksAnimations[combo % m_EquippedItem.Config.quickAttacksAnimations.Length];
PlayHandsAnimation(animationName);
m_PlayerAnimator.PlayQuickAttack(combo);
}
//
@@ -382,6 +406,11 @@ namespace RebootReality.jelycho.Player {
if (m_QuickAttackComboTimer > 0.0f) {
m_QuickAttackComboTimer -= deltaTime;
if (m_QuickAttackComboTimer <= 0.0f && m_QuickAttackState == QuickAttackState.WaitingForNextAttack) {
m_QuickAttackState = QuickAttackState.None;
SetHandsIdleAnimation();
}
}
m_SyncRemoteStateTimer -= deltaTime;
@@ -465,14 +494,14 @@ namespace RebootReality.jelycho.Player {
PlayerActorRequestHandsAnimationCommand command = new PlayerActorRequestHandsAnimationCommand();
DataSerializationUtils.Deserialize(actorCommand.Data, ref command);
if (m_Animator.HasState(m_HandsLayerIndex, command.AnimationHash)) {
PlayerPlayHandsAnimationEvent handsAnimationEvent = new PlayerPlayHandsAnimationEvent {
AnimationHash = command.AnimationHash
};
SendActorEvent((byte)PlayerActorEvents.PlayHandsAnimation, ref handsAnimationEvent);
} else {
s_Logger.Error($"Animator does not have state with hash {command.AnimationHash}");
}
// if (m_Animator.HasState(m_HandsLayerIndex, command.AnimationHash)) {
// PlayerPlayHandsAnimationEvent handsAnimationEvent = new PlayerPlayHandsAnimationEvent {
// AnimationHash = command.AnimationHash
// };
// SendActorEvent((byte)PlayerActorEvents.PlayHandsAnimation, ref handsAnimationEvent);
// } else {
// s_Logger.Error($"Animator does not have state with hash {command.AnimationHash}");
// }
break;
}
@@ -561,11 +590,11 @@ namespace RebootReality.jelycho.Player {
PlayerPlayHandsAnimationEvent handsAnimationEvent = new PlayerPlayHandsAnimationEvent();
DataSerializationUtils.Deserialize(actorEvent.Data, ref handsAnimationEvent);
if (m_Animator.HasState(m_HandsLayerIndex, handsAnimationEvent.AnimationHash)) {
m_Animator.CrossFade(handsAnimationEvent.AnimationHash, 0.0f, m_HandsLayerIndex);
} else {
s_Logger.Error($"Animator does not have state with hash {handsAnimationEvent.AnimationHash}");
}
// if (m_Animator.HasState(m_HandsLayerIndex, handsAnimationEvent.AnimationHash)) {
// m_Animator.CrossFade(handsAnimationEvent.AnimationHash, 0.0f, m_HandsLayerIndex);
// } else {
// s_Logger.Error($"Animator does not have state with hash {handsAnimationEvent.AnimationHash}");
// }
break;
}
@@ -690,8 +719,6 @@ namespace RebootReality.jelycho.Player {
return;
}
// @BUG: Sometimes the item will not update it's physics state and will keep floating in the air. It's rare?
UpdateEquippedItem();
item.SetHidden(false);
@@ -740,6 +767,12 @@ namespace RebootReality.jelycho.Player {
};
SendActorEvent((byte) PlayerActorEvents.PrimaryEquippedItemChanged, ref itemChangedEvent);
if (m_EquippedItem != null) {
m_PlayerAnimator.SetHandsAnimationSet(m_EquippedItem.Config.handsAnimationClipsSets);
} else {
m_PlayerAnimator.SetHandsAnimationSet(null);
}
SetHandsIdleAnimation();
}
@@ -756,12 +789,13 @@ namespace RebootReality.jelycho.Player {
// @MARK: Common
//
void TickCharacterRotation() {
// @TODO: restore old delayed character rotation
m_Locomotion.YawRotation = m_Camera.Yaw;
float3 targetCharacterForward = math.normalize(LookDirection.With(y: 0.0f));
float3 currentCharacterForward = math.normalize(m_CharacterForwardTransform.forward.With(y: 0.0f));
float angleRad =
math.acos(math.clamp(math.dot(targetCharacterForward, currentCharacterForward) / (math.length(targetCharacterForward) * math.length(currentCharacterForward)),
-1f, 1f));
float angleRad = math.acos(math.clamp(math.dot(targetCharacterForward, currentCharacterForward) / (math.length(targetCharacterForward) * math.length(currentCharacterForward)), -1f, 1f));
float angleDeg = math.degrees(angleRad);
bool rotateCharacter = false;
@@ -886,14 +920,6 @@ namespace RebootReality.jelycho.Player {
//
// @MARK: Animations
//
struct AnimatorParamHashes {
public static readonly int VelocityForwardNormalized = Animator.StringToHash("VelocityForwardNormalized");
public static readonly int VelocityRightNormalized = Animator.StringToHash("VelocityRightNormalized");
public static readonly int TurnVelocity = Animator.StringToHash("TurnVelocity");
public static readonly int IsGrounded = Animator.StringToHash("IsGrounded");
}
void UpdateAnimator(Vector3 velocity) {
Vector3 localVelocity = m_CharacterForwardTransform.InverseTransformDirection(velocity);
float forwardNormalized = localVelocity.z / m_Locomotion.runSpeed;
@@ -906,11 +932,13 @@ namespace RebootReality.jelycho.Player {
turnVelocity = 0.0f;
}
m_Animator.SetFloat(AnimatorParamHashes.VelocityForwardNormalized, forwardNormalized);
m_Animator.SetFloat(AnimatorParamHashes.VelocityRightNormalized, rightNormalized);
m_Animator.SetFloat(AnimatorParamHashes.TurnVelocity, turnVelocity);
m_Animator.SetBool(AnimatorParamHashes.IsGrounded, m_Locomotion.IsGrounded);
PlayerLocomotionAnimatorParams locomotionParams = new PlayerLocomotionAnimatorParams {
IsGrounded = m_Locomotion.IsGrounded,
VelocityForwardNormalized = forwardNormalized,
VelocityRightNormalized = rightNormalized,
TurnVelocity = turnVelocity
};
m_PlayerAnimator.SetLocomotionParams(locomotionParams);
}
}

View File

@@ -0,0 +1,166 @@
using System;
using System.Runtime.InteropServices;
using RebootKit.Engine.Animations;
using RebootReality.jelycho.Items;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Events;
using UnityEngine.Playables;
namespace RebootReality.jelycho.Player {
public struct PlayerLocomotionAnimatorParams {
public float VelocityForwardNormalized;
public float VelocityRightNormalized;
public float TurnVelocity;
public bool IsGrounded;
}
public class CharacterHandsReAnimatorNode : IReAnimatorNode {
enum State {
None,
Idle,
QuickAttack
}
[field: SerializeField] public string Name { get; private set; }
PlayableGraph m_Graph;
AnimationMixerPlayable m_Mixer;
AnimationClipPlayable m_CurrentPlayable;
ItemHandsAnimationClipsSet m_ClipsSet;
State m_State;
public event Action OnQuickAttackAnimationFinished = delegate { };
public void Tick(float deltaTime) {
switch (m_State) {
case State.QuickAttack: {
if (m_CurrentPlayable.GetTime() >= m_CurrentPlayable.GetAnimationClip().length &&
m_CurrentPlayable.GetPlayState() == PlayState.Playing) {
m_CurrentPlayable.Pause();
OnQuickAttackAnimationFinished?.Invoke();
}
break;
}
}
}
public IPlayable Build(PlayableGraph graph) {
m_Graph = graph;
m_Mixer = AnimationMixerPlayable.Create(graph, 1);
return m_Mixer;
}
public bool TryFindChild(string name, out IReAnimatorNode node) {
node = null;
return false;
}
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_CurrentPlayable = AnimationClipPlayable.Create(m_Graph, clip);
m_Mixer.DisconnectInput(0);
m_Mixer.ConnectInput(0, m_CurrentPlayable, 0, 1.0f);
m_State = State.QuickAttack;
m_CurrentPlayable.Play();
}
public void SetIdle() {
if (m_ClipsSet == null) {
return;
}
m_CurrentPlayable = AnimationClipPlayable.Create(m_Graph, m_ClipsSet.idle);
m_Mixer.DisconnectInput(0);
m_Mixer.ConnectInput(0, m_CurrentPlayable, 0, 1.0f);
m_CurrentPlayable.Play();
m_State = State.Idle;
}
}
public class PlayerAnimator : MonoBehaviour {
[SerializeField] ReAnimator m_ReAnimator;
MixerNode m_LocomotionRootMixer;
BlendTree2DNode m_GroundBlendTree;
CharacterHandsReAnimatorNode m_Hands;
// @TODO: for some reason `SetLocomotionParams` is called before awake
bool m_IsReady = false;
public UnityEvent onQuickAttackFinished = new UnityEvent();
void Awake() {
m_LocomotionRootMixer = m_ReAnimator.FindNode<MixerNode>("locomotion_root");
m_LocomotionRootMixer.SetInputWeight(0, 1.0f);
m_LocomotionRootMixer.SetInputWeight(1, 0.0f);
m_GroundBlendTree = m_ReAnimator.FindNode<BlendTree2DNode>("locomotion_ground");
m_GroundBlendTree.SetDirection(new float2(0, 1));
m_Hands = m_ReAnimator.FindNode<CharacterHandsReAnimatorNode>("hands");
m_Hands.OnQuickAttackAnimationFinished += () => { onQuickAttackFinished?.Invoke(); };
m_IsReady = true;
}
void Update() {
}
public void SetLocomotionParams(PlayerLocomotionAnimatorParams locomotionParams) {
if (!m_IsReady) {
return;
}
m_LocomotionRootMixer.SetInputWeight(0, locomotionParams.IsGrounded ? 1.0f : 0.0f);
m_LocomotionRootMixer.SetInputWeight(1, locomotionParams.IsGrounded ? 0.0f : 1.0f);
float2 groundBlendDirection = new float2(locomotionParams.VelocityRightNormalized,
locomotionParams.VelocityForwardNormalized);
m_GroundBlendTree.SetDirection(groundBlendDirection);
}
public void SetHandsAnimationSet(ItemHandsAnimationClipsSet clipsSet) {
if (clipsSet == null) {
m_ReAnimator.SetLayerWeight(1, 0.0f);
return;
}
m_ReAnimator.SetLayerWeight(1, 1.0f);
m_Hands.UpdateClips(clipsSet);
}
public void PlayQuickAttack(int combo) {
m_Hands.PlayQuickAttack(combo);
}
public void PlayHandsIdle() {
m_Hands.SetIdle();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 00a9f9c2ce4a41fdaadcfb24c4233127
timeCreated: 1754007861