I need a way to create an infinite generator of random stages in my runner game

Hello, I am facing a problem in developing my runner game for mobile.

This problem is that I want to make a generator for infinite levels that do not end, like runner games, so that you know more about the thing I mean. I mean, I do not want to make infinite tiles. I just want to make a generator that creates stages. Whenever you complete a stage, he gives you another stage, but with different things, meaning the obstacle will be in a different place, and the money is in a different place, and so on, and I want automatically. I mean, whenever you complete a stage, he gives you another different stage, and changes the number of the stage or the number of the stage. For example, when I finish 1 stage, they are given a stage. Randomly, he writes number 2 and notes: I never want the stages to be the same.

Thank you

If you are developing in C# i made a pretty simple code for you. Remember to actually read the comments so you learn how to actually do it and dont just copy and paste it, write the whole thing yourself.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
  
public class LevelBuild : MonoBehaviour
{
    public GameObject tileObj; //attach the basic tile prefab to this
  
    public GameObject obstacleObj; //attach obstacle prefab to this
  
    public int levelLength; //stores the level length (basically the amount of rows there are)
  
    [SerializeField] List<Vector3> tilePosList = new List<Vector3>(); //List to store tile positions
  
    int currentTileID = 0; //Value to use to apply tile IDs to the list
  
    [SerializeField] List<int> tileIDList = new List<int>(); //List to store tile IDs
  
    int obstacleAmount; //Value for the amount of obstacles you want in the level
  
    int[] obstacleTile; //Stores the IDs of the tiles you want to spawn the obstacles on.
  
    // Start is called before the first frame update
    void Start()
    {
      
        levelLength = Random.Range(10, 20); //Generate random length for the level. The "10" is the minimum length for the level, and the "20" is the maximum. The length is basically how many "rows" of tiles there are.
  
  
        obstacleAmount = Random.Range(2, 6); //Generate random amount of obstacles
  
        obstacleTile = new int[obstacleAmount]; //Tell the obstacle tile array how many obstacles there should be.
  
        GenerateTiles(); //Generate the tiles
  
        AddObstacle(); //Generate the obstacles
  
    }
  
    Vector3 tilePos; //Acts as a temporary position for the tile while its being spawned(or something like that).
    void GenerateTiles() //Here is the level generation logic
    {
  
  
        for(int i = 0; i < levelLength; ) /*Loop for generating the tiles. This loop essentially generates rows, the Z position of the tiles is linked to the "i" integer.
                                            The integer "i" acts as the value for the rows, 
                                            you could/should make a unique value or even a List for the rows if you want to add more functions. 
                                           (for example: you want to make it so only 1 or 2 obstacles spawn per row etc)*/
        {
  
            for (int a = 0; a < 3;) //Loop to instantiate the tiles on the row, you can have more tiles per row by changing the 3 to a larger number, you could also make a unique integer for this and call it "levelWidth" or similar.
            {
  
                tileIDList.Add(currentTileID); //Adds a new ID to the tile ID list, first ID is 0 and the ID increases by 1 every time this loop starts over.
  
                tilePos = new Vector3(a, 0, i); /*Define the position of the current tile being spawned. "a" is the x position on the scene. The reason we use "a" is because its a simple way to change to position everytime we spawn a new tile,.
                                                since the value of a increases by 1 everytime the loop starts over. If you want the tile size to be something other than 1x1 you will have to make an individual float/integer for the X position.
                                                The 0 value is self explanatory if you know how Vector3's work, the tiles spawn at the 0 position on the scene. The "i" value, like mentioned before is the value of the rows, here we use it
                                                to spawn the next row of tiles 1 above the last row on the Z axis.*/
  
                tilePosList.Add(new Vector3(tilePos.x, tilePos.y, tilePos.z)); //Here we add and store the position of the current tile being spawned to the Tile position list.
               
                Instantiate(tileObj, tilePos, Quaternion.Euler(0,0,0)); //Spawn the Tiles, "tileObj" is the reference to the prefab we want to spawn, "tilePos" was explained before, "Quaternion.Euler" is the rotation of the tiles.
  
                currentTileID++; //Adds 1 to the currentTileID value.
                a++; //Adds 1 to the a value so when the loop runs again the next tile spawns to the right of the last one.
            }
            i++; //Add 1 to the value of "i" so we generate the next row
  
        }
  
  
    }
  
  
  
    Vector3 obstaclePos; //Pretty much the same as "tilePos" but for obstacles
  
    void AddObstacle () //Generate the obstacles
    {
  
        for(int i = 0; i < obstacleAmount;) //Loop to spawn every obstacle based on the amount of obstacles you want. This "i" integer is different from the one before since variables instantiated inside loops live inside them only.
        {
            obstacleTile[i] = Random.Range(5, tileIDList.Count); //This chooses which tile to spawn the obstacle on. We set the maximum value of Random.Range to tileIDList.Count (which is the maximum amount of tiles on our game) since the value of tiles is random.
                                                                 //The minimum value is 5 so the obstacle doesnt spawn on the first 2 rows. (5 because the Tile IDs start at 0.)
  
            obstaclePos = new Vector3(tilePosList[obstacleTile[i]].x, 1, tilePosList[obstacleTile[i]].z); //We set the obstaclePos X and Z values to the same value as the tile we want to spawn it on. The Y value is 1 so the obstacle spawns above the tiles.
  
            Instantiate(obstacleObj, obstaclePos, Quaternion.Euler(0,0,0)); //Spawn the obstacles, same logic as before.
  
            i++; //Add 1 to the value of "i" so we can generate the next obstacle.
        }
    }
}