【问题标题】:Unity linear Interpolation for smooth 3D movement用于平滑 3D 运动的统一线性插值
【发布时间】:2021-06-12 14:29:03
【问题描述】:

所以我正在尝试创建一个向前运行的游戏(类似于 Temple Run),但我希望我的角色能够顺畅地左右移动,而不仅仅是传送。我尝试使用Vector3.Lerp(),但我无法理解它是如何工作的。

这是我尝试过的,但角色只是传送

    void Update()
    {
        if(Input.GetKeyDown("a")&&lane-1>0)
        {
            lane-=1;
            shouldMove = true;
            Vector3 newpos= new Vector3(transform.position.x -2.5f, transform.position.y, transform.position.z);
            while (shouldMove)
            {
                transform.position = Vector3.Lerp(transform.position, newpos, 0.1f * Time.deltaTime);
                if(transform.position.x>=newpos.x)
                {
                    shouldMove = false;
                    transform.position = newpos;
                }
            }

这个例子只是为了向左移动。

【问题讨论】:

    标签: c# unity3d linear-interpolation


    【解决方案1】:

    您认为使用Vector3.Lerp 在开始值和结束值之间逐渐插值是正确的。但是,实现和用例并不完全适合您尝试做的事情。

    由于您只更改运动的单个轴,因此我不会使用Vector3.Lerp,而是使用Mathf.Lerp,因为您只是更改位置的 x 轴。

    您使用的是while 循环而不是Update,这意味着程序将停留在该循环内,直到该过程完成。它立即移动到下一点的原因是由于您的if 条件。您正在从当前位置中减去 2.5 的值,然后不断检查当前位置 x 是否大于新位置,这始终是正确的。它会立即将您的当前位置设置为新位置,然后跳出您的 while 循环。另一个问题是您正在使用GetKeyDown,它只发生在用户单击键的一帧。 Lerps 应该随着时间的推移完成,而不是立即完成。

    我不会将您的逻辑放在Update 中,而是考虑将实际运动转移到一个称为Coroutine 的特殊函数中。将Courtines 视为一个在多个帧上完成的过程,并跳回到它在前一帧中停止的位置。 Coroutines 非常强大,但请在过度使用它们之前仔细阅读文档以深入了解它们的作用。

    现在开始实施。我不完全确定你的车道设置,但假设你有 3 条车道,类似于其他无限跑道游戏。我会将输入检测保留在Update 中,并允许玩家从中间左右跳跃,但不会偏离轨道,也不会在跳跃时跳跃。我也会用时间而不是速度来控制Lerp的跳跃,你可以很容易地把它改成速度。

    [SerializeField] private float TimeForJump = 0.25f;
    [SerializeField] private float JumpOffset = 2.5f;
    
    // I am assuming your setup for lanes is -1 | 0 | 1
    private int lane = 0;
    private Coroutine PlayerJumping = null;
    
    void Update()
    {
        // no need to detect input if we are already jumping
        if(PlayerJumping == null)
        {
            // instead of 'a' and 'd' you can use GetAxis to allow for arrow key and wasd support
            // it is also an easy way to determine direction when adding or subtracting for a goal location
            float horzInput = Input.GetAxis("Horizontal");
    
            if (horzInput < 0 && lane > -1)
            {
                PlayerJumping = StartCoroutine(Jump(-1));
                lane--;
            }
            else if(horzInput > 0 && lane < 1)
            {
                PlayerJumping = StartCoroutine(Jump(1));
                lane++;
            }
        }
    
        // simulating your movement
        transform.position = new Vector3(transform.position.x, transform.position.y + 0.1f, transform.position.z);
    }
    
    /// <summary>
    /// Horizontally have the player jump
    /// </summary>
    private IEnumerator Jump(float direction)
    {
        // store our current position
        float currentXPos = transform.position.x;
    
        // our goal position
        float goalXPos = currentXPos + (direction * JumpOffset);
    
        // timer for how long it has passed since we started the jump
        float jumpTimer = 0.0f;
    
        // continue the lerp for the time we have left
        while(jumpTimer <= TimeForJump)
        {
            transform.position = new Vector3(Mathf.Lerp(currentXPos, goalXPos, jumpTimer / TimeForJump), transform.position.y, transform.position.z);
    
            // increment the time that has passed
            jumpTimer += Time.deltaTime;
            yield return null;
        }
    
        // set our position directly in case of floating point errors
        transform.position = new Vector3(goalXPos, transform.position.y, transform.position.z);
    
        // set the coroutine to null so we can jump again
        PlayerJumping = null;
    }
    

    由于我不确定您的实施是如何完成的,因此我对车道和其他一般设置有一些假设。答案非常通用,因此可以根据您的需要进行调整。如果您愿意,您也可以将输入交换回GetKeyDown,我使用它的唯一原因是您可以获得箭头键以及wasd 输入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-11
      • 2023-02-16
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2014-11-10
      • 2013-10-08
      • 1970-01-01
      相关资源
      最近更新 更多