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

