从键盘输入迁移至UI按钮:玩家移动与动画状态异常问题排查
问题修复方案
问题根源
- 无法再次跑动:停止移动时错误地把
moveSpeed赋值为0,这个全局变量被修改后,后续点击移动按钮时会一直用0值,自然跑不起来。 - 无法切换Idle动画:动画状态判断依赖
moveSpeed而非玩家实际的水平速度,停止时moveSpeed还是初始的7f,所以始终判定为Walk状态。 - 冗余的动画更新:FixedUpdate内多次调用
UpdateAnimationState,容易导致状态判断混乱。
修正后的代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class UiPlayerControl : MonoBehaviour { private Rigidbody2D rb; private BoxCollider2D coll; private Animator anim; [SerializeField] private LayerMask jumpableGround; [SerializeField] private float moveSpeed = 7f; [SerializeField] private float jumpForce = 14f; private bool isMovingRight, isMovingLeft; private enum MovementState { Player_Idle, Player_Walk, Player_Jump, Player_Falling } private void Start() { rb = GetComponent<Rigidbody2D>(); coll = GetComponent<BoxCollider2D>(); anim = GetComponent<Animator>(); } private void FixedUpdate() { // 处理移动逻辑 if (isMovingRight) { rb.velocity = new Vector2(moveSpeed, rb.velocity.y); transform.localScale = new Vector2(1, transform.localScale.y); } else if (isMovingLeft) { rb.velocity = new Vector2(-moveSpeed, rb.velocity.y); transform.localScale = new Vector2(-1, transform.localScale.y); } else { // 停止时直接清零水平速度,不修改moveSpeed rb.velocity = new Vector2(0, rb.velocity.y); } // 键盘跳跃保留(可根据需求移除) if (Input.GetButtonDown("Jump") && IsGrounded()) { rb.velocity = new Vector2(rb.velocity.x, jumpForce); } // 统一更新动画状态 UpdateAnimationState(); } // UI按钮调用:向右移动 public void MoveRight() { isMovingRight = true; isMovingLeft = false; } // UI按钮调用:向左移动 public void MoveLeft() { isMovingLeft = true; isMovingRight = false; } // UI按钮调用:跳跃 public void Jump() { if (IsGrounded()) { rb.velocity = new Vector2(rb.velocity.x, jumpForce); } } // UI按钮调用:停止移动 public void StopMoving() { isMovingRight = false; isMovingLeft = false; } private void UpdateAnimationState() { MovementState state; // 根据实际刚体水平速度判断是否行走 if (Mathf.Abs(rb.velocity.x) > 0.1f) { state = MovementState.Player_Walk; } else { state = MovementState.Player_Idle; } // 覆盖跳跃/下落状态 if (rb.velocity.y > 0.1f) { state = MovementState.Player_Jump; } else if (rb.velocity.y < -0.1f) { state = MovementState.Player_Falling; } anim.SetInteger("state", (int)state); } private bool IsGrounded() { return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, 0.1f, jumpableGround); } }
关键修改说明
- 保留原始移动速度:停止时直接设置
rb.velocity.x = 0,不再修改moveSpeed,确保后续点击移动按钮时能正常使用初始速度。 - 基于实际速度判断动画:用
Mathf.Abs(rb.velocity.x) > 0.1f来判断是否处于行走状态,停止时速度为0,自动切换到Idle。 - 优化移动逻辑:把移动判断改成
else if,避免左右移动同时触发;移除冗余的stop变量,简化状态管理。 - 统一动画更新:只在FixedUpdate末尾调用一次
UpdateAnimationState,避免重复判断导致的状态错误。 - 简化跳跃判断:去掉
rb.velocity.y == 0的判断,因为IsGrounded()已经能确保玩家在地面上。
内容的提问来源于stack exchange,提问作者Yusril
相关产品推荐
相关产品推荐

