Build Minecraft in Unity Part 4: Simple World Generation (a fast and inefficient approach)

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.

In Part 3 we succeeded to add clicking functionality to our cubes so as to create or destroy instances with a mouse click.

If everything is working as intended, we can proceed to add a first person functionality so we can move freely in play-mode. Fortunately for us, Unity provides a ready-made first person character controller package, so there is no need to program it from scratch in this iteration. Go to Assets -> Import Package and select Character Controller.

42_addcc

Importing a Character Controller package

In the Importing package window select the following:

43_importcc

Tick only what you need from the package

In the Project tab. go to Standard Assets > Character Controllers, select First Person Controller.prefab and drag it in the Hierarchy tab.

44_firstpersoncontroller

First Person Character Controller prefab

Position it close to the Scene‘s origin.

45_positioncc

Position the prefab instance in our world

We need to prevent the object from falling, before we test it. We will set the value back after we finish the world generator algorithm.

46_gravityoff

Defy the laws of gravity!

Test it.

47_test

Test the gravity defying First Person Controller to create something extraordinary.

The First Person Controller in our Scene has a Camera attached as a child GameObject. When we run the game, this child Camera becomes the main Camera, so there is no need for another. Every Camera default contains an AudioListener component. This is the reason why the message “There are 2 audio listeners in the scene. Please ensure there is always exactly one audio listener in the scene.” persists in the Console tab. Disable the stand-alone Main Camera, from the Hierarchy tab.

48_disablecamera

Disable the Main Camera

We’re almost done! Open WorldGenerator.cs and modify it as follows:

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

public class WorldGenerator : MonoBehaviour 
{
  // Public fields are visible and their values can be changed dirrectly in the editor

  // Drag and drop here the Voxel from the Scene
  // Used to create new instances
  public GameObject Voxel;

  //Specify the dimensions of the world
  public float SizeX;
  public float SizeZ;
  public float SizeY;

  // Use this for initialization
  void Start () 
  {
   // Start the world generation coroutine
   // StartCoroutine function always returns immediately, however you can yield the result. 
   StartCoroutine(SimpleGenerator());
  }
 
  // 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 = "Cube@" + clone.transform.position;
  }

  /* from docs.unity.com
  * The execution of a coroutine can be paused at any point using the  yield statement. 
  * The yield return value specifies when the coroutine is resumed. 
  * Coroutines are excellent when modelling behaviour over several frames. 
  * Coroutines have virtually no performance overhead. 
  * StartCoroutine function always returns immediately, however you can yield the result. 
  * This will wait until the coroutine has finished execution.
  */
  IEnumerator SimpleGenerator()
  {
   // In this Coroutine we will instantiate 50 voxels per frame
   uint numberOfInstances = 0;
   uint instancesPerFrame = 50;
  
   for(int x = 1; x <= SizeX; x++)
   {
     for(int z = 1; <= SizeZ; z++)
     {
       // Compute a random height
      float height = Random.Range(0, SizeY);
      for (int y = 0; y <= height; y++)
      {
        // Compute the position for every voxel
        Vector3 newPosition = new Vector3(x, y, z);
        // Call the method giving the new position and a Voxel instance as parameters
       CloneAndPlace(newPosition, Voxel);
       // Increment numberOfInstances
       numberOfInstances++;

       // If the number of instances per frame was met
      if(numberOfInstances == instancesPerFrame)
      {
        // Reset numberOfInstances
        numberOfInstances = 0;
       // Wait for next frame
       yield return new WaitForEndOfFrame();
      }
     }//end for
    }//end for
   }//end for
  }
 }

Here is an extremely interesting read about Unity Coroutines, that I really think can shed some light on this behavior.

An Unity script will only run when attached to an active GameObject present in the scene. Create an new Empty GameObject and drag WorldGenerator.cs on it.

49_dragndrop

Drag and drop WorldGenerator.cs on the newly created GameObject

Drag Voxel to its corresponding field. This version of our world generation algorithm loads all the voxels in memory so it is highly advised not to set high values for the dimension fields. Otherwise, you will have poor performance or worse, the editor will crash. In Build Minecraft in Unity Series 2, we will offer a more efficient and more complex approach so as to create a terrain more similar in size and implementation to the original.

50_values

If you set higher values than the above, do it on your risk!

Before we can finally see our creation in action, don’t forget to update the Gravity field in the script attached to the Character Controller.

51_cc_valback

Gravity is important

Done! Press 38_play and have fun!

52_final

Build Minecraft in Unity (a fast and inefficient approach)

Also, you can test a web build of the application:

See you soon in Build Minecraft in Unity Series 2!


blog comments powered by Disqus