【问题标题】:Smooth Lerp movement?平滑 Lerp 运动?
【发布时间】:2018-09-27 02:26:41
【问题描述】:

目前它是我的脚本,用于将玩家移动到场景周围。怎样才能让它顺利移动?

void FixedUpdate()
{
    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)
    {
        transform.position += movement * Time.fixedDeltaTime;
        transform.LookAt(transform.position + movement);
    }

}

【问题讨论】:

  • 你看过Vector3.MoveTowards或Vector3.Lerp吗?两者都有平滑运动的例子......
  • 它的运动有什么不顺畅的地方?与您想要的结果相比,您当前的问题是什么?我只是想确定我了解运动的哪个部分不“顺利”。

标签: c# unity3d


【解决方案1】:
  1. 创建一个速度向量:

    Vector3 velocity = Vector3.zero;

  2. 将您的运动矢量添加到速度:

    velocity += movement;

  3. 将速度添加到实际位置:

    transform.position += velocity;

  4. 通过随着时间的推移降低速度来平滑速度:

    velocity *= 0.975f;

【讨论】:

  • 代码很简单,哪一部分没有意义?
【解决方案2】:

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

因此,在此示例中,您可以看到角色如何以每帧不同的量向前跳跃,并且您无法保证游戏将以何种帧速率运行,因此最终可能会变得更糟。

不过,有几种方法可以让你的角色平稳移动。

  1. 将您的代码放入 Update() 循环而不是 FixedUpdate() 循环中,这将移动每个渲染帧的角色位置。除此之外,您可以将移动速度乘以 Time.deltaTime,这是自上一帧渲染以来的时间(也就是自上次运行 Update() 并移动角色以来的时间)

  2. 使用 Vector3.Lerp(..)/Quaterion.Lerp(..) 或 Vector3.MoveTowards(..)/Quaternion.RotateToward(..) 使用乘以 Time.deltaTime 的时间/步长值来插入角色移动,以保持其平稳移动与游戏帧率有关。

  3. 如果你的角色有一个刚体组件,那么你可以简单地将刚体插值设置为插值,然后通过调用移动你的角色:

    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 上的本指南。

【讨论】:

    【解决方案3】:

    首先,如果您希望代码执行每一帧,您需要将代码放入 Update() 方法中。 FixedUpdate 根据项目设置以固定间隔调用(您可以在编辑 -> 项目设置 -> 时间 -> 固定时间步长中更改它)。通常 FixedUpdate() 用于物理相关的东西。

    【讨论】:

      【解决方案4】:

      在 FixedUpdate 中移动它应该非常顺利。当然,Vector3.Lerp 可以帮助您的运动,但首先为什么它不流畅?

      我只能猜测您的相机在正常的更新脚本中,或者存在一些刚体插值。您需要了解的有关平滑运动的所有信息都在此处进行了说明:

      http://www.kinematicsoup.com/news/2016/8/9/rrypp5tkubynjwxhxjzd42s3o034o8

      【讨论】:

        【解决方案5】:

        您可以使用Vector3.Lerp(...)。

        试试这个代码:

        float smoothTime = 0.125f;
        Vector3 newPos;
        
        ...
        
        void FixedUpdate()
        {
            bool running = Input.GetKey(KeyCode.LeftShift);
            float h = Input.GetAxisRaw("Horizontal");
            float v = Input.GetAxisRaw("Vertical");
        
            movement = ((running) ? runSpeed : walkSpeed) * new Vector3(h, 0.0f, v).normalized;
        
            //Set the new position
            if(movement.magnitude > 0)
                newPos = transform.position + movement;
        
            // Use Vector3.Lerp(...)
            transform.position = Vector3.Lerp(transform.position, newPos, smoothTime);
            transform.LookAt(transform.position);
        
        }
        

        希望对你有帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-10-12
          • 1970-01-01
          • 2021-03-03
          • 1970-01-01
          • 2018-09-30
          • 1970-01-01
          • 2012-01-07
          相关资源
          最近更新 更多