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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 09:36:19