d d doe
d d doe

Reputation: 125

Smooth Lerp movement?

Currently it is my script for movement the player to the around the scene. How can i make it smoothly move?

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

}

Upvotes: 7

Views: 5035

Answers (5)

Ehsan Mohammadi
Ehsan Mohammadi

Reputation: 1228

You can use Vector3.Lerp(...).

Try this code:

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

}

I hope it helps you.

Upvotes: 0

KYL3R
KYL3R

Reputation: 4073

Moving it in FixedUpdate should be very smooth. Sure, Vector3.Lerp could help with your movement, but why in the first place isn't it smooth?

I can only guess that you have your Camera in a normal Update Script or that there is some Rigidbody interpolation. All that you need to know about smooth motion is explained here:

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

Upvotes: 0

Sean McManus
Sean McManus

Reputation: 138

The FixedUpdate() function is ran every fixed interval as defined by Time.fixedDeltaTime (which you can either set via the TimeManager (Fixed Timestep) or at runtime by directly setting Time.fixedDeltaTime to a new value.

Because you are moving the character position and rotation on a fixed interval, depending on framerate the character will either move a lot with a lower framerate or only move every few frames with a higher framerate.

For example with a fixed timescale of 0.02 seconds and the game running at a framerate of 30 frames per second (aka rendering every 0.033 seconds) your game will be doing this:

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

So in this example you can see how the character would jump forward at different amounts per frame and you can't guarantee what framerate the game will be running at either so it could end up being worse.

There are a few ways to make your character move smoothly though.

  1. Put your code in an Update() loop instead of a FixedUpdate() loop, this will move the position of the character each rendered frame. Along with this you can multiply the movement speed by Time.deltaTime which is the time since the previous frame was rendered (aka time since Update() was last ran and the character was moved)

  2. Use Vector3.Lerp(..)/Quaterion.Lerp(..) or Vector3.MoveTowards(..)/Quaternion.RotateToward(..) using a time/step value multiplied by Time.deltaTime to interpolate the character movement keeping it moving smoothly in relation to the game framerate.

  3. If your character has a rigidbody component then you can simply just set the rigidbody interpolation to interpolate then move your character by calling:

    characterRigidbody.MovePosition(wantedPosition);
    characterRigidbody.MoveRotation(wantedRotation);
    

    As a replacement to your existing transform movements (keeping your code inside of the FixedUpdate() loop)

    But note that continuing to have your Input.* calls inside a FixedUpdate() is polling them more than needed so you might want to move them over into an Update() splitting the movement code and input listening code if you decide to do this. (I develop android games so maybe on PC this isn't worth worrying about as much, but probably still worth changing)

A direct code block answer to the question though could be to just try this, which is a combination of explanation 1 and 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);    
}

If you want to read up in more detail about smoothly moving objects, learning about lerps or just want more examples then check out this guide on how to fix movement stutter in Unity.

Upvotes: 4

denebiv
denebiv

Reputation: 71

First of all you need to put your code into Update() method if u want it to execute each frame. FixedUpdate is called at fixed intervals depend on project settings (you can change it in Edit -> Project Settings -> Time -> Fixed Timestep). Usualy FixedUpdate() is used for physics related stuff.

Upvotes: 0

Iggy
Iggy

Reputation: 4888

  1. Create a velocity vector:

    Vector3 velocity = Vector3.zero;

  2. Add your movement vector to velocity:

    velocity += movement;

  3. Add velocity to the actual position:

    transform.position += velocity;

  4. Smooth out velocity by reducing it over time:

    velocity *= 0.975f;

Upvotes: 11

Related Questions