c# - 如何实现 lerp 以实现平滑运动

标签 c# unity3d game-development

我只想通过 lerp 实现 x 轴上的移动对象以获得平滑移动。

这是我需要的图片

enter image description here

我不知道如何对这段代码实现 lerp 以获得这些值之间的平滑移动,它现在可以工作但是它传送玩家并且这不是我想要实现的平滑移动

这是我传送玩家的工作代码:

void Start()
{

}


void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        Vector3 desiredPos = new Vector3(transform.position.x + 1.5f, transform.position.y, transform.position.z);
        transform.position = desiredPos;
    }

    if (Input.GetMouseButtonDown(1))
    {
        Vector3 desiredPos = new Vector3(transform.position.x -1.5f, transform.position.y, transform.position.z);
        transform.position = desiredPos;
    }
}

我想实现这个,但我不知道该怎么做。当我将所有代码放入更新时,播放器甚至都不会移动。只有当我从文档中复制粘贴所有代码时,它才对我有用,但是我如何将时间从开始方法移动到更新并始终做同样的事情来实现玩家在左右移动时的平滑移动我真的不知道请帮助我......

这是有效的代码,但我不知道如何针对我的示例更改它..

https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html

最佳答案

有多种方法。我不会使用Translate因为这让你在这里几乎没有控制权,而是例如MoveTowards这确保你最后没有过度射击。将此用于具有给定 moveSpeed 的线性移动:

// set move speed in Units/seconds in the Inspector
public float moveSpeed = 1f;

private Vector3 desiredPos;
private bool isMoving;

private void Update()
{
    if (!isMoving && Input.GetMouseButtonDown(0))
    {
        desiredPos = transform.position + Vector3.right * 1.5f;
        isMoving = true;
    }

    if (!isMoving && Input.GetMouseButtonDown(1))
    {
        desiredPos = transform.position - Vector3.right * 1.5f;
        isMoving = true;
    }

    if(isMoving)
    {
        transform.position = Vector3.MoveTowards(transform.position, desiredPos, moveSpeed * Time.deltaTime);

        // this == is true if the difference between both
        // vectors is smaller than 0.00001
        if(transform.position == desiredPos)
        {
            isMoving = false;

            // So in order to eliminate any remaining difference
            // make sure to set it to the correct target position
            transform.position = desiredPos;
        }
    }
}

或者按照您的要求使用 Vector3.Lerp比如

// a factor between 0 and 1
[Range(0, 1)] public float lerpFactor;

...

transform.position = Vector3.Lerp(transform.position, desiredPos, lerpFactor);

lerpFactor 必须是 01 之间的值,在我们的例子中 0 表示对象从不移动,1 它直接跳转到目标位置。换句话说,将它设置得越接近 0,它到达目标的速度就越慢,将它设置得越接近 1,它到达目标的速度就越快。

很多人这样做是为了获得“平稳”的运动,但实际发生的是,例如如果您为 lerpFactor 设置 0.5,则对象的每一帧都将放置在当前位置和目标位置之间的中间。

这看起来有点平滑,开始时移动非常快,结束时非常非常慢......但是:它实际上从未真正到达目标位置,只是变得非常慢。

对于您的情况,这很好,因为无论如何我们使用 == with a precision of 0.00001 比较当前位置和目标位置.人们只需要记住 Lerp 是如何工作的。

但是有了这个,你将无法控制移动速度和持续时间。


如果你想要更多的整体控制(就像我一样)我建议使用 Coroutine (这不是绝对必要的,您也可以在 Update 中执行相同的操作,但在我看来,Coroutines 更易于维护和跟踪)。

无论距离多远,您都可以始终固定持续时间进行平滑的缓入和缓出运动

// set desired move duration in seconds
public float moveDuration = 1;

private bool isMoving;

privtae void Update()
{
    if (!isMoving && Input.GetMouseButtonDown(0))
    {
        StartCoroutine(transform.position + Vector3.right * 1.5f, moveDuration);
    }

    if (!isMoving && Input.GetMouseButtonDown(1))
    {
        StartCoroutine(transform.position - Vector3.right * 1.5f, moveDuration);
    }
}

private IEnumerator Move(Vector3 targetPosition, float duration)
{
    if(isMoving) yield break;

    isMoving = true;

    var startPosition = transform.position;
    var passedTime = 0f;

    do
    {
        // This would move the object with a linear speed
        var lerpfactor = passedTime / duration;

        // This is a cool trick to simply ease-in and ease-out
        // the move speed 
        var smoothLerpfactor = Mathf.SmoothStep(0, 1, lerpfactor);

        transform.position = Vector3.Lerp(startPosition, targetPosition, smoothLerpfactor);

        // increase the passedTime by the time 
        // that passed since the last frame
        passedTime += Time.deltaTime;

        // Return to the main thread, render this frame and go on
        // from here in the next frame
        yield return null;

    } while (passedTime < duration);

    // just like before set the target position just to avoid any
    // under shooting
    transform.position = targetPosition;

    isMoving = false;
}

并且您仍然可以扩展此示例以将 dtsnace 考虑在内,例如

var actualDuration = duration * Vector3.Distance(startPosition, targetPosition);

然后以后到处都使用 actualDuration

关于c# - 如何实现 lerp 以实现平滑运动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56640470/

相关文章:

c# - 单击前更改 Bootstrap 模式上的标签文本

c# - 进度条无法正常工作

c# - Unity 4.6+ 通过脚本创建文本

Java JProgressBar 使用图像

game-engine - 检测敌人是否被子弹击中

game-development - 开始游戏编程基础

c# - 使用正则表达式 C# 获取包含特定单词的整行

c# - 在 C# 中解密使用 RSA 在 iPhone 上加密的内容时遇到问题

unity3d - 从鼠标点击位置获取变换

c# - 在 Android 上的 Unity 中从 C++ DLL 访问 StreamingAssets 资源