[ SOLVED ] playerController - limit lane movements

Hi, I had the following basic code to lerp my player object between lanes, this worked well, however, it didn’t fit the final functionality that I’d like to achieve in my game. This code moves my player between 3 lanes, left, centre and right. However, there is no forward motion or ‘jump’ functionality :

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

public class playerController : MonoBehaviour {

    [Header("Player Properties")]
    public Rigidbody playerRigidbody;
    public float playerSpeed = 1.0f;
    public float yOffset = 0.5f;

    [Header("Lane Width Reference")]
    public float laneWidth = 1.5f;

    private bool inLaneLeft, inLaneRight, inLaneCentre = false;

    private Vector3 playerNewPos;

    void Start () {
        // Make sure our player character starts off in the centre lane
        inLaneCentre = true;
        playerNewPos = new Vector3(0, yOffset, 0);
        transform.position = playerNewPos;
    }

    void Update () {

        if (Input.GetKeyDown(KeyCode.LeftArrow)) {
            if(inLaneRight) {
                inLaneRight = false;
                inLaneCentre = true;
                // From inLaneRight to inLaneCentre
                playerNewPos = new Vector3(0, yOffset, 0);
            }
            else {
                if(inLaneCentre) {
                    inLaneCentre = false;
                    inLaneLeft = true;
                    // From inLaneCentre to inLaneLeft
                    playerNewPos = new Vector3(-laneWidth, yOffset, 0);
                }
            }
        }
        else {
            if (Input.GetKeyDown(KeyCode.RightArrow)) {
                if(inLaneLeft) {
                    inLaneLeft = false;
                    inLaneCentre = true;
                    // From inLaneLeft to inLaneCentre
                    playerNewPos = new Vector3(0, yOffset, 0);
                }
                else {
                    if(inLaneCentre) {
                        inLaneCentre = false;
                        inLaneRight = true;
                        // From inLaneCentre to inLaneRight
                        playerNewPos = new Vector3(laneWidth, yOffset, 0);
                    }
                }
            }
        }
        // Smoothly move from our players current position to the players new position over time
        transform.position = Vector3.Lerp(transform.position, playerNewPos, Time.deltaTime * 10);
    }
}

I have found some example code online more in tune with what I require, which I have amended somewhat, however, I’d like to implement the 3 lane functionality from the first script, so I am limited to only 3 lanes, the script below just lets me roam as far as I’d like in any direction, my question is, how to limit this to basically left, right and centre lanes only ? :

using UnityEngine;

public class PlayerControllerAMEND : MonoBehaviour {

    [Header("Player Properties")]
    public float playerSpeed = 5f;
    public float playerJumpHeight = 1f;
    public float changeLaneSpeed = 4f;
    public float gravity = 12f;

    [Header("Lane Properties")]
    public float laneWidth = 1.5f;
    private int laneIndex = 0;

    private CharacterController myCharacterController;
    private Vector3 velocity;

    private void Start()
    {
        myCharacterController = GetComponent<CharacterController>();
        laneIndex = 0;
    }

    private void Update()
    {
        Move();
    }

    private void Move()
    {
        if (Input.GetButtonDown("Horizontal")) {
            laneIndex += (int)Input.GetAxisRaw("Horizontal");
        }

        if (myCharacterController.isGrounded) {
            velocity = Vector3.forward * playerSpeed;

            if (Input.GetKeyDown(KeyCode.UpArrow)) {
                velocity.y = Mathf.Sqrt(2 * gravity * playerJumpHeight);
            }
        }  
        velocity.y -= gravity * Time.deltaTime;

        Vector3 moveAmount = velocity * Time.deltaTime;
        float targetX = laneIndex * laneWidth;
        float dirX = Mathf.Sign(targetX - transform.position.x);
        float deltaX = changeLaneSpeed * dirX * Time.deltaTime;

        // Correct for overshoot
        if (Mathf.Sign(targetX - (transform.position.x + deltaX)) != dirX) {
            float overshoot = targetX - (transform.position.x + deltaX);
            deltaX += overshoot;
        }
        moveAmount.x = deltaX;

        myCharacterController.Move(moveAmount);
    }
}

Solved… :smile:

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

public class playerController : MonoBehaviour {

    [Header("Player Properties")]
    public float playerSpeed = 5f;
    public float playerJumpHeight = 1f;
    public float changeLaneSpeed = 10f;
    public float gravity = 12f;

    [Header("Lane Properties")]
    public float laneWidth = 1.5f;
    private int laneIndex = 0;

    private CharacterController myCharacterController;
    private Vector3 velocity;

    bool isFalling = false;

    bool userInput = true;

    private void Start() {
        myCharacterController = GetComponent<CharacterController>();
        laneIndex = 0;
    }

    private void Update() {
        Move();
    }

    private void Move() {

        if (userInput == true ) {
           
            if (Input.GetKeyDown(KeyCode.LeftArrow)) {
                print ("Left");
                if (laneIndex == 0 || laneIndex == 1) {
                    laneIndex--;
                }
            }
            else if (Input.GetKeyDown(KeyCode.RightArrow)) {
                print ("right");
                if (laneIndex == 0 || laneIndex == -1) {
                    laneIndex++;
                }
            }
            else if (myCharacterController.isGrounded) {
                velocity = Vector3.forward * playerSpeed;

                if (Input.GetKeyDown(KeyCode.UpArrow)) {
                    velocity.y = Mathf.Sqrt(2 * gravity * playerJumpHeight);
                }
            }
        }

        if (transform.position.y < -1f && isFalling == false) {
            isFalling = true;
            userInput = false;
            print ("Falling");
        }

        velocity.y -= gravity * Time.deltaTime;

        Vector3 moveAmount = velocity * Time.deltaTime;
        float targetX = laneIndex * laneWidth;
        float dirX = Mathf.Sign(targetX - transform.position.x);
        float deltaX = changeLaneSpeed * dirX * Time.deltaTime;

        // Correct for overshoot
        if (Mathf.Sign(targetX - (transform.position.x + deltaX)) != dirX) {
            float overshoot = targetX - (transform.position.x + deltaX);
            deltaX += overshoot;
        }
        moveAmount.x = deltaX;

        myCharacterController.Move(moveAmount);
    }
}
1 Like

Sir, First of thanks for this code here because it has solved many problems occuring to me. And I want to take some permission from you that can i use this code logic in my ads and iap enabled android endless runner game. I mean that if you have any problems regarding your copyright then I will not use in my game. But if you think that a new game developer needs to be rise then please give me permission to use this code in my game.
The, TechSoft Station Team

@TechSoft_Station

Hi, Yes you can use the code in any way you want, I posted the solution publicly for anyone to use who may have had similar problems.

Good luck with your game ! :slight_smile:

Regards

Thanks! This helped me out with a little problem I was having