You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从键盘输入迁移至UI按钮:玩家移动与动画状态异常问题排查

问题修复方案

问题根源

  1. 无法再次跑动:停止移动时错误地把moveSpeed赋值为0,这个全局变量被修改后,后续点击移动按钮时会一直用0值,自然跑不起来。
  2. 无法切换Idle动画:动画状态判断依赖moveSpeed而非玩家实际的水平速度,停止时moveSpeed还是初始的7f,所以始终判定为Walk状态。
  3. 冗余的动画更新: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 17:12:56