Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Last time we created a textured cube using quads. In Part 3 we want to instantiate a new cube or destroy a cube when clicking the mouse buttons.

This is a series of tutorials oriented towards the research and building of a minimal Minecraft-like game while exploring different facets of the Unity game engine. As this is an introductory tutorial, and because of the need to simplify (for didactic purposes), the algorithms presented in Series 1 are not in any way optimal, nor the structures of the objects used in the game are efficient. Presenting a trivial, fast way to build a minimal Minecraft-like game offers an introductory experience to people just stating to learn Unity, and in the same time, it arises the imperative need for optimization and efficiency. Over the course of the following tutorial series we will cover different implementations with higher degree of complexity.

I recommend to you, The Reader, to state any issues in the comments below. I encourage you to debate anything and everything regarding the contents of this tutorial, for the benefit of the community. Your contribution will help make these tutorials better!

Before we start coding, let’s add a directional light to our scene. We need the light to better see the 3D world.

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Let there be light!

If you want, you can change the default light orientation:

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Position a light in the scene.

We can now proceed to create our first script. We want to instantiate a new cube over the side on which we right click and to destroy the cube on which we left click. In the Project tab, go to the Code folder, and create two C# scripts.

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Adding a C# script to the project

We will name them WorldGenerator and ClickOnFaceScript.

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Scripts we will use in the project.

Before we continue, it is of VITAL IMPORTANCE to take a look at these links:

Now, open WorldGenerator.cs in MonoDevelop (allready installed along with Unity) by double clicking on the script, while in the Project tab, and enter the following code:

/* Andrei Jifcovici
 * In2GPU.com
 */ 
using UnityEngine;
using System.Collections;

public class WorldGenerator : MonoBehaviour
{

    // Use this for initialization
    void Start ()
    {
    
    }

    // Update is called once per frame
    void Update ()
    {
    
    }
    
    public static void CloneAndPlace(Vector3 newPosition, GameObject originalGameobject)
    {
        // Clone
        GameObject clone = (GameObject)Instantiate(originalGameobject, newPosition, Quaternion.identity);
        // Place
        clone.transform.position = newPosition;
        // Rename
        clone.name = "Voxel@" + clone.transform.position;
    }
}

We will use the static method above whenever we create a clone of our original cube. It also allows us to set its position and to automatically generate a suitable and useful name for it. More information about Instantiate here.

In Minecraft, when you left click on a cube (if you are close enough to it), it will eventually disappear into your inventory. When you right click on any side of a cube (if you have enough cubes in your inventory), a new instance will appear close to the face on which you clicked. As we are generous gods, we won’t dabble with such limitations (for now at least). So, we’ll have infinite cubes and infinite clicking distance!

Open ClickOnFaceScript.cs, and enter the code below:

/* Andrei Jifcovici
 * In2GPU.com
 */ 
using UnityEngine;
using System.Collections;

public class ClickOnFaceScript : MonoBehaviour 
{

    // Use this for initialization
	void Start () 
	{
	
	}
	
	// Update is called once per frame
	void Update () 
	{

	}

    // This function is triggered when the mouse cursor is over the GameObject on which this script runs
	void OnMouseOver()
	{
        // If the left mouse button is pressed
		if (Input.GetMouseButtonDown(0))
		{
            // Display a message in the Console tab
			Debug.Log("Left click!");
		}
        
		// If the right mouse button is pressed
		if (Input.GetMouseButtonDown(1))
		{
            // Display a message in the Console tab
			Debug.Log("Right click!");
		}
	}
}

Now, drag and drop the script on each of the six faces of the cube from the scene.

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Apply a script on a GameObject

When clicked, each of the six faces should have the script visible in the Inspector tab:

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

A script component

Give it a try! Press 1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach) and test if the debug messages appear correctly when clicking the textured cube appearing in the Game tab.

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Left click or right click on the cube to test the functionality

Remember! In playmode, any modification to any element in the Scene will be discarded! So remember not the change anything while the game is running. Press 1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach) again to stop the game.

Now, we have the everything we need to create new cubes when clicking the right mouse button. We just need to specify the exact position of the new GameObjects, relative to the face on which we click. In our scene, the distance between the centers of two neighboring cubes is equal to 1.

For simplicity, we will name C, the center of the cube being clicked and N, the center of the newly instantiated object. We consider these centers as positions in 3d space.

  • If we click the top face: N = C + (0, 1, 0)
  • If we click the bottom face: N = C + (0, -1, 0)
  • If we click the right face: N = C + (1, 0, 0)
  • If we click the left face: N = C + (-1, 0, 0)
  • If we click the front face: N = C + (0, 0, 1)
  • If we click the back face: N = C + (0, 0, -1)

If it’s not clear why, run the application below to convince yourself (right click and press Go Fullscreen):

We can generalize the above statements into:

N = C + delta,

where delta is the position displacement needed to compute the center of the new cube instance. Each of the six faces holds a different instance of ClickOnFaceScript, and each should contain a different value for delta.

We need to change ClickOnFaceScript.cs to accommodate the functionality presented above. Open the script and extend the code as follows:

/* Andrei Jifcovici
 * In2GPU.com
 */ 
using UnityEngine;
using System.Collections;

public class ClickOnFaceScript : MonoBehaviour 
{
    // Public fields are visible and their values can be changed dirrectly in the editor
	// represents the position displacement needed to compute the position of the new instance
	public Vector3 delta;

	// Use this for initialization
	void Start () 
	{
		
	}
	
	// Update is called once per frame
	void Update () 
	{
		
	}
	
	// This function is triggered when the mouse cursor is over the GameObject on which this script runs
	void OnMouseOver()
	{
		// If the left mouse button is pressed
		if (Input.GetMouseButtonDown(0))
		{
			// Display a message in the Console tab
			Debug.Log("Left click!");
			// Destroy the parent of the face we clicked
			Destroy(this.transform.parent.gameObject);
		}
		
		// If the right mouse button is pressed
		if (Input.GetMouseButtonDown(1))
		{
			// Display a message in the Console tab
			Debug.Log("Right click!");

			// Call method from WorldGenerator class
			WorldGenerator.CloneAndPlace(this.transform.parent.transform.position + delta, // N = C + delta
			                             this.transform.parent.gameObject); // The parent GameObject 
		}
	}
}

Go back to the editor and change the value of delta accordingly:

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Values for delta, for each cube face, marked with rectangles (Click to enlarge)

Test to see if everything works. Position the camera several times (by changing the Transform position in the Inspector tab) and run the game to check if the above values are correct.

1x1.trans Build Minecraft in Unity Part 3. Clicking Functionality (a fast and inefficient approach)

Position the camera and click the sides of the cube

There you have it! In Part 4 we will procedurally populate a small world with cubes and will add a first person player.


Tagged under:
blog comments powered by Disqus