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

Unity新输入系统实现角色平滑移动问题求助

问题分析与解决

你的代码里有几个核心问题导致平滑移动失效:

  • 回调时机错误:把移动逻辑放在performed回调里,导致代码只在输入触发的单帧执行,而平滑需要每帧持续更新,不是只有输入变化时才运行。
  • 目标速度计算错误:你写的targetVelocityX = _velocity.x * _playerDetails.Acceleration * Time.deltaTime完全偏离逻辑,目标速度应该是输入方向乘以最大移动速度(MoveClamp)。
  • 手动速度累加与SmoothDamp冲突:先手动给_velocity.x加加速度值,之后又用SmoothDamp,等于手动硬改速度覆盖了平滑效果。
  • 输入归零直接硬停:输入为0时直接把_velocity.x设为0,没有平滑减速过程。

修正后的SmoothDamp实现

首先把移动逻辑移到FixedUpdate(物理帧)里,输入回调只负责存储输入值,不要把核心逻辑绑在输入触发事件上:

private Vector2 _input;

// 绑定输入回调,仅负责更新输入值
private void OnEnable()
{
    _inputAction.Player.Movement.performed += ctx => _input = ctx.ReadValue<Vector2>();
    _inputAction.Player.Movement.canceled += ctx => _input = Vector2.zero;
}

private void OnDisable()
{
    _inputAction.Player.Movement.performed -= ctx => _input = ctx.ReadValue<Vector2>();
    _inputAction.Player.Movement.canceled -= ctx => _input = Vector2.zero;
}

private void FixedUpdate()
{
    Movement();
}

private void Movement()
{
    // 计算目标速度:输入方向 × 最大移动速度
    float targetVelocityX = _input.x * _playerDetails.MoveClamp;
    
    // SmoothDamp平滑过渡,区分地面/空中的平滑时间
    _velocity.x = Mathf.SmoothDamp(_velocity.x, targetVelocityX, ref _velocityXSmoothing, 
        _controller.CollisionInfos.Below ? _playerDetails.AccelerationTimeGrounded : _playerDetails.AccelerationTimeAirborne);

    // 重力应用与移动执行
    _velocity.y += _gravity * Time.fixedDeltaTime;
    _controller.Move(_velocity * Time.fixedDeltaTime);

    Debug.Log("_velocity.x: " + _velocity.x);
}

其他平滑实现方式

1. 手动加速度/减速度控制(无需SmoothDamp)

这种方式手感更可控,完全自定义加速、减速速率:

private void Movement()
{
    float targetSpeed = _input.x * _playerDetails.MoveClamp;
    // 区分地面/空中的加速、减速速率
    float accelRate = _controller.CollisionInfos.Below ? _playerDetails.GroundAccel : _playerDetails.AirAccel;
    float decelRate = _controller.CollisionInfos.Below ? _playerDetails.GroundDecel : _playerDetails.AirDecel;

    // 加速逻辑:当前速度未达目标时,逐步逼近
    if (Mathf.Abs(_velocity.x) < Mathf.Abs(targetSpeed))
    {
        _velocity.x = Mathf.MoveTowards(_velocity.x, targetSpeed, accelRate * Time.fixedDeltaTime);
    }
    // 减速逻辑:输入归零或速度超目标时,逐步减速到0
    else
    {
        _velocity.x = Mathf.MoveTowards(_velocity.x, 0, decelRate * Time.fixedDeltaTime);
    }

    _velocity.y += _gravity * Time.fixedDeltaTime;
    _controller.Move(_velocity * Time.fixedDeltaTime);
}

需要在PlayerDetails中新增GroundAccel、AirAccel、GroundDecel、AirDecel参数来适配不同场景的手感。

2. 线性平滑(Vector2.Lerp)

适合追求简单线性过渡的场景,速率需和时间关联避免帧率影响:

private void Movement()
{
    float targetVelocityX = _input.x * _playerDetails.MoveClamp;
    // 地面平滑系数更高(响应更快),空中更低(更飘)
    float smoothFactor = _controller.CollisionInfos.Below ? 0.12f : 0.06f;
    // 乘以60让速率不受帧率波动影响
    _velocity.x = Mathf.Lerp(_velocity.x, targetVelocityX, smoothFactor * Time.fixedDeltaTime * 60);

    _velocity.y += _gravity * Time.fixedDeltaTime;
    _controller.Move(_velocity * Time.fixedDeltaTime);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 14:05:39