Przemek Stepien
Przemek Stepien

Reputation: 11

Vector3.Lerp in C# in unity doesn't move smoothly just snaps from one position to another

I'm making an endless runner like game where very in mechanics to android IronMan game. The player will be flying straight along the course and will be able to move left, right, up and down. I managed to split the screen in to 9 even sections and implement a little control system that recognizes where the player is and where he want's to move and if he/she is allowed to move there and I managed to get the player to move to desired location on the screen but instead of gradually travelling from one point to another the Game object just snaps from one position to another. Please find below my code for moving in one direction:

public class PlayerControl : MonoBehaviour
{

// Declare Control Input
public KeyCode moveL;
public KeyCode moveR;
public KeyCode moveU;
public KeyCode moveD;

// Set movement distance
private float verticalIncrement = 3.0f;
private float horizontalIncrement = 5.0f;

// Set initial internal position of the craft
private int laneNum = 1;
private int rowNum = 1;

// Declare player Game object
GameObject spaceCraft;

// Set input lock
bool pressLockOn = false;

// Use this for initialization
void Start()
{
    spaceCraft = GameObject.FindGameObjectWithTag("Player");
}

// Update is called once per frame
void Update()
{        
    if (Input.GetKeyDown(moveR))
    {
        if (laneNum < 2)
        {
            // Retrieve craft current position coordinates
            float craftPositionX = spaceCraft.transform.localPosition.x;
            float craftPositionY = spaceCraft.transform.localPosition.y;
            
            // Save craft's desired position coordinates as string for comparison
            string newCraftPositionString = (craftPositionX + horizontalIncrement) + "" + craftPositionY;

            // Declare target box position coordinates for comparison
            string targetPositionString = null;

            // Find desired target box based on player's location and button pressed
            for (int i = 0; i < Initialization.positionCubesArray.Length; i++)
            {
                for (int j = 0; j < Initialization.positionCubesArray[i].Length; j++)
                {
                    // Declare temp GameObject to store desired target box 
                    GameObject target = Initialization.positionCubesArray[i][j];

                    // Retrieve target box location coordinates
                    float boxPosX = target.GetComponent<Transform>().localPosition.x;
                    float boxPosY = target.GetComponent<Transform>().localPosition.y;

                    // Save target box's coordinates as string for comparison
                    boxPositionString = boxPosX + "" + boxPosY;
                    
                    // Check if craft's desired position matches found target
                    if (newCraftPositionString.Equals(targetPositionString))
                    {
                        // Set input lock on
                        pressLockOn = true;

                        // Move player's craft to desired location
                        spaceCraft.transform.localPosition = Vector3.Lerp(spaceCraft.transform.localPosition, target.transform.localPosition, 1f);                            

                        // Start coroutine to delay input lock for half a second
                        StartCoroutine(stopTime(0.5f));
                        
                        // Check if craft traveled to desired location
                        if ((craftPositionX + "" + craftPositionY).Equals(newCraftPositionString) )
                        {
                            // Update internal position of the craft
                            laneNum++;  
                        }
                    }
                }
            }
        }
    }
...
}

IEnumerator stopTime(float amount)
{       
    yield return new WaitForSeconds(amount);
    pressLockOn = false;
}

I've also tried with another approach following this tutorial:

https://www.youtube.com/watch?v=Zb7Th_H7bvw

But it wouldn't work either and wouldn't move my player at all as the journey fraction would always equal to 0. I also tried exporting the moving object logic out of the loop but with no effect either. Please find below updated code:

// Update is called once per frame
void Update()
{ 
    if (Input.GetKeyDown(moveR))
    {
        if (laneNum < 2)
        {
            // Declare target Dame object
            GameObject target;

            // Retrieve craft position coordinates
            float craftPositionX = spaceCraft.transform.localPosition.x;
            float craftPositionY = spaceCraft.transform.localPosition.y;

            // Retrieve desired craft's postiotn
            string newCraftPositionString = (craftPositionX + horizontalIncrement) + "" + craftPositionY;

            // Declare target box string for comparison
            string boxPositionString = null;

            // Declare initial temp i and j to export target game object from the loops
            int tempI = 0;
            int tempJ = 0;

            // Search for target game objects in 2D array
            for (int i = 0; i < Initialization.positionCubesArray.Length; i++)
            {
                // Setup found target flag
                bool foundTarget = false;
                for (int j = 0; j < Initialization.positionCubesArray[i].Length; j++)
                {
                    // Retrieve each target's coordinates
                    float boxPosX = Initialization.positionCubesArray[i][j].GetComponent<Transform>().localPosition.x;
                    float boxPosY = Initialization.positionCubesArray[i][j].GetComponent<Transform>().localPosition.y;

                    // Target coordinates string for comparison
                    boxPositionString = boxPosX + "" + boxPosY;

                    // Check if target's coordinates matches desired location's coordinates
                    if (newCraftPositionString.Equals(boxPositionString))
                    {                    
                        // Set temp i and j to export found target out off the loop
                        tempI = i;
                        tempJ = j;
                        print("Found Target\n " + tempI + " " + tempJ);
                        print("Target Postion: " + boxPositionString);

                        // Set found target flag to true
                        foundTarget = true;
                        
                        // Break inner loop
                        break;
                    }
                }

                // Break outter loop
                if (foundTarget)
                {
                    break;
                }
            }

            print("New Crafft Position: " + newCraftPositionString + "\nTarget Position: " + boxPositionString);


            // Again chack if target's coordinates matches desired location's coordinates
            if (newCraftPositionString.Equals(boxPositionString))
            {
                // Retrieve found target from 2D array with temp i and j found in 2D for-loop
                target = Initialization.positionCubesArray[tempI][tempJ];

                // Set input lock on
                pressLockOn = true;

                float startTime = Time.time;
                float totalDistance = Vector3.Distance(spaceCraft.transform.localPosition, target.transform.localPosition);
                float currentDuration = Time.time - startTime;
                float journeyFraction = currentDuration / totalDistance;

                print("Start time: " + startTime + " | Total Distance: " + totalDistance
                    + "\nCurrent Duration: " + currentDuration + " | Journey fraction: " + journeyFraction);
                spaceCraft.transform.localPosition = Vector3.Lerp(spaceCraft.transform.localPosition, target.transform.localPosition, journeyFraction);

                // Start coroutine to delay input lock
                StartCoroutine(stopTime(0.5f));

                // Update internal craft coordinates
                if ((craftPositionX + "" + craftPositionY).Equals(newCraftPositionString))
                {
                    laneNum++;
                }
            }
        }
    }

I've also tried moving startTime variable to Start method and currentDuration time to the start of the update method like in the tutorial and my player would move but not into desired position, it would only move very slightly but never reach the target and it would crash the whole moving "system".

Upvotes: 0

Views: 1615

Answers (2)

Przemek Stepien
Przemek Stepien

Reputation: 11

Ok, I fixed it and it's working. The code is a lot more clear now as well. The issue had to do with fact that I was pressing the button and the position was only being updated once. The code responsible for calling the Lerp method wasn't being called in the update method anymore.

Upvotes: 1

Gusman
Gusman

Reputation: 15151

Lerp will interpolate two values via a factor. Per example, if you Lerp between 0 to 20 with a factor of 0.5 the result will be 10, by 0 will be 0, by 1 will be 20 and so on.

Why I say that? Because in your code you just Lerp with a factor of 1.0f, that will just return the final value.

If you want a smooth interpolation you must "travel" from 0 to 1 on the factor at the desired speed.

Upvotes: 2

Related Questions