Unity角色动画控制异常求助:闪避动画触发错误(附脚本)
问题分析与修正方案
你的问题核心是状态逻辑冲突和错误的速度设置:
- 跳跃、闪避逻辑块互相重置对方的状态变量,导致动画触发混乱
- 闪避时设置
ySpeed=2直接赋予了向上速度,这就是伴随跳跃行为的原因 - 闪避分支的错误逻辑导致动画持续触发,无法正常切换
以下是修正后的完整脚本,关键修改点已标注:
using UnityEngine; public class PlayerMovement : MonoBehaviour { [SerializeField] private float rotationSpeed; [SerializeField] private float jumpHeight; [SerializeField] private float gravityMultiplier; [SerializeField] private float jumpHorizontalSpeed; [SerializeField] private float jumpButtonGracePeriod; [SerializeField] private float dodgeButtonGracePeriod; [SerializeField] private Transform cameraTransform; private Animator animator; private CharacterController characterController; private float ySpeed; private float originalStepOffset; private float? lastGroundedTime; private float? jumpButtonPressedTime; private float? dodgeButtonPressedTime; private bool isJumping; private bool isGrounded; private bool isDodging; void Start() { animator = GetComponent<Animator>(); characterController = GetComponent<CharacterController>(); originalStepOffset = characterController.stepOffset; } void Update() { // 基础移动输入 float horizontalInput = Input.GetAxis("Horizontal"); float verticalInput = Input.GetAxis("Vertical"); Vector3 movementDirection = new Vector3(horizontalInput, 0, verticalInput); float inputMagnitude = Mathf.Clamp01(movementDirection.magnitude); // 慢走逻辑 if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { inputMagnitude /= 2; } // 动画混合树参数 animator.SetFloat("Input Magnitude", inputMagnitude, 0.05f, Time.deltaTime); // 基于相机方向调整移动方向 movementDirection = Quaternion.AngleAxis(cameraTransform.rotation.eulerAngles.y, Vector3.up) * movementDirection; movementDirection.Normalize(); // 重力计算 float gravity = Physics.gravity.y * gravityMultiplier; ySpeed += gravity * Time.deltaTime; // 更新地面状态时间 if (characterController.isGrounded) { lastGroundedTime = Time.time; } // 捕获输入事件 if (Input.GetButtonDown("Jump")) { jumpButtonPressedTime = Time.time; } if (Input.GetButtonDown("Dodge")) { dodgeButtonPressedTime = Time.time; } // 统一处理地面状态逻辑 if (Time.time - lastGroundedTime <= jumpButtonGracePeriod) { characterController.stepOffset = originalStepOffset; ySpeed = -0.5f; isGrounded = true; animator.SetBool("isGrounded", true); // 优先处理闪避(可根据需求调整优先级) bool shouldDodge = Time.time - dodgeButtonPressedTime <= dodgeButtonGracePeriod; bool shouldJump = Time.time - jumpButtonPressedTime <= jumpButtonGracePeriod && !shouldDodge; if (shouldDodge) { // 闪避:地面动作,移除向上速度 animator.SetBool("isDodging", true); animator.SetBool("isJumping", false); animator.SetBool("isFalling", false); isDodging = true; isJumping = false; dodgeButtonPressedTime = null; lastGroundedTime = null; // 短暂脱离地面判定,防止连续触发 } else if (shouldJump) { // 跳跃逻辑 ySpeed = Mathf.Sqrt(jumpHeight * -3 * gravity); animator.SetBool("isJumping", true); animator.SetBool("isDodging", false); animator.SetBool("isFalling", false); isJumping = true; isDodging = false; jumpButtonPressedTime = null; lastGroundedTime = null; } else { // 普通地面状态 animator.SetBool("isJumping", false); animator.SetBool("isDodging", false); animator.SetBool("isFalling", false); isJumping = false; isDodging = false; } } else { // 空中状态 characterController.stepOffset = 0; isGrounded = false; animator.SetBool("isGrounded", false); animator.SetBool("isDodging", false); // 空中强制关闭闪避动画 isDodging = false; if ((isJumping && ySpeed < 0) || ySpeed < -2) { animator.SetBool("isFalling", true); animator.SetBool("isJumping", false); isJumping = false; } } // 角色转向逻辑 if (movementDirection != Vector3.zero) { animator.SetBool("isMoving", true); Quaternion toRotation = Quaternion.LookRotation(movementDirection, Vector3.up); transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime); } else { animator.SetBool("isMoving", false); } // 空中移动处理 if (!isGrounded) { Vector3 velocity = movementDirection * inputMagnitude * jumpHorizontalSpeed; velocity.y = ySpeed; characterController.Move(velocity * Time.deltaTime); } } private Vector3 AdjustVelocityToSlope(Vector3 velocity) { var ray = new Ray(transform.position, Vector3.down); if (Physics.Raycast(ray, out RaycastHit hitInfo, 0.2f)) { var slopeRotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal); var adjustedVelocity = slopeRotation * velocity; if (adjustedVelocity.y < 0) { return adjustedVelocity; } } return velocity; } private void OnAnimatorMove() { if (isGrounded) { Vector3 velocity = animator.deltaPosition; velocity = AdjustVelocityToSlope(velocity); velocity.y += ySpeed * Time.deltaTime; characterController.Move(velocity); } } private void OnApplicationFocus(bool focus) { Cursor.lockState = focus ? CursorLockMode.Locked : CursorLockMode.None; } }
关键修改说明
- 统一状态处理:将跳跃、闪避逻辑合并到地面状态判断中,避免互相覆盖状态变量
- 修正闪避速度:移除闪避时的
ySpeed=2设置,闪避为地面动作,无需向上速度 - 输入优先级控制:设置闪避优先于跳跃的逻辑(可按需调整),防止同时触发两个动作
- 空中状态清理:空中强制关闭闪避动画,避免错误触发旧动画
- 状态同步优化:规范状态变量与动画参数的同步逻辑,确保状态一致
内容的提问来源于stack exchange,提问作者Schauhi
相关产品推荐
相关产品推荐

