Infinite Roller Tutorial Fourteen – Blocks Part Four

Welcome to Edge of Code’s series of Infinite Roller tutorials. If you’d prefer a video tutorial, you can find one here.

In the previous tutorial, we continued using blocks to create terrain, made the menu buttons play the appropriate game, and gave the different terrain types their own high scores. Today, we’ll randomly generate the blocks as the character moves over them.

Open the Infinite Roller project and the scene. First, we’ll create the block terrain. Open the Block and BlockTerrainGenerator scripts. In BlockTerrainGenerator, we’ll first activate blocks in their initial random position. We’ll also need to keep track of which blocks are active so that we know which ones are available to use next. Create a new variable

private List<Block> activeBlocks;

and initialise it in awake

activeBlocks = new List<Block>();

Next, create a new method

/* Activate numToActivate blocks*/
private void ActivateBlocks(int numToActivate)
{
	for (int i=0; i<numToActivate; i++)
	{
	}
}

where we pass in the number we want to activate, then loop through that number of times. First we want to get an inactive block to position and activate – add

Block block = GetRandomInactiveBlock();

inside the for loop. Then create the method

/* Get a random inactive block*/
private Block GetRandomInactiveBlock()
{
	//block to return 
	Block nextBlock;
	
	//get a random number and use that to select a block
	int randomNo = Random.Range (0, blocks.Count);
	Block randomBlock = blocks[randomNo];
	
	//make sure it's not active. If it isn't, use it as the next block
	if (!randomBlock.IsBlockActive())
	{
		nextBlock = randomBlock;
	}
	//if it is, try again.
	else
	{
		nextBlock = GetRandomInactiveBlock();
	}
	
	return nextBlock;
}

The method gets random block from the blocks list, then checks if it’s already active. If it’s inactive, we assign it to nextBlock which is then returned. If it’s active, we call the method again, assigning what is returned to nextBlock, which is then returned to the ActivateBlocks method. We’ll create the IsBlockActive method now – go to the Blocks script and add

/*Check if the block is active */
public bool IsBlockActive()
{
	return gameObject.activeSelf;
}

gameObject.activeSelf is true if the block is active, and false if it is not. Go back to BlockTerrainGenerator and the ActivateBlocks method. Now that we have a block, we’ll position it:

//position it
block.SetRandomPosition(frontBlock); 

The method takes the frontBlock as a parameter since we need to know where that block is to make sure the next one is positioned after it. Again we need to create this method in the Block script.

Unity tutorial activate

Switch to that script and add a new method

/* Set a random position */
public void SetRandomPosition(Block frontBlock)
{
}

To position the block correctly, we need to know the width of the frontBlock, the width of this block, and add an extra random distance on (see the image below).

Unity tutorial position blocks

Create a new variable

private float blockWidth;

to store the width of the block. Create an Awake method to assign the variable.

void Awake()
{
	Renderer renderer = GetComponent<Renderer>();
	blockWidth = renderer.bounds.size.x;
}

First we get a reference to the Block gameobject’s renderer, then access its width. Now that we know the width, create a new local variable in SetRandomPosition to store the distance between the current and front block

float blockDistance = previousBlock.BlockWidth/2 + BlockWidth/2;

Next add the following to get an extra random distance between the blocks

float randomGap = Random.Range (LOWER_POS_BOUND, UPPER_POS_BOUND);

And create the two const variables for the range

private const float LOWER_POS_BOUND = 5f;
private const float UPPER_POS_BOUND = 30f;

Also, add another constant variable to limit the y position

private const float HEIGHT_RANGE = 10f;

Now assign the x and y positions of the gameobjects

float xPos = frontBlock.transform.position.x + blockDistance + randomGap;
float yPos = Random.Range (-HEIGHT_RANGE, HEIGHT_RANGE);

So the x position is the frontBlock’s x position, plus the widths of the front and current blocks divided by two, plus the extra random gap. The y position is a random variable between plus and minus HEIGHT_RANGE. Next, set the new position:

transform.position = new Vector3(xPos, yPos, 0);

Unity tutorial random position

Save the script and return to ActivateBlocks in BlockTerrainGenerator. Since block is now the block at the front, reassign frontBlock

//set it as frontBlock
frontBlock = block;

And activate it

//activate it
block.SetBlockActive(true);

Then add it to the list of active blocks

//add it to the active list 
activeBlocks.Add (block);

Each time through the for loop, we get a new block, position it, reset frontBlock to be that block, activate it and add it to the list.

Unity tutorial activate

Call this method from Awake, after the blocks have been instantiated:

ActivateBlocks(NUM_INITIAL_BLOCKS);

and create a const variable for the number of blocks to initially activate.

private const int NUM_INITIAL_BLOCKS = 5;

Make sure both scripts are saved, then go to Unity and test that five blocks are positioned randomly after the initial long block (there should be six blocks altogether). Go back to the BlockTerrainGenerator script. Next we need to generate blocks as the character is rolling along. Add an Update method

void Update()
{
}

If the character reaches a certain position, we want to deactivate the first block, and activate one new one ahead, so add the following to Update():

//keep track of which block the player is on
if (PlayerReachedNextPosition())
{
	//deactivate first one
	DeactivateFirstBlock();
	
	//activate a new one ahead
	ActivateBlocks(1);
}

Passing one into ActivateBlocks will activate the new block, but we’ll need to create the other two methods. First create the DeactivateFirstBlock method

/* Deactivate the first active block*/
private void DeactivateFirstBlock()
{
	Block firstBlock = activeBlocks[0];
	firstBlock.SetBlockActive(false);
	activeBlocks.RemoveAt(0);
}

The first block is at position zero in the activeBlocks list. We deactivate that block using SetBlockActive and then remove it from the activeBlocks list.

Next, let’s look at the PlayerReachedNextPosition method. ChunkTerrainGenerator has a method that checks if the character has reached a certain position as well, so PlayerReachedNextPosition should be an abstract method in AbstractTerrainGenerator. Open AbstractTerrainGenerator and add

public abstract bool PlayerReachedNextPosition();

Unity tutorial abstract method

Save the script, open ChunkTerrainGenerator and find the PlayerReachedNextChunk script. Rename it by right clicking, go to refactor and type in PlayerReachedNextPosition. Press OK, then add the override keyword to the method and change its access modifier to public so that it becomes

public override bool PlayerReachedNextPosition()

Save the script and create the following method in BlockTerrainGenerator.

/* Check if the character has reached the next section*/
public override bool PlayerReachedNextPosition()
{
	bool playerReachedNextSection = false;

	return playerReachedNextSection;
}

We need a reference to the character’s position, so add a new class variable

 
//ref to the character
public Transform character;

Save the script, then go to Unity and drag the character gameobject into the BlockTerrainGenerator’s empty Character slot. Return to PlayerReachedNextPosition() and add a variable to store the distance between the player and the front block

//distance between player and front block 
float distance = frontBlock.transform.position.x – character.position.x;

If the distance is below some value, we want to set playerReachedNextSection to true:

//if distance is short enough, want to activate next block
if (distance < DISTANCE_ACTIVATE_BLOCK)
{
	characterReachedNextSection = true;
}

Unity tutorial override

Create the const variable

private const float DISTANCE_ACTIVATE_BLOCK = 40f;

You might need to change this value to get the blocks to generate at the correct point.

Finally, we need to fill in the Restart method. Find it in your script and add

//set all inactive
foreach (Block block in blocks)
{
	block.SetBlockActive(false);
}
		
//clear active blocks list
activeBlocks.Clear();

//reinit frontblock
frontBlock = initialBlock;

//add new blocks
ActivateBlocks(NUM_INITIAL_BLOCKS);

In here, we deactivate all of the blocks which are stored in the blocks list, empty the activeBlocks list, reinitialise the frontBlock to be the initialBlock, and activate the new blocks.

Save the script and return to Unity to test the game works. You should be able to select a terrain type in the menu, then the terrain will randomly generate either in the form of chunks or blocks, depending on which you chose.

Unity tutorial random blocks

Save the scene and the project. You have now learned how to create an infinite roller game while also learning about random, infinite terrain generation, audio, how to draw simple 2D objects, the UI system and more. I hope you’ve enjoyed these tutorials!

Remember you can download the files for this tutorial and all the previous ones on the Downloads page.

PreviousTutorialButton

Comments are closed.