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

使用BoxCast做地面检测时Unity跳跃动画异常问题求助

安卓无尽跑酷游戏跳跃动画异常与跳跃高度问题修复

问题背景

开发安卓无尽跑酷平台游戏时,使用BoxCast实现地面检测出现以下问题:

  • 跳跃动画频繁被打断,表现异常
  • 首次跳跃有时高度远超预期
    Animator挂载在Player对象的子物体模型上,此前用OnCollisionEnter结合标签检测时动画正常,但希望避免标签检测方案。

问题代码

using UnityEngine;

public class Player : MonoBehaviour
{
    [Header("Move Settings")]
    [SerializeField] float jumpSpeed = 5f;
    [SerializeField] float normalSpeed = .2f;
    [SerializeField] float slowSpeed = .01f;
    [SerializeField] float slowAnimationSpeed = .02f;

    [Header("CastBox Settings")]
    public Vector3 boxsize;
    public float maxDistance;
    public LayerMask layerMask;

    //Cached References
    private Rigidbody playerRigidBody;
    private Animator playerAnimator;

    //Properties
    private bool canDoubleJump = false;
    private Vector3 jumpInput;
    private float moveSpeed;


    private void Awake()
    {
        playerRigidBody = GetComponent<Rigidbody>();
        playerAnimator = GetComponentInChildren<Animator>();

    }

    private void Start()
    {
        moveSpeed = normalSpeed;
        jumpInput = Vector3.up * jumpSpeed;
    }

    private void FixedUpdate()
    {
        GroundCheck();
        Move();
    }

    private void OnJump()
    {
        if (GroundCheck())
        {
            Jump();
            canDoubleJump = true;
            playerAnimator.SetBool("Jump", true);

        }
        else if (!GroundCheck() && canDoubleJump)
        {
            Jump();
            playerAnimator.SetBool("DoubleJump", true);
            canDoubleJump = false;
        }
    }

    private void Jump()
    {
        playerRigidBody.AddForce(jumpInput, ForceMode.Impulse);

    }

    private void Move()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            OnJump();
        }

        if (Input.GetKey(KeyCode.LeftShift) && GroundCheck())
        {
            SlowSpeed();
        }
        else
        {
            NormalSpeed();
        }
        transform.position += Vector3.right * moveSpeed;

    }

    private void SlowSpeed()
    {
        moveSpeed = slowSpeed;
        playerAnimator.speed = slowAnimationSpeed;
    }

    private void NormalSpeed()
    {
        moveSpeed = normalSpeed;
        playerAnimator.speed = 1;
    }

    bool GroundCheck()
    {
        if (Physics.BoxCast(transform.position, boxsize,
            -transform.up, transform.rotation, maxDistance, layerMask))
        {
            playerAnimator.SetBool("Jump", false);
            playerAnimator.SetBool("DoubleJump", false);
            return true;
        }
        else
        {
            return false;
        }

    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawCube(transform.position - transform.up * maxDistance, boxsize);
    }
}

修复方案

1. 分离地面检测与动画控制逻辑

当前GroundCheck每帧检测到地面就直接重置动画布尔值,会导致动画被频繁打断。改为仅在落地状态切换时更新动画:

  • 新增isGrounded变量缓存地面状态,避免重复检测触发动画变更
  • 仅当isGrounded从false变为true时,才重置跳跃动画

修改后的核心逻辑:

private bool isGrounded; // 新增状态缓存变量

private void FixedUpdate()
{
    bool newGroundedState = GroundCheck();
    // 仅在落地瞬间重置动画
    if (!isGrounded && newGroundedState)
    {
        playerAnimator.SetBool("Jump", false);
        playerAnimator.SetBool("DoubleJump", false);
    }
    isGrounded = newGroundedState;
    Move();
}

// 修改GroundCheck,只返回检测结果,不处理动画
bool GroundCheck()
{
    return Physics.BoxCast(transform.position, boxsize,
        -transform.up, transform.rotation, maxDistance, layerMask);
}

2. 修复跳跃触发的重复检测问题

原OnJump中多次调用GroundCheck,可能因帧同步问题导致重复施加力,引发超预期跳跃高度。改用缓存的isGrounded状态判断:

private void OnJump()
{
    if (isGrounded)
    {
        Jump();
        canDoubleJump = true;
        playerAnimator.SetBool("Jump", true);
    }
    else if (canDoubleJump)
    {
        Jump();
        playerAnimator.SetBool("DoubleJump", true);
        canDoubleJump = false;
    }
}

3. 优化BoxCast检测参数

  • 调整boxsize适配Player模型的碰撞范围,避免检测范围过大或过小
  • 设置maxDistance为略大于Player与地面的最小间隙(如0.1f),防止提前或延迟检测地面
  • 确认layerMask仅包含地面层,避免误检测其他碰撞体

4. 修复移动逻辑的物理同步问题

原Move中直接修改transform.position会与Rigidbody的物理模拟冲突,导致跳跃位置异常。改用Rigidbody控制水平移动:

private void Move()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        OnJump();
    }

    if (Input.GetKey(KeyCode.LeftShift) && isGrounded)
    {
        SlowSpeed();
    }
    else
    {
        NormalSpeed();
    }
    // 用Rigidbody控制水平移动,保持物理同步
    playerRigidBody.velocity = new Vector3(moveSpeed, playerRigidBody.velocity.y, 0);
}

内容的提问来源于stack exchange,提问作者inanakmugan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 20:03:13