使用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
相关产品推荐
相关产品推荐

