Unity Tutorials 01 – Simple Cube Maze

We will be starting our Unity course by making a simple puzzle game. We will be doing some practices that are not considered best just for the sake of keeping it simple. Also, I won’t be telling everything in detail so that this will require you to stay aware and do some web searching on your own, although the text should provide you with search terms. You will do that a lot after the course and web searching is pretty much the do or die skill of the beginner phase of any development. Do the beginner tutorials so you know what the inspector is and what the absolute basics are.

Let’s start out by creating a new project. You can name it whatever you want, but this is a puzzle game where you push little cubes and mazes and it’s great if you name it something you’ll instantly recognize in a year or two. Don’t try to be cute and funny. I’ve done that and have had absolutely no idea what the project was about when finding it later.

We will be having a main camera and directional light in the game. You won’t need to touch them. Create a cube 3d asset. Make its transform position into 0,0,0. Duplicate it. We’ll need to move all of the cubes one unit at a time, which can be done by holding ctrl while moving the object. Move the other cube down and change the scale into 10,1,10 so that it resembles a plate. Move the small cube into 0.5,0,0.5. Duplicate it again and move the copy into the edge of the plate while holding ctrl. This will be a wall cube. Remove the box collider component from the wall cube and create a new capsule collider in the wall cube. It will prevent the wall cubes from having sharp edges which slow the player cube down.

This is the point where we’ll be needing physics materials. Create a new physics material called movingObjects and change its static and dynamic frictions into 0.3. Duplicate it and rename it into wallObjects. Set the friction parameters into 0 and change the friction combine into ‘minimum’.

Select the middle cube and add a rigidbody to it in the inspector. Set weight to 5. Duplicate the cube and move it a little to the side by holding the ctrl key again. Change the middle cube weight to 10 so it can easily push the other cubes off the plate.

Create a folder in your project window called Materials and create a new material in it called ‘green’. Make the albedo color green. Duplicate (ctrl+d) the green material and rename it ‘blue’. Change the color into blue. Duplicate it and rename it ‘black’. Change the color into black. Drag and drop the green material on the middle cube, the blue one on the cube you just created and moved a little to the side and drop the black color into the bottom plate.

Name the green object ‘player’, the blue object ‘movable’ and the black plate ‘plate’ and the white object wall. Now it’s time to code. Under the player object, create a new C# script called InputController. It should look like this.

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

public class InputController: MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {

    }
}

Inside the Class, make a public vector3 called Axes. It will be our directional vector. We’ll need to assign the user input into the x and z axes of it. The inputs are called Horizontal and Vertical and they are defined in the input editor. Write the next code into the Update method

        Axes.x = Input.GetAxis("Horizontal");
        Axes.z = Input.GetAxis("Vertical");

Create PlayerEntity C# script under the player object. It needs a public float called Speed, so write that inside the class. Change the Update method into FixedUpdate, because FixedUpdate is something that physics and accurate timing needs. Fixed Update calls are related to the physics frames. Everything that needs to be accurate should be run under FixedUpdate. Inside the FixedUpdate method create the following that moves the object according to the InputController script.

GetComponent<Rigidbody>().AddForce(GetComponent<InputController>().axes * Speed, ForceMode.Force);

The speed needs to be 500 because we’re working with RigidBody. We don’t want it to be too slippery, so change the drag parameter of the rigidbody into 5. We don’t also want the object to tumble around, so change the green object’s freeze rotation parameter inside the rigidbody component so that all axes are locked. On the blue object, lock only the z parameter so it tumbles while falling. To make things smoother, change the blue object’s box collider size into 0.8, 1, 0.8. Try it out.

Create a new empty object called gameController and create a script component in it called GameController. We’ll need to track all the movable objects inside the controller so we need to make a list of objects.

Public List<GameObject>() MovableObjects;

Let’s get back to the editor and drop the movable object into the list inside the editor. Create a script under the movable that is called MovableEntity. In the script’s class we’ll need a public reference to the game controller.

public GameController GC;

Inside the editor, drag and drop the gameController object into the GC property. Change back to the code editor and under Update write the following:

if (transform.position.y < -10)
{
GC.MovableObjects.Remove(this.gameObject);
Destroy(this.gameObject);
}

This will remove the gameobject from both the controller list and from the playfield if it drops under -10 y position. Destroy(this.gameObject) should always be the last line in a delete sequence because it also removes the script instance from the play field.

Create a new TextMeshPro object from the UI group. Move it into the upper corner of the GUI and change its anchor to upper left from the image in rect transform’s upper left corner.

Add the following into the top part of your GameController script:

using TMPro;
using UnityEngine.SceneManagement;

Inside the class we need two public properties.

public TextMeshProUGUI ScoreText;
public string NextScene;

Inside the Update method, we’ll have to break the best practice rules a bit.

ScoreText.text = MovableObjects.Count.ToString();
if (MovableObjects.Count == 0)
    SceneManager.LoadScene(NextScene);

This will load the NextScene by name when the level is completed. After that we’ll need to make a fail state. Write under the Update Method in the PlayerEntity script the following:

if (transform.position.y < -10)
{
     UnityEngine.SceneManagement.SceneManager.LoadScene("GameOverScreen");
}

Time to create a Game Over screen. Go to the scenes folder and create a new scene called GameOverScreen. Double click it. When it’s active we can rename the SampleScene object into Level 1. Change the camera background into solid color and create a new UI textmesh pro text. Change the font size into around 35 and write “Game Over” in it. Resize the text box so it’s in one line. Duplicate the text mesh object, move it a little down and write Press Space. Change the size into around 25.

Create a new empty game object called endScreenController and create a new script in it called EndScreenController. Add the using scenemanagement part into the top like before. Under update write:

if (Input.GetKeyDown(KeyCode.Space))
{
     SceneManager.LoadScene("Level 1");
}

This will load the first level when pressed space. Let’s create a win screen as well. Duplicate the GameOverScreen and rename the new one into WinScreen. Change the text into the more friendly “You win!”.

Time to make another level. This is where you’re on your own. Remember that under GameController there’s the NextScene field where you input the name of the next scene. Build your puzzle levels by duplicating the wall objects and moving them around the stage. Also, you can keep everything in order by making an empty object called ‘walls’ and moving the wall objects into it’s child objects so that they won’t clutter your inspector view.

When you build the game, remember to include all scenes in the build. Good luck.