FixedUpdate() 函数按 Time.fixedDeltaTime 定义的每个固定间隔运行一次(您可以通过 TimeManager 进行设置 (Fixed Timestep ) 或在运行时直接将 Time.fixedDeltaTime 设置为新值。
因为您要以固定的间隔移动角色的位置和旋转,所以根据帧速率,角色会以较低的帧速率移动很多,或者每隔几帧就以较高的帧速率移动。
例如,固定时间刻度为 0.02 秒,游戏以每秒 30 帧的帧速率运行(也就是每 0.033 秒渲染一次)您的游戏将这样做:
- [Time: 0.020s] Character position += 0.02
- [Time: 0.033s] Render frame with character at position 0.02
- [Time: 0.040s] Character position += 0.02
- [Time: 0.060s] Character position += 0.02
- [Time: 0.066s] Render frame with character at position 0.06
- [Time: 0.080s] Character position += 0.02
- [Time: 0.099s] Render frame with character at position 0.08
- [Time: 0.100s] Character position += 0.02
- [Time: 0.120s] Character position += 0.02
- [Time: 0.133s] Render frame with character at position 0.12
因此,在此示例中,您可以看到角色如何以每帧不同的量向前跳跃,并且您无法保证游戏将以何种帧速率运行,因此最终可能会变得更糟。
不过,有几种方法可以让你的角色平稳移动。
-
将您的代码放入 Update() 循环而不是 FixedUpdate() 循环中,这将移动每个渲染帧的角色位置。除此之外,您可以将移动速度乘以 Time.deltaTime,这是自上一帧渲染以来的时间(也就是自上次运行 Update() 并移动角色以来的时间)
使用 Vector3.Lerp(..)/Quaterion.Lerp(..) 或 Vector3.MoveTowards(..)/Quaternion.RotateToward(..) 使用乘以 Time.deltaTime 的时间/步长值来插入角色移动,以保持其平稳移动与游戏帧率有关。
-
如果你的角色有一个刚体组件,那么你可以简单地将刚体插值设置为插值,然后通过调用移动你的角色:
characterRigidbody.MovePosition(wantedPosition);
characterRigidbody.MoveRotation(wantedRotation);
作为现有变换动作的替代品(将代码保持在 FixedUpdate() 循环内)
但请注意,继续在 FixedUpdate() 中调用 Input.* 会比需要更多地轮询它们,因此您可能希望将它们移到 Update() 中,如果您决定拆分移动代码和输入监听代码做这个。 (我开发安卓游戏,所以也许在 PC 上这不值得担心,但可能仍然值得改变)
该问题的直接代码块答案可能只是尝试一下,这是解释 1 和 2 的组合:
// How long in seconds will it take the lerps to finish moving into position
public float lerpSmoothingTime = 0.1f;
private Vector3 targetPosition;
private Quaternion targetRotation;
void Update()
{
bool running = Input.GetKey(KeyCode.LeftShift);
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
bool isWalking = Mathf.Abs(h) + Mathf.Abs(v) > 0;
movement = ((running) ? runSpeed : walkSpeed) * new Vector3(h, 0.0f, v).normalized;
if (isWalking)
{
targetPosition += movement * Time.deltaTime;
targetRotation = Quaternion.LookRotation(targetPosition - transform.position);
}
// Always lerping as if we suddenly stopped the lerp as isWalking became false the stop would be sudden rather than smoothly moving into position/rotation
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime / lerpSmoothingTime);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime / lerpSmoothingTime);
}
如果您想详细了解平滑移动的物体、了解 lerps 或只是想了解更多示例,请查看how to fix movement stutter in Unity 上的本指南。