Files
BABA_YAGA/Assets/Scripts/Player Controller/PlayerAnimationHandler.cs

162 lines
6.4 KiB
C#
Raw Normal View History

2026-04-28 00:07:42 +07:00
using UnityEngine;
using Fusion;
namespace OnlyScove.Scripts
{
public class PlayerAnimationHandler : NetworkBehaviour
{
[Header("Animator Settings")]
[SerializeField] private string speedParamName = "Speed";
[SerializeField] private string velocityXParamName = "Velocity X";
[SerializeField] private string velocityZParamName = "Velocity Z";
2026-05-30 11:20:59 +07:00
[SerializeField] private string groundedParamName = "Grounded";
2026-04-28 00:07:42 +07:00
[SerializeField] private float animationDamping = 0.2f;
2026-05-30 11:20:59 +07:00
[Header("Visual Correction")]
[SerializeField] private float visualOffsetY = 0f;
[SerializeField] private Transform modelTransform;
private CharacterController controller;
2026-04-28 00:07:42 +07:00
private Animator anim;
private int speedHash;
private int velocityXHash;
private int velocityZHash;
2026-05-30 11:20:59 +07:00
private int groundedHash;
private readonly System.Collections.Generic.HashSet<int> parameterHashes = new System.Collections.Generic.HashSet<int>();
2026-04-28 00:07:42 +07:00
public void Initialize(Animator animator)
{
this.anim = animator;
2026-05-30 11:20:59 +07:00
this.controller = GetComponentInParent<CharacterController>();
// Auto-assign modelTransform if null
if (modelTransform == null && anim != null) modelTransform = anim.transform;
2026-04-28 00:07:42 +07:00
if (anim != null)
{
2026-05-30 11:20:59 +07:00
Debug.Log($"<color=green>[AnimationHandler]</color> Animator found on: {anim.gameObject.name}");
parameterHashes.Clear();
2026-04-28 00:07:42 +07:00
foreach (AnimatorControllerParameter param in anim.parameters)
{
2026-05-30 11:20:59 +07:00
parameterHashes.Add(param.nameHash);
}
int speedHashCheck = Animator.StringToHash(speedParamName);
if (!parameterHashes.Contains(speedHashCheck) && parameterHashes.Contains(Animator.StringToHash("Blend")))
{
speedParamName = "Blend";
speedHash = Animator.StringToHash(speedParamName);
Debug.Log($"<color=yellow>[AnimationHandler]</color> 'Speed' not found, using 'Blend' instead.");
2026-04-28 00:07:42 +07:00
}
}
2026-05-30 11:20:59 +07:00
else
{
Debug.LogError("<color=red>[AnimationHandler]</color> FAILED to find Animator! Please check your Prefab.");
}
2026-04-28 00:07:42 +07:00
speedHash = Animator.StringToHash(speedParamName);
velocityXHash = Animator.StringToHash(velocityXParamName);
velocityZHash = Animator.StringToHash(velocityZParamName);
2026-05-30 11:20:59 +07:00
groundedHash = Animator.StringToHash(groundedParamName);
}
private bool wasGroundedInAnimator;
public void UpdateAnimator(float speed, Vector2 moveInput, bool isGrounded, float deltaTime)
{
if (anim == null) return;
// Snap to zero if speed is very low to force Idle
float targetSpeed = speed < 0.05f ? 0f : speed;
float damping = (targetSpeed == 0f || targetSpeed > 0.9f) ? 0f : animationDamping;
if (parameterHashes.Contains(speedHash)) anim.SetFloat(speedHash, targetSpeed, damping, deltaTime);
if (parameterHashes.Contains(velocityXHash)) anim.SetFloat(velocityXHash, moveInput.x * targetSpeed, damping, deltaTime);
if (parameterHashes.Contains(velocityZHash)) anim.SetFloat(velocityZHash, moveInput.y * targetSpeed, damping, deltaTime);
// Quan trọng: Cập nhật biến Grounded cho Animator
if (parameterHashes.Contains(groundedHash)) anim.SetBool(groundedHash, isGrounded);
// Nếu đang ở trên mặt đất, đảm bảo reset các trạng thái nhảy/rơi
if (isGrounded)
{
SafeSetBool("IsJumping", false);
SafeSetBool("IsFalling", false);
var stateInfo = anim.GetCurrentAnimatorStateInfo(0);
if (stateInfo.IsName("Jump") || stateInfo.IsName("Fall") || stateInfo.IsName("Airborne"))
{
anim.CrossFadeInFixedTime("Locomotion Ground", 0.1f);
}
}
wasGroundedInAnimator = isGrounded;
}
public void SafeSetTrigger(string name)
{
if (anim == null) return;
int hash = Animator.StringToHash(name);
if (parameterHashes.Contains(hash)) anim.SetTrigger(hash);
2026-04-28 00:07:42 +07:00
}
2026-05-30 11:20:59 +07:00
public void SafeSetTrigger(int hash)
2026-04-28 00:07:42 +07:00
{
if (anim == null) return;
2026-05-30 11:20:59 +07:00
if (parameterHashes.Contains(hash)) anim.SetTrigger(hash);
}
public void SafeResetTrigger(string name)
{
if (anim == null) return;
int hash = Animator.StringToHash(name);
if (parameterHashes.Contains(hash)) anim.ResetTrigger(hash);
}
public void SafeResetTrigger(int hash)
{
if (anim == null) return;
if (parameterHashes.Contains(hash)) anim.ResetTrigger(hash);
}
2026-04-28 00:07:42 +07:00
2026-05-30 11:20:59 +07:00
public void SafeSetBool(string name, bool value)
{
if (anim == null) return;
int hash = Animator.StringToHash(name);
if (parameterHashes.Contains(hash)) anim.SetBool(hash, value);
}
public void SafeSetFloat(int hash, float value, float dampTime, float deltaTime)
{
if (anim == null) return;
if (parameterHashes.Contains(hash)) anim.SetFloat(hash, value, dampTime, deltaTime);
2026-04-28 00:07:42 +07:00
}
public void SetSpeed(float speed)
{
2026-05-30 11:20:59 +07:00
if (anim != null && parameterHashes.Contains(speedHash))
anim.SetFloat(speedHash, speed);
}
public void ForceLocomotion()
{
if (anim != null) anim.CrossFadeInFixedTime("Locomotion Ground", 0.1f);
}
private void LateUpdate()
{
if (modelTransform != null && controller != null)
{
// Automatically snap mesh to the bottom of the CharacterController capsule
// This fixes hovering/tiptoeing issues regardless of animation offsets
Vector3 targetPos = modelTransform.localPosition;
float bottomY = controller.center.y - (controller.height / 2f);
targetPos.y = bottomY + visualOffsetY;
modelTransform.localPosition = targetPos;
}
2026-04-28 00:07:42 +07:00
}
}
}