简体   繁体   中英

Unity linear Interpolation for smooth 3D movement

So I am trying to create a forward running game(something like Temple Run) but I want my character to move from side-to-side smoothly and not just teleport. I tried to use Vector3.Lerp() but I just can't wrap my head around how it works.

Here is what I tried but the character just teleports

    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;
                }
            }

This example is just for moving to the left.

You are right in thinking to use a Vector3.Lerp to gradually interpolate between a start and end value. However, the implementation and use case does not quite fit what you are attempting to do.

As you are only changing a single axis of the movement, I would not use Vector3.Lerp , instead use Mathf.Lerp as you are only changing the x-axis of your position.

You are using a while loop instead of Update meaning the program will stick inside of that loop until the process has finished. The reason it is immediately moving to the next point is due to your if conditional. You are subtracting a value of 2.5 from your current then continually checking if your current position x is greater than the new, which is always true. It will immediately set your current position to your new position, then break out of your while loop. One other issue is you are using GetKeyDown , which only occurs the one frame the user clicks the key. Lerps are meant to be completed over time, not immediately.

Instead of placing your logic inside of Update , I would consider moving the actual movement to a special function called a Coroutine . Think of Courtines as a process that is completed over multiple frames, jumping back to where it left off in the previous frame. Coroutines are very powerful but please read into the documentation before overusing them to get a firm understanding of what they do.

Now for the implementation. I am not entirely sure of your lane setup but will assume you have 3 lanes similar to the other infinite run track games. I will keep the input detection inside of Update , and will allow the player to jump from side to side from the middle, but not off the track nor jump while jumping already. I will also be using time not speed to control the jump of the Lerp , you can easily change it to speed if you like.

[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;
}

As I was not exactly sure how your implementation was done, I had a few assumptions about lanes and other general setups. The answer is quite generic so it can be tweaked to what you need. You can also swap the input back to GetKeyDown if you like, the only reason I used it is so you get arrow keys as well as wasd input.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM