using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; using Quaternion = System.Numerics.Quaternion; public class AnimatorController : MonoBehaviour { [Header("Input")] public float speed; public bool jump; [Header("Player")] public float walkSpeed = 2.0f; public float runSpeed = 6.0f; [Range(0f,1f)] public float freeLookRange; public Transform head; public Transform lookAtTarget; public Camera playerCamera; [Space(10)] [Header("Jump")] //滞空后开始下落动画时间 public float FallTimeout = 0.15f; //判断是否接地 [Header("Player Grounded")] public LayerMask groundLayers; public float groundedOffset = -0.14f; public float groundedRadius = 0.28f; public bool grounded = true; //脚步声 public AudioClip landingAudioClip; public AudioClip[] footstepAudioClips; [Range(0, 1)] public float footstepAudioVolume = 0.5f; private Animator _animator; private bool _hasAnimator; // animation IDs private int _animIDSpeed; private int _animIDGrounded; private int _animIDJump; private int _animIDFreeFall; // 滞空时间 private float _fallTimeoutTimer; void Start() { _animIDSpeed = Animator.StringToHash("Speed"); _animIDGrounded = Animator.StringToHash("Grounded"); _animIDJump = Animator.StringToHash("Jump"); _animIDFreeFall = Animator.StringToHash("FreeFall"); _hasAnimator = TryGetComponent(out _animator); if(playerCamera==null) playerCamera=Camera.main; } // Update is called once per frame void FixedUpdate() { JumpAndGravity(); GroundedCheck(); Move(); LookAtTarget(); } private void JumpAndGravity() { if (grounded) { // 重置滞空时间 _fallTimeoutTimer = FallTimeout; // 动画设为非空中状态 if (_hasAnimator ) { _animator.SetBool(_animIDJump, false); _animator.SetBool(_animIDFreeFall, false); } // 满足条件开始跳跃 Debug.Log(jump + "*********" + _hasAnimator); if (jump) { if (_hasAnimator) { _animator.SetBool(_animIDJump, true); } } jump = false; } else { // 计算滞空时间 if (_fallTimeoutTimer >= 0.0f) { _fallTimeoutTimer -= Time.deltaTime; } else { // 滞空结束,开始播放下落动画 if (_hasAnimator) { _animator.SetBool(_animIDFreeFall, true); } } jump = false; } } // 检查指定位置的球体与地面接触,判断是否接地 private void GroundedCheck() { Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - groundedOffset, transform.position.z); grounded = Physics.CheckSphere(spherePosition, groundedRadius, groundLayers, QueryTriggerInteraction.Ignore); if (_hasAnimator) { _animator.SetBool(_animIDGrounded, grounded); } } private void Move() { float animSpeed=0f; if (_hasAnimator) { if (speed >= 0 && speed <= walkSpeed) { animSpeed = RemapNum(speed, 0f, walkSpeed, 0f, 2f); } if (speed >walkSpeed) { speed = Mathf.Clamp(speed, 0f, 6.0f); animSpeed = RemapNum(speed, walkSpeed, runSpeed, 2f, 6f); } _animator.SetFloat(_animIDSpeed, animSpeed); } } private void LookAtTarget() { Vector3 cameraForward = playerCamera.transform.forward; if (Vector3.Dot(cameraForward, head.forward) < freeLookRange) { lookAtTarget.position = Vector3.Lerp(lookAtTarget.position ,head.position + head.forward,0.1f); } else { lookAtTarget.position =Vector3.Lerp(lookAtTarget.position ,head.position + cameraForward,0.1f); } } private float RemapNum(float input, float oldMin, float oldMax, float newMin, float newMax) { float result = (newMax - newMin) / (oldMax - oldMin) * (input - oldMin) + newMin; return result; } //球体与地面接触判断触地可视 private void OnDrawGizmosSelected() { Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f); Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f); if (grounded) Gizmos.color = transparentGreen; else Gizmos.color = transparentRed; // when selected, draw a gizmo in the position of, and matching radius of, the grounded collider Gizmos.DrawSphere(new Vector3(transform.position.x, transform.position.y - groundedOffset, transform.position.z), groundedRadius); } private void OnFootstep(AnimationEvent animationEvent) { if (animationEvent.animatorClipInfo.weight > 0.5f) { if (footstepAudioClips.Length > 0) { var index = Random.Range(0, footstepAudioClips.Length); AudioSource.PlayClipAtPoint(footstepAudioClips[index], transform.transform.position, footstepAudioVolume); } } } private void OnLand(AnimationEvent animationEvent) { if (animationEvent.animatorClipInfo.weight > 0.5f) { AudioSource.PlayClipAtPoint(landingAudioClip, transform.position, footstepAudioVolume); } } }