Unity Character Controller跳跃异常 动画延迟、落地悬停问题
Unity角色跳跃逻辑问题诊断与修复
两类异常的根因与修复方案
1. 跳跃触发后动画延迟1秒播放
核心原因不是代码调用时序,而是Animator状态机配置错误:
- 从待机/移动状态到跳跃状态的过渡勾选了Has Exit Time,且退出时间设为了1秒左右,必须等当前状态动画播到指定退出时间,才会响应
jump触发器参数切换动画,和代码里什么时候调用SetTrigger无关 - 次要原因是
jump触发器参数可能存在残留:之前帧触发的trigger没有被状态机消费,新设置的trigger会排队等待,导致触发延迟
修复操作:
- 打开Animator窗口,选中所有指向跳跃状态的过渡线,取消勾选Has Exit Time,将过渡时长(Transition Duration)设为0.1~0.2秒,保证trigger触发后立即切换动画
- 在
Enter方法中设置jump触发器前,先调用ResetTrigger("jump")清除残留参数
2. 落地前地面上方悬停、提前触发地面检测
核心原因是代码执行时序错误+Character Controller原生检测特性共同导致:
- 代码中
PhysicsUpdate的执行顺序错误:先调用Move执行位移,再累加重力,最后读取isGrounded状态,导致isGrounded读取的是上一次位移的结果,和当前帧角色位置不匹配 - Character Controller的
isGrounded检测依赖组件的Skin Width参数,当角色下落距离地面小于Skin Width值时就会返回true,这时候角色还没真正接触地面,如果此时直接切换落地状态并重置垂直速度,就会卡在半空悬停 - 原代码没有给落地检测加垂直速度判断,角色上升阶段蹭到碰撞体也可能误判为落地
修复操作:
- 调整
PhysicsUpdate的执行顺序:先累加重力,再执行位移,位移完成后再做落地检测 - 落地判定增加垂直速度校验:只有当角色垂直速度小于0(处于下落状态)且
isGrounded为true时,才判定为真正落地 - 判定落地后给一个小的向下位移,强制角色贴合地面,消除Skin Width导致的悬浮间隙
- 检查Character Controller组件的
Skin Width参数,设置为角色半径的1/10左右(比如半径0.3时设为0.03~0.05),不要过大
修复后的核心代码片段:
public override void Enter() { base.Enter(); grounded = false; gravityValue = character.gravityValue; jumpHeight = character.jumpHeight; playerSpeed = character.playerSpeed; gravityVelocity.y = 0; character.animator.SetFloat("speed", 0); // 清除残留触发器,避免动画延迟 character.animator.ResetTrigger("jump"); character.animator.SetTrigger("jump"); Jump(); } public override void PhysicsUpdate() { base.PhysicsUpdate(); if (!grounded) { // 先累加重力,保证重力作用于本次位移 gravityVelocity.y += gravityValue * Time.deltaTime; velocity = character.playerVelocity; airVelocity = new Vector3(input.x, 0, input.y); velocity.y = 0f; airVelocity.y = 0f; // 执行位移 character.controller.Move(gravityVelocity * Time.deltaTime + (airVelocity * character.airControl + velocity * (1 - character.airControl)) * playerSpeed * Time.deltaTime); // 落地判定:下落状态+控制器检测到地面,避免上升段误判 grounded = character.controller.isGrounded && gravityVelocity.y < 0; // 落地后强制贴地,消除Skin Width导致的悬停 if (grounded) { gravityVelocity.y = -2f; character.controller.Move(Vector3.down * (character.controller.skinWidth + 0.01f)); } } }
内容的提问来源于stack exchange,提问作者Draken Forge37
相关产品推荐
相关产品推荐

