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

Unity3D墙跳移动问题:乘Time.deltaTime角色无移动,移除则瞬移

墙跳平滑移动解决方案

你的问题根源在于直接在碰撞触发事件里调用_controller.Move():

  • 加Time.deltaTime时,OnControllerColliderHit只在碰撞瞬间触发一次,乘以deltaTime后移动量太小,玩家看起来完全没动
  • 不加的话,一次性把整个跳跃距离移完,自然会出现瞬移

正确的做法是把墙跳的「状态标记」和「移动执行」分开,用每帧执行的逻辑来处理平滑移动:

步骤1:调整变量,记录墙跳状态

添加几个变量跟踪墙面接触状态和墙跳速度:

[SerializeField] float slideForce = 3f;
[SerializeField] float wallJumpHeight = 3f;
[SerializeField] float wallJumpRange = 3f;
[SerializeField] float wallJumpGravity = 9.8f;

// 新增变量
private bool isTouchingWall;
private Vector3 wallNormal;
private Vector3 _movementVelocity;
private CharacterController _controller;

private void Awake()
{
    _controller = GetComponent<CharacterController>();
}

步骤2:在碰撞事件里标记墙面状态

只在碰到墙时记录墙面方向,不直接处理移动:

private void OnControllerColliderHit(ControllerColliderHit hit)
{
    // 检测是否碰到垂直墙面(y轴法线接近0)
    if (Mathf.Abs(hit.normal.y) < 0.3f)
    {
        isTouchingWall = true;
        wallNormal = hit.normal;
        Debug.DrawRay(hit.point, hit.normal, Color.red, 1.25f);
    }
    else
    {
        // 没碰到墙时重置状态
        isTouchingWall = false;
    }
}

步骤3:在Update里处理跳跃输入

检测到跳跃键且触墙时,计算墙跳速度:

private void Update()
{
    bool jumpPressed = Keyboard.current.spaceKey.isPressed || 
                      (Gamepad.current != null && Gamepad.current.buttonSouth.isPressed);

    if (jumpPressed && isTouchingWall)
    {
        // 沿用你原来的垂直速度计算逻辑
        float verticalVelocity = Mathf.Sqrt(wallJumpHeight * wallJumpRange * wallJumpGravity);
        // 组合水平(沿墙面法线)和垂直速度
        _movementVelocity = wallNormal.normalized * wallJumpRange + new Vector3(0, verticalVelocity, 0);
        Debug.DrawRay(transform.position, wallNormal, Color.yellow, 1.25f);
    }

    // 持续施加重力
    _movementVelocity.y -= wallJumpGravity * Time.deltaTime;
}

步骤4:在FixedUpdate里执行平滑移动

用固定帧更新应用移动,保证平滑和物理稳定:

private void FixedUpdate()
{
    if (_movementVelocity.magnitude > 0)
    {
        // 每帧应用速度乘以deltaTime,实现平滑移动
        _controller.Move(_movementVelocity * Time.deltaTime);
        // 落地后重置速度
        if (_controller.isGrounded)
        {
            _movementVelocity = Vector3.zero;
        }
    }
}

关键说明

  • 把移动逻辑放到FixedUpdate里,它是固定时间间隔执行的,能避免帧率波动导致移动不流畅
  • 碰撞事件只负责「检测是否触墙」,不直接移动,让移动的控制权回到每帧更新的逻辑里
  • 用_movementVelocity存储当前速度,每帧叠加重力后再乘以Time.deltaTime调用Move,就能实现自然平滑的墙跳效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:42:53