Skip to content

dannythorne/MakingMinecraft_Take02

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Making Minecraft

This tutorial shows a way to create the most basic game mechanics of Minecraft: blocks that can be broken to drop items and a first person player who can pick up the dropped items.

Developed with

  • Unity Version 5.1.0f3 Personal
  • MonoDevelop-Unity Version 4.0.1.
  • OS X Yosimite Version 10.10.3 (14D136)

Should work the same in Windows just with the usual OS interface differences.

Table of Contents (TOC)

Back to TOC

Preliminaries

Create a 3D project and select the default layout in the editor.

  1. Click to start a new project. (The following is what you should see when you start Unity. If, on the other hand, you already started Unity and have an existing project open, select New Project... under the File menu.)

    New Project

    Name the project.

    Name the Project

    3D should be highlighted.

    3D Project

    Click the create the project.

    Click to Create the Project

  2. Select the default layout.

    Defaut Layout

Back to TOC

Basic Objects and Mechanics

Here we build the ground, the block prefab, and the item drop prefab.

Back to TOC

Ground

You can think of the following as a quick and dirty substitute for a layer of bedrock.

  1. Hierarchy | Create | 3D Object | Plane

    Plane

    In the Hierarchy View, click the Create dropdown, select 3D Object and then Plane.

  2. Inspector | Transform | Scale ( 16, 1, 16)

    Select the plane Scale the plane

    Scale the plane in the x and z directions for plenty of room to play on. The Inspector shows the components of the game object that is selected in the Hierarchy View, so make sure the Plane game object is selected in the Hierarchy View before modifying the Transform component.

  3. Inspector | Transform | Position ( 0, -0.5, 0)

    Shift the plane down

    Lower the plane by half a unit. Doing this leaves space for unit cubes centered at y=0 so they will be on top of the plane.

Back to TOC

Blocks

We will now make a block that disappears when clicked on.

Making a Block Prefab

  1. Hierarchy | Create | 3D Object | Cube

    Create a Cube

    Create a Cube game object.

  2. In the Inspector, rename Cube to Block.

    Select the Cube

    Select the Cube game object in the Hierarchy View first.

    Cube name

    Click on Cube in the field at the very top of the Inspector View.

    Cube renamed to Block

    Change it to Block.

    Note that we can name it whatever we want or even leave it with the default name. We just have to be consistent with what we call it thereafter. Since cubes in Minecraft are called “blocks”, it makes sense to call them that in this project.

  3. Drag the Block game object from the Hierarchy View into the Assets folder of the Project View.

    Block prefab

    This makes it a “prefab”. Prefabs can be added to the game multiple times resulting in multiple game objects that are clones of the prefab. Then changes to the prefab apply to all of those game objects. This is very useful to avoid having to modify lots of game objects just to make a simple change. Another reason it is useful to make prefabs is because they can be “instantiated” from scripts dynamically at run time. We will eventually want to do this in order to produce a procedurally generated terrain of blocks.

  4. Drag a few Block prefabs into the scene.

    Scene with some blocks

  5. In the Inspector for each block, manually assign their position coordinates to be integers and make them all have y=0 in particular.

    Block1 select Block1 position

    Observe that Unity automatically numbers the game objects generated from prefabs.

    Block2 select Block2 position

    Block3 select Block3 position

Save the Scene and the Project

  1. File | Save Scene

    Select File and Save Scene.

    Save Scene

    We will only have the one scene, so no need for a very purposeful name. Let's just name it Scene.

    Now a scene asset named Scene will appear in the Assets folder of the Project View.

    Scene Asset

  2. File | Save Project

    Select File and Save Project.

    Save Project

    The project already has a name from when we created it, so there will not be a prompt for naming it.

Adding a Script to the Block Prefab

  1. In the Assets folder of the Project View, right-click and select Create | C# Script

    Create MineBlock.cs script

  2. Rename it to MineBlock.

    Newly created MineBlock.cs script

    Its default name is NewBehavior. Just type over that to change it to MineBlock.

    Renamed MineBlock.cs script

    Now double-click the MineBlock C# asset. That will cause the script to be loaded in Mono.

    Mono MineBlock initial script

    There is a Start function and an Update function. They are empty to start with. We could write code in them, but we won't for now. We can also add other functions. We will add another function soon.

    It is important to realize first and foremost, however, that this script needs to be “attached” to a game object (or multiple game objects). Let's go ahead and attach it to our block prefab before delving into actual coding in the script.

  3. Go back to Unity and select the Block prefab.

    Select Block Prefab

    Now click and drag the MineBlock script asset over to the Add Component button in the Inspector View for the Block prefab and drop it there.

    MineBlock Script Drop To Add

    The MineBlock script will be added as a component to the Block prefab.

    MineBlock Script Added

    Note that the Add Component button activates a menu through which we could have added the script as well. (There are usually multiple different ways of accomplishing the same thing.)

  4. Go back to Mono and add the following OnMouseDown function to the MineBlock script.

    Mineblock Script OnMouseDown Destroy

    Here's the code for you to copy-and-paste if necessary:

      void OnMouseDown() {
          Destroy( gameObject);
      }
    

    However, it is recommended that you type the code yourself to help you learn the patterns.

  5. Save the script in Mono.

    Save the Script

  6. Go back to Unity and run the game by clicking on the play button.

 ![Run the Game](./ScreenCaps/game_run.png "Run the Game")

 After clicking play, the buttons will be colored blue signifying that the game is playing.

 ![Game Running](./ScreenCaps/game_running.png "Game Running")

 While the game is running, click on some of the blocks and watch them
 disappear. They disappear because of the `Destroy` statement in the
 `OnMouseDown` function of the `MineBlock` script that is attached to the
 block game objects via the `Block` prefab. Whenever the mouse button is
 clicked with the mouse cursor hovering over a block, the `OnMouseDown`
 function of that block executes and thus the `Destroy(gameObject)`
 statement executes. Note that `gameObject` refers to the game object to
 which the script that contains the function that's executing is attached.

 Click the play button again to stop the game.

 **WARNING:** If you fail to stop the game before going on to make changes
 to the game, your changes will be lost when the game is stopped.  You
 *must* stop the game before making changes that you want to keep.  Note
 that it can sometimes be useful to make temporary changes to the game
 while it is running just for the purpose of diagnostics and
 experimentation, but in any case you should always be alert to whether the
 game is running or not before making changes.
  1. Save the scene and the project.

Hide the original Block game object

In the next section we are going to add a new game object to the scene. To keep the scene view clean in preparation for that, we will now hide the original Block game object that we used to make the Block prefab. Also, eventually, we will be placing multitudes of blocks from a script at run time in some systematic way and will want to remove all of the hand-placed blocks from the initial scene. For now, we will leave the other few blocks that were added to the scene via the prefab just to have something there in the meantime. We do want to hide the original one, though, because it occupies the special origin location that other new game objects will occupy by default. (Alternatively, we could just move it out of the way, but we are going to want to hide it eventually anyway so let's just do it now.)

  1. In the Hierarchy View, select the Block game object.

    Select the Block Game Object

  2. In the Inspector View, uncheck the checkbox next to the game object's name field.

    Uncheck Checkbox Next to Name Field

    That game object should no longer appear in the scene. It is still listed in the Hierarchy View although dimmed.

Back to TOC

Drops

In Minecraft, when a block is “mined” it can drop a resource which appears as a smaller version of the block floating in the space that the original block had occupied. This section shows how to create a dropped block prefab and cause it to be instantiated in place of blocks whenever blocks are destroyed.

  1. Hierarchy | Create | 3D Object | Cube

    Create a Cube

    Create another Cube game object.

  2. Rename it DroppedBlock.

    Rename to DroppedBlock

  3. Inspector | Transform | Scale (0.5,0.5,0.5)

    Scale the Dropped Block

    Make it smaller.

  4. Inspector | Transform | Rotate (15,0,5)

    Rotate the Dropped Block

    Rotate it.

    Feel free to adjust the scale and rotation as desired. To make it look like a dropped item, it just needs to be smaller and tilted.

  5. Make a prefab from the DroppedBlock game object by dragging it into the Assets folder of the Project View.

    DroppedBlock Prefab

  6. Select the source DroppedBlock Game Object and hide it.

    Select DroppedBlock Game Object Hide DroppedBlock Game Object

  7. Go to Mono and edit the MineBlock script by adding this line

      public GameObject droppedBlockPrefab;
    

    before the Start function:

    Script Object for DroppedBlock Prefab

  8. Go back to Unity and select the Block prefab.

    Select the Block Prefab

    Look at the Inspector View and see the Dropped Block Prefab field in the Mine Block (Script) component.

    DroppedBlockPrefab Field

    That field was put there automatically by the Unity editor after we declared the droppedBlockPrefab variable in the MineBlock script.

    Now drag the DroppedBlock prefab into that Dropped Block Prefab field.

    Dragging DroppedBlockPrefab

    DroppedBlockPrefab Dropped

    This will cause the droppedBlockPrefab variable in the MineBlock script to be initialized to the DroppedBlock prefab when the game runs. It is in this way that our script will have access to that prefab.

  9. Finally, add this line

      Instantiate( droppedBlockPrefab, transform.position, droppedBlockPrefab.transform.rotation);
    

    to the OnMouseDown function of the MineBlock script right before the Destroy statement.

    Instantiate On Mouse Down

    This causes the DroppedBlock prefab to be “instantiated” as a game object at the same position as the block that was clicked and with the rotation that we specified in the Inspector for the DroppedBlock prefab.

  10. Save the script.

    Save the Script

  11. Go back to Unity and save the scene and project.

    Save Scene Save Project

  12. Play the game.

    Run the Game

    See that when you click a Block game object, a DroppedBlock game object appears in its place.

  13. Stop the game.

    Stop the Game

Back to TOC

First Person Character

This section adds a first person character to the scene so that the player can look around and move around in a way similar to Minecraft.

Beware: The first person character asset is provided by Unity in the Standard Assets package, so Standard Assets must be installed. If they are not, the Import Package menu in the very first step below will not contain the shown options. In that case, go to the Asset Store:

Asset Store Under Window Menu

and download/import Standard Assets from there instead.

Back to TOC

Import Assets

  1. Assets | Import Package | Characters

    Import Package Characters

    If you do not see the shown options in your Import Package menu, see the note above. You will need to install/import them from the Asset Store.

  2. Click the "None" button to uncheck all of the options.

    Click None to Deselect All

  3. Click the checkbox next to FirstPersonCharacter.

    Select FirstPersonCharacter

    Now just the FirstPersonCharacter asset is selected.

    FirstPersonCharacter Selected

  4. Click the Import button.

    Click Import

    Notice the new StandardAssets folder inside your Assets folder of the Project View.

    New StandardAssets Folder

    You will also notice an error message in the Unity status bar. If you click the Console tab next to the Project tab, you will see other messages, too. There are a couple of dependencies that we need to import before we can use the FirstPersonCharacter standard asset.

  5. Assets | Import Package | CrossPlatformInput

    Import Package CrossPlatformInput

    Click Import

    And now there is a new folder named Editor inside the Assets folder of the Project View.

    New Editor Folder

  6. Assets | Import Package | Utility

    Import the Utility Package

    Click the Import Button

    No additional new folders will appear at the top level of the Assets folder this time, but you'll see that the error messages have disappeared now.

Back to TOC

Add and Configure Character

  1. Under the Assets folder in the Project View, expand StandardAssets, Characters, FirstPersonCharacter, and then select Prefabs.

    FPSController Prefab

    Notice the FPSController prefab. That's what we are going to use.

  2. Drag the FPSController prefab into the scene.

    Drag the FPSController into the Scene

    Drop it somewhere near the current camera.

    Dropthe FPSController into the Scene

  3. Remove the old camera which is called Main Camera.

    Delete the Old Main Camera

    The FPSController prefab comes with its own camera built in.

  4. Adjust the y coordinate of the FPSController position so that it is completely above the plane, e.g., y=2.

    Select the FPSController Game Object Adjust Position of FPSController

    It's okay if it starts higher than the plane. It will fall to the surface when the game begins.

  5. Save the scene and project.

    Save Scene Save Project

  6. Run the game.

    Run the Game

    Notice that the camera follows the cursor as expected for a first person character. Also, you can use the W A S D keys to make the player walk and the SPACE bar to make it jump.

  7. Stop the game.

    Stop the Game

  8. Adjust the scale of the FPSController to (0.5,0.9,0.5).

    FPSController Selected Adjust the Scale of the FPSController

    This will make it possible for the character to fit through one block wide and two block high openings (eventually).

  9. Save.

    Save Scene Save Project

Back to TOC

Lock the Mouse

The way the player interacts with the scene will be more natural if the cursor is always in the center of the screen (like the crosshairs of Minecraft).

  1. Select the Assets folder in the Project View and create a new C# Script.

    Create MouseLock Script

  2. Rename the new script to MouseLock.

    New Script Renaming Script Script Renamed

  3. Select the FPSController game object.

    Select FPSController Game Object

  4. Scroll down in the Inspector View until the Add Component button is visible.

    Button for Add Component

  5. Drag the MouseLock asset onto the Add Component button of the Inspector for the FPSController.

    Add MouseLock Script as Component of FPSController

    Now the Mouse Lock (Script) component should appear in the list of components for the FPSController.

    MouseLock Script Added

  6. Double-click the MouseLock C# asset in the Project View to open it in Mono.

    Initial MouseLock Script

    Notice that Mono now has two tabs, one for the Mineblock script that we edited previously (and will return to later) and one for the new MouseLock script that we will edit now.

  7. To lock the mouse cursor when the game begins, put this line

      Cursor.lockState = CursorLockMode.Locked;
    

    in the Start function.

    Cursor Lock in Start Function

  8. To unlock the mouse cursor when the user presses the ESC key, put these lines

     if( Input.GetKeyDown("escape"))
     {
       Cursor.lockState = CursorLockMode.None;
     }
    

    in the Update function.

    Capture ESC in Update Function

  9. Save the script.

    Save the Script

  10. Go back to Unity and save the scene and the project.

    Save Scene Save Project

  11. Run the game.

    Run the Game

    If you're lucky, the mouse cursor will lock in the middle of the Game View until you hit the ESC key.

    Cursor Centered in Game View

    The mouse lock mechanism can be a bit flakey in the Game View. Sometimes it doesn't work right. To see it work reliably, we might need to build the game as a native application.

  12. Stop the game.

    Stop the Game

    In my experience, if the cursor lock doesn't work the first time the game is run, stopping it and then running it again will make it work, so try running it again at this point. (And then stop it before proceeding.)

Back to TOC

Build the Game

  1. File | Build Settings...

    File | Build Settings...

    From the File menu, select Build Settings....

  2. PC, Mac & Linux Standalone.

    Platform

    From the Platform list, select PC, Mac & Linux Standalone.

  3. Target Platform

    Targer Platform

    Select your operating system from the Target Platform menu.

  4. Click the Build And Run button.

    Click Build And Run

  5. Name the application something like MakingMinecraft.

    Name the Application

  6. Click Save.

    Save the Application

  7. Select your desired resolution from the Configuration dialog that pops up.

    Choose Resolution

  8. Check the Windowed check box.

    Check Windowed

    This will make the application run inside a window rather than in full screen. (Optionally, you can leave that checkbox unchecked to run in full screen mode, but it might be tricky to escape out of the game when it is running that way.)

  9. Play!

    Play!

    Click the Play! button and enjoy playing the game as a native application.

    Application Running

    When finished playing, press ESC to unlock the cursor and then close the application.

  10. Back in Unity, close the Build Settings window.

    Close Build Settings

Back to TOC

Pickup Mechanic

When the player runs into a dropped block, the dropped block game object should disappear as the player “picks up” the item.

  1. Select the DroppedBlock prefab in the Assets folder of the Project View.

    Select the DroppedBlock Prefab

  2. In the Inspector View, check the Is Trigger check box of the Box Collider component.

    Check the Is Trigger Check Box

  3. In the Assets folder, create a new C# Script.

    Create New C# Script Asset

  4. Rename it to PickUp.

    New Script Renaming Renamed

  5. Select the DroppedBlock prefab again.

    Select the DroppedBlock Prefab

  6. Drag the PickUp script over to the Add Component button in the Inspector for the DroppedBlock prefab.

    Adding PickUp Script Component to DroppedBlock Prefab

    Then the Pick Up (Script) component should appear in the list of components in the Inspector for the DroppedBlock prefab.

    PickUp Script Added

  7. Save the scene and project.

    Save Scene Save Project

  8. Double-click the PickUp script to open it in Mono.

    Double Click the Pickup Script

    Now you will see three tabs in Mono with the one for the PickUp script in front.

    Initial PickUp Script

  9. Add the following OnTriggerEnter function

      void OnTriggerEnter()
      {
          Destroy( gameObject);
      }
    

    after the Update function like this:

    OnTriggerEnter Function in PickUp Class

  10. Save the script.

    Save the Script

  11. Back in Unity, run the game.

    Run the Game

    Click on a block to make it drop a dropped block item and then run your character into the dropped block. It should disappear.

  12. Stop the game.

    Stop the Game

Back to TOC

Sound Effects

Breaking blocks and collecting dropped items is much more satisfying with sound effects!

Back to TOC

Add Sound Assets.

  1. Download the following two wav files:

    dig_grass1.wav

    pop.wav

    Save Link As

    Save them in the Assets folder.

    Save in Assets Folder

    Do that with both files: dig_grass1.wav and pop.wav . Then you will see both of those files in the Assets folder on your harddrive.

    Assets Folder Listing

    They will also appear in the Assets folder inside the Unity editor.

    Assets Folder in Unity

Back to TOC

Sound Effect for Mining Blocks

  1. In the MineBlock script in Mono, add this line

      public AudioClip mineSound;
    

    at the top of the MineBlock class:

    MineSound Variable in MineBlock Class

  2. Save the MineBlock script in Mono.

    Save the MineBlock Script

  3. Go back to Unity. Select the Block prefab from the Assets folder and notice the Mine Sound field in the Mine Block (Script) component in the Inspector.

    Mine Sound Field in Mine Block Script Component

  4. Drag the dig_grass1 asset into that field.

    Adding dig_grass1 Asset to Mine Sound Field dig_grass1 Asset Added to Mine Sound Field

  5. Go back to Mono and add this line

      AudioSource.PlayClipAtPoint( mineSound, transform.position);
    

    inside the OnMouseDown function before the Destroy statement.

    PlayClip

  6. Save.

    Save the MineBlock Script

  7. Go back to Unity and save the scene and project.

    Save Scene Save Project

  8. Play the game.

    Run the Game

    If you have audio on your computer, you should now hear the familiar sound of a dirt block breaking when you click on a block.

  9. Stop the game.

    Stop the Game

Back to TOC

Sound Effect for Picking Up Dropped Blocks

Challenge: As an exercise, see if you can now add the sound effect for picking up dropped blocks without looking at the following instructions.

  1. In the PickUp script in Mono, add this line

      public AudioClip pickupSound;
    

    at the top of the PickUp class:

    PickUp Sound Varialbe in PickUp Class

  2. Save.

    Save the PickUp Script

  3. Back in Unity, select the DroppedBlock prefab and see the Pickup Sound field in the PickUp (Script) component in the Inspector.

    PickUp Sound Field in Script Component

  4. Drag the pop asset into that field.

    Adding Pop Asset to PickUp Sound Field Pop Asset Added to PickUp Sound Field

  5. Go back to Mono and add this line

      AudioSource.PlayClipAtPoint( pickupSound, transform.position);
    

    in the OnTriggerEnter function before the Destroy statement:

    PlayClip

  6. Save.

    Save PickUp Script

  7. Go back to Unity and save the scene and project.

    Save Scene Save Project

  8. Play the game.

    Run the Game

    After breaking a block to make it drop a dropped block, when you run your character into the dropped block you should hear the popping sound of the item being collected.

  9. Stop the game.

    Stop the Game

Back to TOC

Balance the Volume of Sound Effects

The walking/stepping sound effects that come as part of the FPSController may be too loud relative to the sound effects for breaking and picking up blocks. Let's turn the FPSController sound effects down a little.

  1. Select the FPSController game object in the Heirarchy View.

    Select FPSController Game Object

  2. In the Inspector View, adjust the Volume slider in the Audio Source componenent.

    Adjust Volume

    About half volume feels right to me, but adjust to suit yourself.

  3. Save the scene and project.

    Save Scene Save Project

  4. Play the game.

    Run the Game

  5. Stop the game.

    Stop the Game

  6. If unsatisfied with the volume balance, go back to step 2, otherwise continue to the next section.

Back to TOC

Terrain

Now that the basic breaking and collecting mechanics are in place, let's generate an actual terrain rather than a scattering of hand-placed blocks.

  1. Create a new C# Script called GenTerrain.

    Create GenTerrain C# Script

  2. Select the Plane game object.

    Select Plane Game Object

  3. Add the GenTerrain script as a componenet on the Plane game object.

    Adding GenTerrain Script to Plane GenTerrain Script Added to Plane

  4. Double click the GenTerrain script to open it in Mono.

    Open the GenTerrain Script

  5. Add this line

      public GameObject block;
    

    at the top of the GenTerrain class just before the Start function.

    Add Block Variable to GenTerrain Class

  6. Save.

    Save the GenTerrain Script

  7. Go back to Unity and see the Block field in the GenTerrain component in the Inspector for the Plane game object.

    GenTerrain Block Field

  8. Drag the Block prefab into that field.

    Adding Block Prefab to Block Field Block Prefab Added to Block Field

  9. Back in Mono, add these lines

      int i, j, k;
      int nk;
    
      int n = 32;
      int h = 8;
    
      for( j=-n; j<=n; j++)
      {
          for( i=-n; i<=n; i++)
          {
              nk = (int)( Mathf.Floor( h*( 1 + Mathf.Sin( 2*Mathf.PI*i/n) * Mathf.Sin( 2*Mathf.PI*j/n) )));
              for( k=0; k<nk; k++)
              {
                  Instantiate( block, new Vector3( i, k, j), Quaternion.identity);
              }
          }
      }
    

    to the Start function in the GenTerrain class:

    GenTerrain Start Function Code

  10. Save.

    Save the Script

  11. Back in Unity, select the FPSController game object

    Select FPSController

    and adjust its Position

    Adjust FPSController Position

    so that the player starts in the middle of the world and up high.

  12. Delete the manually placed blocks.

    Deleting Manually Placed Blocks Manually Placed Blocks Deleted

  13. Save the scene and project.

    Save Scene Save Project

  14. Play the game.

    Run the Game

  15. Stop the game.

    Stop the Game

Back to TOC

Optional Stuff

The following list of tasks can be done in any order and independently of the others. They are listed roughly in order of how much time they should probably take.

Back to TOC

Turn Off Shadows

  1. If you wish, you may turn off shadows for the Block and/or DroppedBlock prefabs.

    In the Mesh Renderer component, you can toggle both whether the object casts shadows and whether the object receives shadows.

Back to TOC

Animate Dropped Blocks

  1. Put this line

      transform.RotateAround( transform.position, Vector3.up, 100*Time.deltaTime);
    

    in the Update function of the PickUp class:

    The first argument transform.position specifies the center of the rotation. The second argument Vector3.up specifies the axis of rotation. The third argument, a multiple of Time.deltaTime specifies the speed of the rotation. Adjust that multiple 100 to suit.

Back to TOC

Add a Material to the Block Prefab

  1. Right click in the Assets folder and select to Create a Material asset.

    Create a Material

    It will be named New Material by default.

    New Material

    Rename it to BlockMaterial.

    Renamed to BlockMaterial

  2. Click the white color box toward the top of the Inspector for the BlockMaterial.

    Color Select Box

  3. Choose a color.

    Choose a Color

  4. Close the Color selector.

    Close the Color Selector

  5. Select the Block prefab in the Assets folder.

    Select the Block Prefab

  6. Click the little triangle to expand the Materials property of the Mesh Renderer component.

    Expand Mesh Renderer Materials

    See the Element 0 field.

    See the Element 0 Field

  7. Drag the BlockMaterial asset into that field

    Dropping the BlockMaterial Asset into the Element 0 Field BlockMaterial Dropped in the Element 0 Field

  8. Save the scene and project.

    Save Scene Save Project

  9. Play the game.

    Run the Game

    The blocks should now appear in whatever color you selected for the material.

  10. Stop the game.

    Stop the Game

Back to TOC

Add a Material to the DroppedBlock Prefab

Exercise: Complete this task on your own. Make the game play the pop.wav sound when the player picks up a dropped block.

Back to TOC

Score Counter / Inventory

  1. Create | UI | Text

    Create a UI Text Object

    Create a UI Text game object in the Hiearchy View. It will appear as a child of a Canvas object which get automatically created for this purpose.

    Select the UI Text Object

    There is also an EventSystem game object that is created automatically at this point which we will ignore for now.

  2. Set an Anchor Preset.

    Select the Anchor Preset menu

    Select the Anchor Preset menu in the Inspector for the Text game object.

    Anchor Preset Menu

    Hold down the Alt key. See how the annotations change to signify position.

    Anchor Preset Menu with Alk Key Down

    Select a desired position. I propose the bottom middle since that is where the Minecraft hotbar is displayed.

    Anchor Preset Selected

  3. Change the contents of the Text field from New Text to 0.

    Changing The Default Text

    Default Text Changed

  4. Increase the font size a bit:

    Increase Font Size

  5. Center the text by clicking the center Alignment button in the Paragraph section.

    Center the Text

  6. Go to Mono and select the PickUp script tab.

    Select Pickup Script Tab

  7. Add this using directive

      using UnityEngine.UI;
    

    at the top of the file:

    Using UnityEngine.UI

    This will allow us to access the Text component of the Text game object.

  8. Add this private static variable declaration

      private static int numCollected = 0;
    

    and this private variable declaration

      private Text numCollectedText;
    

    at the beginning of the PickUp class:

    Num Collected Vars in PickUp Script

  9. Put this line

      numCollectedText = GameObject.Find("Text").GetComponent<Text>();
    

    in the Start function:

    Code to Find Text Object

  10. Finally, put these lines

      numCollected++;
      numCollectedText.text = numCollected.ToString();
    

    in the OnTriggerEnter function:

    Lines to Update Num Collected

  11. Save.

    Save the Script

  12. Go back to Unity and save the scene and project.

    Save Scene Save Project

  13. Play the game.

    Run the Game

    See the counter increment whenever you pick up a dropped block.

  14. Stop the game.

    Stop the Game

Back to TOC

More Elaborate Mouse Lock Mechanism

We will replace the cursor pointer with crosshairs and allow for relocking after unlocking.

Back to TOC

Replace Cursor Pointer with Crosshairs

This task involves first making an image of crosshairs. The following instructions are for GIMP, the GNU Image Manipulation Program, which is a free image editing application similar in functionality to Photoshop. Feel free to produce the image in whatever image editing application you prefer or even just find an image of crosshairs online. (The image file format can be PNG or JPG. Maybe it can be other formats, too, but I'm not sure.)

  1. Run GIMP and create a new image.

    New GIMP Image

    Adjust the size to something fairly small and probably square is best. For the tutorial, we'll do a 16×16 image.

    Size the New Image

    Click Okay to create the new image.

    Click Okay

    In the zoom dropdown menu select 800%.

    Zoom

    That way we can edit the image pixels easily.

    Zoomed

  2. Select the Pencil Tool from the Toolbox window.

    Select Pencil Tool

    Make sure that under Tool Options the Mode is Normal and the Brush is 1. Pixel and the Size is 1.00.

  3. Draw horizontal and vertical lines for crosshairs.

    Draw Lines

    Maybe decorate them a bit.

    Decorate

    Feel free to draw your crosshairs however you like. They don't have to look the same as this.

  4. Make the white background of the crosshairs transparent.

    Make Background Transparent

    Select Color To Alpha... from the Colors menu.

    Click Okay

    It should default to white as the color to convert to Alpha, i.e., make transparent, so just click Okay.

    Transparent

  5. Export the image to a PNG file.

    Export

    Expand the Select File Type menu.

    Expand File Type Menu

    Expanded, it will show a list of file types to select from:

    Expanded

    Select PNG image.

    Select PNG

    Now name the file crosshairs.png.bytes.

    Name the File

    Select the Assets folder of your project to save it in and then click the Export button.

    A PNG file with a .bytes extension on the file name is very unusual! Unity wants it that way, but GIMP is skeptical. You will need to confirm that you do want to go with that unusual name.

    Confirm Name

    You will be presented with another dialog window containing various options.

    Export Options

    Just click the Export button to accept the defaults.

  6. Go to Unity and notice the new crosshairs.png asset in the Assets folder.

    New Crosshairs Asset

  7. Go to the MouseLock script in Mono and add these lines

      public TextAsset crossHairsRaw;
      private Texture2D crossHairs;
    

    at the top of the MouseLock class:

    MouseLock Texture Variables

  8. Put these lines

      crossHairs = new Texture2D(16,16);
      crossHairs.LoadImage(crossHairsRaw.bytes);
      Cursor.SetCursor( crossHairs, new Vector2(8,8), CursorMode.Auto);
    

    in the Start function of the MouseLock class after the line that sets the cursor lock state:

    MouseLock Load Image

    If you created a crosshairs image that is bigger than 16×16, you'll need to adjust the numbers for the size of the Texture2D object and the Vector2 argument in the SetCursor function call. The Vector2 object specifies which point inside the image should be used as the cursor point. For a crosshairs shaped cursor it makes sense for it to be in the middle of the cursor image.

  9. Put this line

      Cursor.SetCursor( null, Vector2.zero, CursorMode.Auto);
    

    inside the if statement of the Update function after the line that unlocks the cursor:

    MouseLock Reset Cursor

    That sets the cursor back to the default. Vector2.zero means coordinates (0,0) which are at the top left corner of the cursor image which corresponds to the tip of the point of the default cursor.

  10. Save.

    Save the Script

  11. Now go back to Unity and select the FPSController in the Hierarchy View.

    Select FPSController

    Scroll down in the Inspector View for the FPSController and notice the Cross Hairs Raw field in the Mouse Lock (Script) component.

  12. Drag the crosshairs.png asset into that Cross Hairs Raw field of the Mouse Lock (Script) component.

    Adding Crosshairs to Script Field Crosshairs Added

  13. Save the scene and project.

    Save Scene Save Project

  14. Play the game.

    Run the Game

    The cursor should change to the crosshairs shape.

  15. Stop the game.

    Stop the Game

    You might have to stop and restart the game in order to get it to work. Also, when running the game inside the unity editor, the cursor many not change back from the crosshairs cursor when you press ESC, or at least not until you move the cursor outside of the Game View.

Back to TOC

Mechanism to Relock Cursor After Unlocking

  1. Mouse click to lock cursor. Add else if clause

      else if( Input.GetMouseButtonDown(0))
      {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.SetCursor( crossHairs, new Vector2(8,8), CursorMode.Auto);
      }
    

    after if statement in the Update function:

    As usual, this might not work flawlessly when running the game in the Unity editor. Try doing a File | Build & Run.

Back to TOC

Outline Blocks on Focus

We will use the Unity GL graphics library.

  1. Create a new C# script.

    Create Script

  2. Call it WireFrame.

    Name it WireFrame

  3. Attach it to the FirstPersonCharacter game object. The GL functions are typically called from a script attached to the camera, and our camera is in the FirstPersonCharacter. (See the Unity GL documentation for more information)

    Select FPSController Attach WireFrame to FPSController

  4. Double-click the WireFrame script asset to open it in Mono and add the following lines

      public Material wireMaterial;
      public GameObject targetBlock;
    

    at the top of the class:

    WireFrame Variable Declarations

    The wireMaterial object will be used for draw lines with GL. The targetBlock object will be the block which lines are to be drawn around.

  5. Save.

    Save the Script

  6. Go back to Unity and create a new Material asset.

    New Material

    Name it WireMaterial.

    Name it WireMaterial

    Change it to black.

    Change Material Color to Black

  7. Select the FirstPersonCharacter object and drag the WireMaterial asset into the corresponding field of the WireFrame script.

    Attach WireMaterial to WireFrame Script

  8. With the FirstPersonCharacter still selected, drag the Block prefab into the Target Block field of the WireFrame script.

    Attach Block Prefab to WireFrame Script

    Note that this is just temporary. In later steps, we will code the targetBlock to be assigned dynamically at run time based on which block the player is looking at.

  9. Open the MineBlock script in Mono and add the following line

      public GameObject fpsController;
    

    at the top of the class:

    MineBlock Variable Declaration

  10. Add this line

      fpsController = GameObject.Find("FirstPersonCharacter");
    

    to the Start function:

    MineBlock Find FPSController

  11. Add functions OnMouseEnter and OnMouseExit

      void OnMouseEnter()
      {
      }
    
      void OnMouseExit()
      {
      }
    

    at the bottom of the class after the OnMouseDown function:

    MineBlock OnMouseEnter and OnMouseExit

  12. Add this line

      fpsController.GetComponent<WireFrame>().targetBlock = gameObject;
    

    to the OnMouseEnter function:

    Set TargetBlock

    This assigns the Block game object that the player is pointing at to become the targetBlock in the WireFrame script. Now we need to code the WireFrame script to actually draw a wireframe around that block. (There is a loose end to the mechanism in MineBlock that we will take care of later. If the player looks away from a block but not at another block, the last block the player was looking at will remain highlighted with a wireframe. But let's not worry about that until the WireFrame script is actually drawing something.)

  13. Back in the WireFrame script add this function

      void OnPostRender()
      {
      }
    

    at the end of the class:

    WireFrame OnPostRender

  14. Add these lines

      if( targetBlock)
      {
          GL.PushMatrix();
          wireMaterial.SetPass(0);
          GL.Begin(GL.LINES);
          //
          // Left to right lines
          // TODO
          //
          // Up and down lines
          // TODO
          //
          // Front to back lines
          // TODO
          //
          GL.End();
          GL.PopMatrix();
      }
    

    to the OnPostRender function:

    WireFrame GL Framework

    There are three sets of four lines that need to be drawn around the cube. There is one set of four edges on a cube for each of the three directions in 3D space.

  15. The way a GL line works is by specifying the starting point and ending point of the line with two consecutive calls to GL.Vertex.

    The four lines in the right to left direction can be specified relative to the targetBlock.transform.position like this:

      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.forward + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.forward + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.back + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.back + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.forward + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.forward + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.back + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.back + 0.51f*Vector3.down);
    

    The factor of 0.51 is to make the lines hover a slight bit out from the actual edges of the cube (just like in Minecraft, as you may have noticed).

    The four lines going up and down can be specified like this:

      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.forward + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.forward + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.back + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.back + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.forward + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.forward + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.back + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.back + 0.51f*Vector3.down);
    

    And the four lines along the front to back edges of the cube can be specified like this:

      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.forward + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.back + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.forward + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.left + 0.51f*Vector3.back + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.forward + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.back + 0.51f*Vector3.up);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.forward + 0.51f*Vector3.down);
      GL.Vertex( targetBlock.transform.position + 0.51f*Vector3.right + 0.51f*Vector3.back + 0.51f*Vector3.down);
    

    Replacing each respective TODO in the OnPostRender function with the above lines of code results in this:

    WireFrame Lines

    The if statement checks to be sure targetBlock exists before attempting to wire frame it. This prevents Unity from becoming confused by targetBlock.transform after the player clicks and breaks the block that they are looking at. It doesn't make sense to access the transform of a game object that no longer exists.

  16. Finally, let's tie up the loose end mentioned above. Currently, if the player moves the cursor off of a block and into the sky or plane or something other than another block, that last block that the player was looking at remains highlighted with a wire frame.

    Add this line

      public bool drawWireFrame;
    

    to the top of the MineBlock class:

    MineBlock DrawWireFrame Variable Declaration

  17. Add this line

      drawWireFrame = false;
    

    to the Start function:

    Init DrawWireFrame Variable

  18. Set drawWireFrame to true in OnMouseEnter and set it to false in OnMouseExit.

    DrawWireFrame Toggle

  19. Now, in the WireFrame script, augment the condition in the if statement as follows:

      if( targetBlock && targetBlock.GetComponent<MineBlock>().drawWireFrame)
    

    DrawWireFrame Condition

Back to TOC

Texture Map the Blocks

  1. TODO

































































About

Tutorial on making basic Minecraft game mechanics in Unity.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published