Help with endless runner switching lanes. <Solved>

Hey guys,

I’m trying to implement a simple mechanic in C# for my endless runner game. I want the player to switch between three lanes. The middle (Which is the starting position) and left and right.

I want it so the player cannot move right twice or left twice. I have attached a picture of my code so far.

You know, you can use code tags to post code in a nice formatted manner… rather than an image.

Code tags are better.
After that, what’s the problem with the code? A quick glance at your pic makes me think the idea is good. Is it still going right when it’s already in the right lane?

Using your code, you just need to define a simple boundary, then move the character as you were.
Example: (will move your character along the z-axis positions. Note: not tested, but you get the point)

public float MoveDistance = 150;

private int playerPosition = 1;

private void Update()
{
    // if D key is pressed down
    if (Input.GetKeyDown(KeyCode.D))
    {
        if (playerPosition < 2)
        {
            // move the player along the positive Z axis
            transform.Translate(0, 0, MoveDistance);
            // increment the player position
            playerPosition++;
        }
    }
    // if A key is pressed down
    else if (Input.GetKeyDown(KeyCode.A))
    {
        if (playerPosition > 0)
        {
            // move the player along the negative Z axis
            transform.Translate(0, 0, -MoveDistance);
            // decrement the player position
            playerPosition--;
        }
    }
}

Thank you. I appreciate your help. This code sort of works. It’s hard to explain but the player after a while moves more than 150f’s and falls off the edge. This issue happens at random.

That does seem pretty odd. Is it at all possible that there is some other piece of code that is responsible for those random events?

 void Swipes()
    {

        Vector2 distance = endPos - startPos;

        if (Mathf.Abs(distance.x) > Mathf.Abs(distance.y))
        {
            Debug.Log("Horizontal Swipe");

            if (distance.x > 0)
            {


                   Debug.Log("Right Swipe");

               if (playerPos < 2)
                {

                    if (flip == true)

                    {

                        transform.Translate(new Vector3(0f, 0f, -moveDistance) * Time.deltaTime);  // move right
                        playerPos++;



                    }

                    else

                    {


                        transform.Translate(new Vector3(0f, 0f, moveDistance) * Time.deltaTime);  // move right
                        playerPos++;

                    }



                }






            }

            if (distance.x < 0)
            {
                Debug.Log(" Left Swipe");

                if (playerPos >0)
                {

                    if (flip == true)

                    {

                        transform.Translate(new Vector3(0f, 0f, moveDistance) * Time.deltaTime);  // move right
                        playerPos--;

                    }

                    else

                    {


                        transform.Translate(new Vector3(0f, 0f, -moveDistance) * Time.deltaTime);  // move right
                        playerPos--;

                    }


                }
           

                 




               





            }


           
        }

        else if (Mathf.Abs(distance.x) < Mathf.Abs(distance.y))
        {
            Debug.Log(" Vertical Swipe");

            if (distance.y > 0)
            {
                Debug.Log("Up Swipe");

                if (Grounded())
                {
                   

                        myRigidbody.velocity = new Vector3(myRigidbody.velocity.x, JumpForce);
                  
                  

                }

               
                

            }
           
            if (distance.y < 0)
            {
                Debug.Log(" Down Swipe");

               if (!Grounded())
               {

                   
                 StartCoroutine(RotateAround(Vector3.left, 180.0f, 0.3f));

                

                    if (flip == false)
                    {

                        flip = true;
                    }

                    else
                        flip = false;

                   }





            }


        }



    }

That is my code. I have a mechanic where the cube flips 180 degrees. So the flip if statement stops the controls from inverting.

Okay, well a quick question. When you click a key (‘A’ or ‘D’ from your previous post), the code above doesn’t multiply by Time.DeltaTime. It’s just 1 move… Your code, most recently posted, does though. Besides, one is swiping and one is with Keycodes… You needn’t multiply by Time.deltaTime. I am a little surprised that is moving the full way as it is.

I’m new to programming. The first code I added was so people didn’t have to read lengthy amounts of confusing code. So what are you saying? I should remove Time.deltaTime?

Time.deltaTime is for when you want your “action” to be equivalent to a frame’s time in seconds. For example, if you were moving while a key was held down, and you wanted to calculate how far it should go at a speed of ‘3’ , you’d multiply your speed by the time of frame (ie: deltaTime). This way it’s doing a ‘slice’ of time for the duration the key is held down.
Your situation, as it stands (from what I’ve read) looks like, you swipe/key and the move happens. It’s 1 click/swipe = 1 move :slight_smile:
You do not need the deltaTime. I can see how the code from before works, but I still hope we can resolve the issue of it falling off sometimes, at random. From just the code I saw, that doesn’t make sense. :slight_smile:

Edit: Btw, it’s appreciated that you tried to snip the code to avoid lengthy, unrelated stuff. I wish everyone did that; only include what’s needed … too little/much is not good :wink:

Thank you. I have concluded that my programming knowledge is not good enough to implement the mechanic I want too. Therefore, I will try a different approach. I have too much code in my project so I can’t really post it here.

So instead i’m going use invisible walls to prevent the player from moving too far left or right. However, as it stands my player goes through the walls. I know this is because I need move my character using the rigid body and not transform.translate.

So what code would I need to move the player by the players rigid body?

transform.Translate(new Vector3(0f, 0f, -150) * Time.deltaTime);  // move right

Well, not sure that I conveyed the correct “message” if it made you afraid like that or wanting to add walls :slight_smile:
Just try removing the Time.deltaTime from those places.
And the only relevant code (if there is even anymore to show) is only anything that can change the player’s position.
Otherwise, I would just remove those few entries of deltaTime, save it & re-run the game and move around. You shouldn’t be falling off of anything (unless your path is somehow less wide at spots?)

It’s not that I ignored your question about moving a rigidbody, exactly, it’s just that in your case, I don’t think you need it (right now…).

I have removed Time.deltaTime and the issue improved but bugs still remain. As in every so often the cube will move more than 150 spaces or wont move in a certain direction etc.

The platform the player is running on is the same width from start to finish.

Give me a while to post all of the revelant code

Okay… :slight_smile:

Touch screen swipe functionality.

  if (Input.touchCount > 0)
        {

            Touch touch = Input.GetTouch(0);   // First touch

            if (touch.phase == TouchPhase.Began)
            {

                startTime = Time.time;   // Storing start time
                startPos = touch.position; // storing start position

            }

            else if (touch.phase == TouchPhase.Ended)  // Touch ended
            {
                endTime = Time.time;
                endPos = touch.position;

                swipeDistance = (endPos - startPos).magnitude;
                swipeTime = endTime - startTime;

                if (swipeTime < maxTime && swipeDistance > minSwipeDist)
                {

                    Swipes();


                }



            }

        }

The Swipes Function.

 void Swipes()
    {

        Vector2 distance = endPos - startPos;

        if (Mathf.Abs(distance.x) > Mathf.Abs(distance.y))
        {
            Debug.Log("Horizontal Swipe");

            if (distance.x > 0)
            {


                   Debug.Log("Right Swipe");

             

                    if (flip == true)

                    {
                   
                     if (playerPos < 2)
                    {

                        transform.Translate(new Vector3(0f, 0f, -moveDistance));  // move right
                        playerPos++;
                    }

                 

                    }

                    else

                    {

                      if (playerPos < 2)
                    {

                        transform.Translate(new Vector3(0f, 0f, moveDistance));  // move right while flipped
                        playerPos++;
                    }


                       
                    }

            }


            if (distance.x < 0)
            {
                Debug.Log(" Left Swipe");

               

                    if (flip == true)

                    {

                        if(playerPos > 0)
                    {
                        transform.Translate(new Vector3(0f, 0f, moveDistance));  // move left
                        playerPos--;
                    }

                      
                      

                    }

                    else

                    {
                    
                    if (playerPos >0)
                    {
                        transform.Translate(new Vector3(0f, 0f, -moveDistance));  // move left while flipped
                        playerPos--;

                    }

                       

                    }


               
           

                 




               





            }


           
        }

        else if (Mathf.Abs(distance.x) < Mathf.Abs(distance.y))
        {
            Debug.Log(" Vertical Swipe");

            if (distance.y > 0)
            {
                Debug.Log("Up Swipe");

                if (Grounded())
                {
                   

                        myRigidbody.velocity = new Vector3(myRigidbody.velocity.x, JumpForce);
                  
                  

                }

               
                

            }
           
            if (distance.y < 0)
            {
                Debug.Log(" Down Swipe");

               if (!Grounded())
               {

                   
                 StartCoroutine(RotateAround(Vector3.left, 180.0f, 0.3f));

                

                    if (flip == false)
                    {

                        flip = true;
                    }

                    else
                        flip = false;

                   }





            }


        }



    }

Coroutine for the cube flip

   IEnumerator RotateAround(Vector3 axis, float angle, float duration)
   {
        float elapsed = 0.0f;
        float rotated = 0.0f;
        while (elapsed < duration)
       {
           float step = angle / duration * Time.deltaTime;
           transform.RotateAround(transform.position, axis, step);
           elapsed += Time.deltaTime;
            rotated += step;
           yield return null;
       }
       transform.RotateAround(transform.position, axis, angle - rotated);
   }

This code increases the movement speed over time

        if (transform.position.x > speedCount)
        {
            speedCount += speedIncrease;

            speedIncrease = speedIncrease * speedMultiplier; // Milestones further apart

            moveSpeed = moveSpeed * speedMultiplier;
        }

This is my game manager script. This code restarts the level. Putting the player back to where the player started insteading of reloading the scene.

using UnityEngine;
using System.Collections;


public class GameManager : MonoBehaviour {

   

    public PlayerController1 thePlayer;
    private Vector3 PlayerStartPoint;

    private ScoreManager theScoreManager;
   


    void Start () {

        PlayerStartPoint = thePlayer.transform.position;

        theScoreManager = FindObjectOfType<ScoreManager>();

    } // start End
   
   
    void Update () {


    }  // update end




    public void RestartGame()
    {

        StartCoroutine("RestartGameCo");

    }


    public IEnumerator RestartGameCo()
    {

        theScoreManager.scoreIncreasing = false;    // Simple Save

        thePlayer.gameObject.SetActive(false);

        yield return new WaitForSeconds(1.0f);
        thePlayer.transform.position = PlayerStartPoint;

        thePlayer.gameObject.SetActive(true);

        theScoreManager.scoreCount = 0;
        theScoreManager.scoreIncreasing = true;


    }


}

Didn’t see where moveSpeed was used at all, but that was unrelated to the previous posts. Just thought I’d mention it :slight_smile:
So, with this code, are you still falling off the side (going too far)?
If you are, I apologize, I’m just not seeing where that can be happening. Do you ever set a moveSpeed/velocity to the rigidbody for its movement, at all(not including the jump)?

This piece of codes simply makes the player continuously move forward.

  myRigidbody.velocity = new Vector3(moveSpeed, myRigidbody.velocity.y);

The bug is a lot less common now that I have removed deltatime. I’m trying to find a pattern by playing the game to where it fails

https://www.dropbox.com/s/rgl9qpm8sdq7u1s/Stopfallingofthesides.apk?dl=0
Thats a download link to my game :slight_smile: Very small file for android

I don’t have any easy means to setup an android game to look at :slight_smile:
I’m glad that the bug is a lot less common. If you find a pattern, feel free to reply if you don’t find the solution at the same time :wink:
If you continue to be stumped and you feel inclined to post a small unity package, i could open that and look at it.

It looks to me you are mixing your input with your movement. Most endless runners will make you wait to change lanes until you finish. As well as not changing lanes instantly which is what your code is doing now. You detect the lane change input and then in one frame you move them 150 units. You should be moving the 150 units over X frames. And then when you have finished moving the 150 you start looking for input again.

So You need to detect a lane change input and then set some a variable indicating you are changing lanes.
If this variable is true, you do not read the input for change lanes and instead you do your movement translate function. Using the * time.deltatime. You keep doing this until you have moved the next lane.
This can be based on a distance or a time and speed or lots of other ways.
Once you have reached the other lane, then you set your player pos value to the new lanes value.
You also set the changing lane variable back to false. So the character stops translating and you start looking for input again.

This is a very basic control setup and it can be expanded on from their. Like aborting the change lane, or hitting an obstacle from the side etc.

That’s a good comment, @daxiongmao . I’ve been keeping that thought in the back of my mind the whole time, as far as things go for moving between. However, since he was going too far one side or the other, it seemed okay to try to understand what is wrong with that… because it shouldn’t be happening anyways :slight_smile: