My character is moving but not so smoothly

my player is moving a fixed position which is what I want however it teleports there

        if (Input.GetKeyDown("d"))
        {
            transform.Translate(new Vector3(1, 0, 0));
        }
       
        if (Input.GetKeyDown("a"))
        {
            transform.Translate(new Vector3(-1, 0, 0));
        }

        if (Input.GetKeyDown("w"))
        {
            transform.Translate(new Vector3(0, 0, 1));
        }

a little help

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public enum SIDE {Left, Mid, Right}


public class playermove : MonoBehaviour
{
    public SIDE m_side = SIDE.Mid;
    float NewXpos = 0f;
    [HideInInspector]
    public bool SwipeLeft, SwipeRight;
    public bool Swipeup, Swipedown;
    public float JumpPower = 7f;
    private float y;
    public float XValue;
    public bool Injump;
    public bool InRoll;
    private CharacterController m_char;
    private float x;
    public float speeddodge;
    private float ColHight;
    private float ColCenterY;
    float FwdSpeed = 30f;
   

    void Start()
    {
        m_char = GetComponent<CharacterController>();
        ColHight = m_char.height;
        ColCenterY = m_char.center.y;
        transform.position = Vector3.zero;
    }
    void Update()
    {
        SwipeLeft = Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.LeftArrow);
       
        SwipeRight = Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.RightArrow);
        Swipeup = Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.UpArrow);
        Swipedown = Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.DownArrow);
        if (SwipeLeft)
        {
            if(m_side == SIDE.Mid)
            {
                NewXpos = -XValue;
                m_side = SIDE.Left;
            }else if(m_side == SIDE.Right)
            {
                NewXpos = 0;
                m_side = SIDE.Mid;
            }
        }
        else if (SwipeLeft)
        {
            if (m_side == SIDE.Left)
            {
                NewXpos = -XValue + -2;
                m_side = SIDE.M_Left;
            }
            else if (m_side == SIDE.Left)
            {
                NewXpos = -XValue;
                m_side = SIDE.Left;
            }
        }
        else if (SwipeRight)
        {
            if (m_side == SIDE.Mid)
            {
                NewXpos = XValue;
                m_side = SIDE.Right;
            }
            else if (m_side == SIDE.Left)
            {
                NewXpos = 0;
                m_side = SIDE.Mid;
            }
        }
        x = Mathf.Lerp(x, NewXpos, Time.deltaTime * speeddodge);
        Vector3 MoveVector = new Vector3(x - transform.position.x, y * Time.deltaTime, FwdSpeed * Time.deltaTime); ;
        m_char.Move(MoveVector);
        Jump();
        Roll();

    }
    public void Jump()
    {
        if (m_char.isGrounded)
        {
          Injump = false;
            if (Swipeup)
            {
                y = JumpPower;
                Injump = true;

            }
        }
        else
        {
            y -= JumpPower * 2 * Time.deltaTime;
            if (m_char.velocity.y < 2f)
            {

            }

        }
    }
    internal float RollCounter;
    public void Roll()
    {
        RollCounter -= Time.deltaTime;
        if(RollCounter <= 0)
        {
            RollCounter = 0f;
            m_char.center = new Vector3(0, ColCenterY, 0);
            m_char.height = ColHight;
            InRoll = false;
        }
        if (Swipedown)
        {
            RollCounter = 0.2f;
            y -= 10f;
            m_char.center = new Vector3(0, ColCenterY/2f, 0);
            m_char.height = ColHight/2f;
            InRoll = true;
            Injump = false;
          

        }
    }
}

I want it to move a little smoothly so ill send a video here and it just teleports I just want it to move slowly

Your character is teleporting because the calculation you’re applying does not take the concept of time into account.
What you need is to calculate the new position each frame / physics frame instead of the arbitrary amount you’re adding each cycle.

try something like this

      if (Input.GetKeyDown("w"))
        {
               transform.Translate(new Vector3(0, 0, 1) * Time.deltaTime);
        }

in your update cycle instead.

thx I’ll try that

GetKeyDown only returns true on the frame it was pressed - hence it will only trigger once. Use GetKey instead.

“Returns true while the user holds down the key identified by name.”

transform.Translate(Vector3.forward * Time.deltaTime * movementSpeed);

I want to use GetKeyDown because I want my character to move somwhere each time I tap so 20 units every time I tap wasd I just want it to move smoothly each time I hit wasd

Then your issue is slightly more complex. You want to take a single input within a frame and translate it to smooth movement, right? This means you’re going to have to do something over x seconds.

Linear interpolate between two points (the starting position and ending position)

public static Vector3 Lerp(Vector3 a, Vector3 b, float t);

But you’re probably going to have to trigger it within a coroutine.

Something like this should move the player forward 1 unit linearly interpolated over 45 frames.

public class ExampleClass : MonoBehaviour
{
    public int interpolationFramesCount = 45;
    int elapsedFrames = 0;

    private bool hasReachedDestination;
    private bool isMoving;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            if (!isMoving)
            {
                isMoving = true;
            }
        }

        if (isMoving)
        {
            if (!hasReachedDestination)
            {
                StartCoroutine(Move());
            }
        }
    }

    private IEnumerator Move()
    {
        float interpolationRatio = (float)elapsedFrames / interpolationFramesCount;

        Vector3 interpolatedPosition = Vector3.Lerp(0, 0, 0, 0, 0, 1, interpolationRatio);

        if (elapsedFrames < interpolationFramesCount)
        {
            elapsedFrames = elapsedFrames + 1;
        }
        else
        {
            hasReachedDestination = true;
            isMoving = false;
            elapsedFrames = 0;
        }

    }
}

you could also use a slightly different method

public class ExampleClass : MonoBehaviour
{
    // Transforms to act as start and end markers for the journey.
    public Transform startMarker;
    public Transform endMarker;

    // Movement speed in units per second.
    public float speed = 1.0F;

    // Time when the movement started.
    private float startTime;

    // Total distance between the markers.
    private float journeyLength;

    void Start()
    {
        // Keep a note of the time the movement started.
        startTime = Time.time;

        // Calculate the journey length.
        journeyLength = Vector3.Distance(startMarker.position, endMarker.position);
    }

    // Move to the target end position.
    void Update()
    {
        // Distance moved equals elapsed time times speed..
        float distCovered = (Time.time - startTime) * speed;

        // Fraction of journey completed equals current distance divided by total distance.
        float fractionOfJourney = distCovered / journeyLength;

        // Set our position as a fraction of the distance between the markers.
        transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fractionOfJourney);
    }
}

thx Ill try that

ok I have a couple errors

PlayerController.Move(): not all code paths return a value

no overload for method Lerp takes 7 arguments

Vector3 interpolatedPosition = Vector3.Lerp(0, 0, 0, 0, 0, 1, interpolationRatio);

Yeah I forgot about this. You need to pass it a starting transform and an end transform.

This might work for moving forward.

Vector3 interpolatedPosition = Vector3.Lerp(transform.position, Vector3.forward, interpolationRatio);

if they press “a”

Vector3 interpolatedPosition = Vector3.Lerp(transform.position, Vector3.left, interpolationRatio);

“d”

Vector3 interpolatedPosition = Vector3.Lerp(transform.position, Vector3.right, interpolationRatio);

If that doesn’t work you are going to need to take the current position and add an arbitrary distance on yourself for the end position (maybe something like this). but you would have to account for which direction you are going.

destination = transform.position + new Vector3(transform.position.x, transform.position.y, transform.position.z + 1)

alright ill try that but what about the Move() thing it says it needs to return a value is it just because of the error or is that another problem

The error was because of this

Vector3 interpolatedPosition = Vector3.Lerp([B]__0, 0, 0, 0, 0, 1__[/B], interpolationRatio);

It’s incorrect syntax. Look at the error you posted:

“no overload for method Lerp takes 7 arguments”

It thinks you are trying to pass 7 arguments when it needs to be 3.

transform.position will return a value in the format of (X, X, X)

Vector3.forward is shorthand for (0, 0, 1).

Vector3 interpolatedPosition = Vector3.Lerp(transform.position, Vector3.forward, interpolationRatio);

ok so there is another error for the IEnumerator Move() I am a little new to unity so I do not know what the error means do I have to add a return value or

oh yeah that was my mistake again. Coroutines expect a return (either null or WaitForSeconds)

oh I was just about to do that thank you

ok so there are no errors however the character does not move the interpolated position variable is not used is it? that could be a problem

I might also just try a for loop and see if that works

also I will show you the code here

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public int interpolationFramesCount = 45;
    int elapsedFrames = 0;

    private bool hasReachedDestination;
    private bool isMoving;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            if (!isMoving)
            {
                isMoving = true;
            }
        }

        if (isMoving)
        {
            if (!hasReachedDestination)
            {
                StartCoroutine(Move());
            }
        }
    }

    private IEnumerator Move()
    {
        float interpolationRatio = (float)elapsedFrames / interpolationFramesCount;

        Vector3 interpolatedPosition = Vector3.Lerp(transform.position, Vector3.forward, interpolationRatio);

        if (elapsedFrames < interpolationFramesCount)
        {
            elapsedFrames = elapsedFrames + 1;
        }
        else
        {
            hasReachedDestination = true;
            isMoving = false;
            elapsedFrames = 0;
        }

        yield return null;

    }
}

the character also does not move is there something I did wrong or am I just stupid and not noticing the obvious

Not sure. It can sometimes be difficult as I just wrote it without testing. The best thing to do would be to use debug log to check each step is actually being called.

For example, debug log something after the w key is pressed, then debug log something else just before isMoving is set to true… then debug log something just before the coroutine starts… then debug log something in the coroutine.

This should indicate where the problem is.

You need to reason through the code.

If you press W it sets isMoving true.

Then if isMoving is true it starts a coroutine.

The next frame in Update() (which is where you put this) it will AGAIN start ANOTHER coroutine.

Why will it do that? Because iMoving is still true!

You do not clear isMoving until the elapsed time has passed.

None of this will ever work properly the way this is architected. You absolutely do not need a coroutine, and you CERTAINLY do not want a fresh one started every frame.

I’m not sure what you are trying to do but this sounds like SUPER SUPER SUPER simple stuff, covered by literally THOUSANDS of Youtube character movement tutorials out there. I suggest you set this project aside and go legitimately work through two or three very simple movement tutorials and get familiar with the different approaches to doing this stuff. Otherwise you are going to thrash endlessly with this stuff.

ALSO, feel free to take a look around the movement examples in my proximity_buttons package. Don’t use them in your code until you understand them. They’re really simple, honest.

proximity_buttons is presently hosted at these locations:

https://bitbucket.org/kurtdekker/proximity_buttons

2 Likes