How to make lane switching in mobile endless runner using UI buttons?

hey,

I am currently working on an endless runner game for smartphone where user can switch lanes by pressing UI buttons (one for left and another one for the right).
Currently, I am able to make the player move left right by pressing buttons like in this video:
link:frowning:https://www.youtube.com/watch?v=_zyx8lCIb5A)

but I want to create two-three lanes where user can move right left on those lanes like in temple run.

here is the code I have written so far:

 [SerializeField] float moveSpeed = 10000f;
 [SerializeField] float Padding=100f;
 [SerializeField] float increment = 20f;

 float axis = 20f;
 float directionX,xMin,xMax;
 Rigidbody2D rb;

 private void Start()
 {
     SetUpMoveBoundaries();
     rb = GetComponent();
 }

 private void Update()
 {
     Move();
 }

 private void SetUpMoveBoundaries()
 {
     Camera gameCamera = Camera.main;
     xMin = gameCamera.ViewportToWorldPoint(new Vector3(0, 0, 0)).x+Padding;
     xMax = gameCamera.ViewportToWorldPoint(new Vector3(1, 0, 0)).x-Padding;
 }

 private void Move()
 {
     directionX = CrossPlatformInputManager.GetAxis("Horizontal") * moveSpeed * Time.deltaTime;
     rb.velocity = new Vector2(directionX, 0);
     transform.position = new Vector2(Mathf.Clamp(transform.position.x, xMin, xMax),                                               transform.position.y);
 } }

EDIT: I do see in your code that you are not using ViewportToWorldPoint() properly.


Since you were not passing a 3rd parameter to the ViewportToWorldPoint method it doesn’t matter what you pass to the first parameter (x position), it will always return the camera x, y and z position. So you needed to pass the last parameter instead of leaving it 0.0f. It is the distance the camera is in world space from the plane that you want to translate the point to. Therefore, you should be passing the distance from your player to the camera:


float dist = (Camera.main.transform.position - player.transform.position).magnitude;

Here is some tested code that I believe does what you want. I’m not sure if you wanted the dampening effect, but it is easy enough to remove if not:


[SerializeField] float moveSpeed = 10000f;
    [SerializeField] float Padding = 2f;
    [SerializeField] float increment = 20f;
    [SerializeField] int currentLane = 2; //start in the middle lane

    int nextLane;
    float[] lanes = new float[3];
    float targetXPos;
    float axis = 20f;
    float speed;
    float maxChangeLaneSpeed = 10.0f;
    float laneSeparation;
    float directionX, xMin, xMax;
    Rigidbody2D rb;
    bool changingLane = false;

    private void Start()
    {
        speed = maxChangeLaneSpeed;
        SetUpMoveBoundaries();
        rb = GetComponent<Rigidbody2D>();
        targetXPos = lanes[currentLane - 1];
        nextLane = currentLane;
    }

    private void Update()
    {
        Move();
    }

    private void SetUpMoveBoundaries()
    {
        Camera gameCamera = Camera.main;
        float dist = (gameCamera.transform.position - transform.position).magnitude;
        xMin = gameCamera.ViewportToWorldPoint(new Vector3(0, 0, dist)).x + Padding;
        lanes[0] = xMin;
        xMax = gameCamera.ViewportToWorldPoint(new Vector3(1, 0, dist)).x - Padding;
        lanes[2] = xMax;
        laneSeparation = Mathf.Abs(xMax - xMin)* 0.5f;
        lanes[1] = xMin + laneSeparation;
        transform.position = new Vector3(lanes[currentLane - 1], transform.position.y, transform.position.z);
    }

    private void Move()
    {
        if (Input.GetKey(KeyCode.A))
        {
            directionX = -1.0f;
        }
        else if(Input.GetKey(KeyCode.D))
        {
            directionX = 1.0f;
        }
        else
        {
            directionX = 0.0f;
        }

        if (directionX > 0.0f && currentLane < 3 && currentLane == nextLane)
        {
            targetXPos = lanes[currentLane];
            nextLane = currentLane + 1;
            speed = maxChangeLaneSpeed;
        }
        else if (directionX < 0.0f && currentLane > 1 && currentLane == nextLane)
        {
            targetXPos = lanes[currentLane - 2];
            nextLane = currentLane - 1;
            speed = maxChangeLaneSpeed;
        }
        if (nextLane > currentLane)
        {
            rb.velocity = new Vector2(speed, 0);

            if (targetXPos <= transform.position.x)
            {
                DestinationReached();
            }
        }
        else if (nextLane < currentLane)
        {
            rb.velocity = new Vector2(-speed, 0);

            if (targetXPos >= transform.position.x)
            {
                DestinationReached();
            }
        }
        //transform.position = new Vector2(Mathf.Clamp(transform.position.x, xMin, xMax), transform.position.y);

        if (Mathf.Abs(targetXPos - transform.position.x) < laneSeparation)
        {
            float speedRegulator = Mathf.Abs(targetXPos - transform.position.x) / laneSeparation;
            float minSpeedRegulator = 0.2f;

            if(speedRegulator > minSpeedRegulator)
            {
                speed = maxChangeLaneSpeed * (Mathf.Abs(targetXPos - transform.position.x) / laneSeparation);
            }
            else
            {
                speed = maxChangeLaneSpeed * minSpeedRegulator;
            }
        }
    }

    void DestinationReached()
    {
        currentLane = nextLane;
        rb.velocity = Vector2.zero;
        transform.position = new Vector3(targetXPos, transform.position.y, transform.position.z);
    }

I did not use the CrossPlatformInputManager as I got some errors when importing the package, but you can implement them easy enough. At the moment, left and right is A and D. Cheers