Featured Infinite Terrain Generator Part 1

What would you like to see next 5

  1. How to add multiple types of objects to the terrain (3) 60%
  2. How to make the terrain able to move with the player (1) 20%
  3. How to make multiple biomes for the terrain (1) 20%

Hello! Welcome to my first blog and tutorial, in this tutorial i will be showing you how to make an infinite runner terrain generator, for an example watch this video

. This will be broken up into two or three different articles with this one being about generating the, and the second being about adding the ability for the terrain to follow the player forward and adding different biomes although this might be made into another article.


Getting Started-

Things you will need:

- Open project

- Terrain models/prefabs (These will be the ground)(Mine are 2x the size of a regular Unity cube object)

- Obstacle models/prefab (Optional)

- Understanding the concepts of Object pooling and Scriptable Objects(only for different biomes)


Know lets get started by making a Empty Game Object in the Hierarchy and calling it TerrainSpawner, this object will have the script that is going to be doing all of the work. Know lets add a script and call it whatever you want, i will be calling mine Terrain_Spawner


That's it, your all ready to start making your terrain generator


Variables-

OK, know that we have our terrain spawner object setup we know need to open the Terrain_Spawner script and add some variables to it. We will start by making a public class called pool:


Code
  1. [System.Serializable]
  2. public class Pool
  3. {
  4. public string tag; //Name of Object
  5. public GameObject prefab; //Object prefab
  6. public int size; //Amount of objects
  7. }

Know this class will be used to store all the different ground blocks and obstacles information. In this class we have three different variables, a string tag which will be used to name that object, a gameobject prefab which will have the prefab that you want to use for the objects and obstacles, and a size which will be used in the start to decide how many of that object you want to add to the pool. We will also need to add the [System.Serializable] at the top so we can see it in the inspector.






Once you have that in your script save and go back to the project and look at your TerrainSpawner in the inspector, there should be a Pools tab on the script. You can know add all the objects you wish to spawn in your terrain including any obstacles. You should put the prefab you want in the prefab slot then name the tag to whatever you want to call that prefab, the size can vary and i suggest messing with it to see what fits your terrain later. I will have two ground blocks and two obstacles as seen above.


Know lets add a list and a dictionary. The list will be used for holding all the Pools for use later when we are adding the objects into the scene. The dictionary will be used for keeping track of all our objects

Code
  1. public List<Pool> pools;
  2. public Dictionary<string, Queue<GameObject>> poolDict;


Know that we have all the Gameobjects and object stuff out of the way lets get to the Size and Positioning variables that we will be using in this script

Code
  1. public Vector3 spawnPos;
  2. private float middle;
  3. public int terrainLength;
  4. public float terrainWidth;
  5. private bool widthIsOdd = false;
  6. public string chosenBlock = "";
  7. public string chosenObsticle = "None";


Ok, so let me explain what all these variables are for:


- spawnPos = this will be used for the position to spawn a object at

- middle = this is to keep track of where the middle of the terrain is (we cant use the spawnPos because it will be moving all over the place)

- terrainLength = this will determine how long or how many rows the terrain will have

- terrainWidth = this will determine how wide or how many columns the terrain will have

- widthIsOdd = this is to see if your width is an odd number which makes us use a different equation to find where to start spawning objects

- chosenBlock = chosen block to spawn

-chosenObstacle = chosen obsticle to spawn


That will be all for the variables, once you have all the variables plugged in you can know get started with spawning in all the objects. Also if you wish to not have public variables all of the public variables except the list and class Pool can be made into [SerializeField].


Creating the Pool and Dictionary-

In this section we will be creating the Pool and dictionary. Know in the terrain generator we will be using Object Pooling (Object Pooling Tutorial) which is where we will instantiate all our objects at the beginning then reusing them as we go along. To set this up we will have to do some code to instantiate all the objects then add them to the dictionary so we can use them later.


Out this code in the Start Function


At the top we are creating our Dictionary which will be holding a string which will be the name of the objects and a Queue of gameobjects which will be all of our prefabs.


Then we are going through all of the Pools in the List of Pools and creating a temporary variable called pool. We are then creating a Queue of gameobjects to add the objects into once instantiated. Know that we are all setup we know start spawning in the prefabs by making a for loop that repeats for however big the size variable in that Pool is.


The for loop is is instantiating the object, setting it to false so you cant see it, and adding it to the Queue to be used later. And to finish it of it adds the Queue into the dictionary with the tag of the pool. And it will repeat this for every single Pool you have.


Ok, so know we have all our objects ready to be used in our terrain. Know i know for some of you this might be abit complicated and i dont even fully understand everything, but if you have any questions i will try to help you in the comments.


Spawn Position-


In the start function we are going to set the spawnPos. Let me explain, you might think that you already set the spawnPos in the inspector and why would we set it again in code, well the spawnPos that you set in the inspector is going to be the middle of your terrain. While we are talking about the middle lets set that now

Code
  1. middle = spawnPos.x;


This sets the middle to the spawnPos.x. Now if you want to not have to set the SpawnPos in the inspector you can add:


Code
  1. spawnPos = transform.position;


above the middle code, which will set spawnPos to the objects positions and then you just have to move the object to where you want to spawn the terrain. I will not be doing this though


Once the middle is set we know need to set the spawn to the far left side of the terrain where we will be spawning the first block. To do this we will be using the middle and the width to find how far out we have to go to one side


Code
  1. if(terrainWidth/2 != Mathf.RoundToInt(terrainWidth / 2))//Checks if the width is odd
  2. {
  3. widthIsOdd = true;
  4. }


Before we can set the spawnPos we have to find if the width is an odd number. If the width is an odd number we will have to change the equation abit to find the right left side block.


I do this by dividing the width by 2 and then also Rounding the width divided by zero, if they equal eacother then its even and if they dont its odd. For example an even number would be 6 because if you divide it by 2 then it equals 3 and if you divide it by 2 and round it it equals 3, but for 7 if you divide it by 2 it equals 3.5 and if you divide and round it equals 3 and they are not equal.


Once we decide if its even or odd we set the widthIsOdd to true or false


Next we set the position of the spawnPos (Remeber i am using models 2x the size of regular cubes so if you are using other sizes you might have to tweak some of the adding and subtracting numbers)


Code
  1. if(widthIsOdd == true)//Sets the starting position
  2. {
  3. spawnPos = new Vector3((middle - terrainWidth / 2) + 1, spawnPos.y, spawnPos.z);
  4. }
  5. else
  6. {
  7. spawnPos = new Vector3(middle - (terrainWidth / 2) - 2, spawnPos.y, spawnPos.z);
  8. }


It checks if its even or odd then sets the SpawnPos


The odd will divide width by 2 then subtract that from middle then add one since the width/2 will alwaysbe one less than the far left block


The even one will divide the terrain width by two so that you have half on either side of the middle, then subtracts that number from the middle to get the left side of the middle by the amount to one side, and finally i subtract two from it because if i don't it will be one block more on the left, i am not sure exactly why i need to do this but have tested and without adding - 2 it always has 1 extra block on the right side.

Spawning Terrain-


Now finally, we can start making our terrains.


We are going to start this off still in the start Function with a for loop


Code
  1. for (int i = 0; i < terrainLength; i++) //Spawns rows of objects
  2. {
  3. for (int t = 0; t < terrainWidth; t++)
  4. {
  5. SpawnNewBlock();
  6. }
  7. }


This will start by running the inner for loop for the about of rows we want and the inner for loop triggers a function a object for the amount of columns we want.



This is the function that will be Spawning all of the blocks and obstacles. Lets break this up to explain it abit better


Code
  1. //ChooseBlock();
  2. SpawnFromPool(choosenBlock, spawnPos, Quaternion.Euler(new Vector3(-90, 0, 0)));


The first line is calling a function we havent made yet but will later that chooses the block its going to place for us.


The second line takes one of the objects from the pool and spawning it by looking for a tag that matches choosenBlock string then spawning it at the spawnPos and setting its Rotation(Depending on your models or prefabs you might not need to do this).

Code
  1. spawnPos.x = spawnPos.x + 2;


After spawning the object we can then set the spawnPos to a new Position to the right of the object(I add to because my objects are 2 wide, but you might only have to add 1).



The final part is checking if the new spawnPos is as far as the width needs to go and then sets it back all the way to the left of the terrain using the equations we used at the beginning to find how far left we need to go.


Finishing and Testing-


Ok, know your terrain spawner is all ready to go all you need to do is in the inspector go to chosen block and set it to the block that you want to be spawning and make sure your width and length are bigger than 0. When you press play you should get something that looks like this:




At this point your code should be looking something like this:



Conclusion-

Know you should have a fully functional terrain generator/spawner, but as of right know it cant have multiple types of blocks and doesnt wove with a player. I suggest playing around with differnt sizes of terrain.


I will be making another one to explain how to make multiple types of blocks in your terrain hopefully within the next week so stay tuned.


Any questions or problems you can ask in the comment section or DM me on discord(Ojzach#9271) and i will try to respond.

Comments 7

  • I'm not going to be able to follow this tutorial for a few weeks, but definitely will do as I would love to create an infinite runner and this looks well explained.


    Thanks

    • OK, it is a bit complicated but hope to see what you do with it

    • I have an idea of a Roller Derby themed endless runner. I think it could be really fun.

    • Nice. Just a heads up if you use this script you will have to have your blocks 2 times the size of the regular unity cube or you will have to edit



      Because the equations ifound out after publishing are specific to the 2x blocks

    • Am trying to figure out how to fix this so it can work with any size though

  • Holy Crap man. Lmao. Well done.