Search code examples
c#unity-game-engineunityscript

How to change lane smoothly


I am trying to achieve basic racing game. Infinite racing game, movement method like a subway surfers. I have a problem about changing lane. I dont want to teleport to other lane, I want to smoothly. I am newbee in unity, I have try Lerp method but it is not working.

using UnityEngine;
using System.Collections;

public class VehicleController : MonoBehaviour 
{
    public float drift;
    public Vector3 positionA;
    public Vector3 positionB;
    public Vector3 positionC;
    public Vector3 positionD;

    private Transform tf;
    private Rigidbody rb;
    private Vector3 vehiclePos;

    void Awake()
    {
        //rb = GetComponent<Rigidbody> ();
        tf = transform;
    }

    void Update()
    {
        vehiclePos = tf.position;

        if (Input.GetKey( KeyCode.Space ))
            DecreaseSpeed ();
        else
            IncreaseSpeed ();

        if (Input.GetKeyDown (KeyCode.A)) 
        {
            MoveToRight ();
            Debug.Log( "Move to Right!" );
        }

        if (Input.GetKeyDown (KeyCode.D)) 
        {
            MoveToLeft ();
            Debug.Log( "Move to Left!" );
        }
    }

    void FixedUpdate()
    {
        tf.Translate (Vector3.forward * speed * Time.deltaTime);//My Movement Method.
    }

    void MoveToLeft()
    {
        if (vehiclePos.position.x == positionA.x)
            vehiclePos = Vector3.Lerp (vehiclePos.position, positionB, Time.deltaTime * drift);
    }

    void MoveToRight()
    {
        if (vehiclePos.position.x == positionB.x)
            vehiclePos = Vector3.Lerp (vehiclePos.position, positionA, Time.deltaTime * drift);
    }
}

Solution

  • First: Don't use == for position.x, since it's a floating-point (decimals) value and in this case it would be very rare for it to return "true". Here's some info about comparing floats.

    Second: It doesn't look like you're connecting your actual position with vehiclePos anywhere. transform.position is what you want there.

    Third: Input.GetAxis() is a cleaner way to deal with direction input. Instead of specifically calling out each button you can deal with just one float value between -1 and 1. It will also let you reconfigure the keys easily.

    Fourth: In an infinite runner it is better to have the world move towards your character and camera than to have the character and camera actually move forward. Floating point numbers get less precise as you move further away from zero, so you should have your action take place relatively close to the world origin (0,0,0) point if you can.

    If you want to press the button once to change lanes, you should keep an integer variable that saves which lane you're currently in. If you press LEFT you subtract one, and if you press RIGHT you add one. You should also add a check to make sure it stays within the desired range.

    Then in Update() you just need to ALWAYS Lerp towards that X value. You can use Mathf.Lerp to lerp only one variable at a time if you want.

    public int laneNumber = 0;
    public int lanesCount = 4;
    bool didChangeLastFrame = false;
    public float laneDistance = 2;
    public float firstLaneXPos = 0;
    public float deadZone = 0.1f;
    public float sideSpeed = 5;
    
    void Update() {
        //"Horizontal" is a default input axis set to arrow keys and A/D
        //We want to check whether it is less than the deadZone instead of whether it's equal to zero 
        float input = Input.GetAxis("Horizontal");
        if(Mathf.Abs(input) > deadZone) {
            if(!didChangeLastFrame) {
                didChangeLastFrame = true; //Prevent overshooting lanes
                laneNumber += Mathf.roundToInt(Mathf.Sign(input));
                if(laneNumber < 0) laneNumber = 0;
                else if(laneNumber >= lanesCount) laneNumber = lanesCount - 1;
            }
        } else {
            didChangeLastFrame = false;
            //The user hasn't pressed a direction this frame, so allow changing directions next frame.
        }
    
        Vector3 pos = transform.position;
        pos.x = Mathf.Lerp(pos.x, firstLandXPos + laneDistance * laneNumber, Time.deltaTime * sideSpeed);
        transform.position = pos;
    }
    

    You could likely just use this code as-is, but I suggest you look it over and try to figure out an understanding of how and why it works. A newbie today who always seeks to improve their skill can do something amazing next week. Hope this helps. :)