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.
- Preliminaries
- Basic Objects and Mechanics
- First Person Character
- Build the Game
- Pickup Mechanic
- Sound Effects
- Terrain
- Optional Stuff
Create a 3D project and select the default layout in the editor.
-
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 theFile
menu.)Name the project.
3D should be highlighted.
Click the create the project.
-
Select the default layout.
Here we build the ground, the block prefab, and the item drop prefab.
You can think of the following as a quick and dirty substitute for a layer of bedrock.
-
Hierarchy | Create | 3D Object | Plane
In the
Hierarchy View
, click theCreate
dropdown, select3D Object
and thenPlane
. -
Inspector | Transform | Scale ( 16, 1, 16)
Scale the plane in the
x
andz
directions for plenty of room to play on. TheInspector
shows the components of the game object that is selected in theHierarchy View
, so make sure thePlane
game object is selected in theHierarchy View
before modifying theTransform
component. -
Inspector | Transform | Position ( 0, -0.5, 0)
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.
We will now make a block that disappears when clicked on.
-
Hierarchy | Create | 3D Object | Cube
Create a
Cube
game object. -
In the
Inspector
, renameCube
toBlock
.Select the
Cube
game object in theHierarchy View
first.Click on
Cube
in the field at the very top of theInspector View
.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.
-
Drag the
Block
game object from theHierarchy View
into theAssets
folder of theProject View
.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.
-
Drag a few
Block
prefabs into the scene. -
In the
Inspector
for each block, manually assign their position coordinates to be integers and make them all havey=0
in particular.Observe that Unity automatically numbers the game objects generated from prefabs.
-
File | Save Scene
Select
File
andSave 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 theAssets
folder of theProject View
. -
File | Save Project
Select
File
andSave Project
.The project already has a name from when we created it, so there will not be a prompt for naming it.
-
In the
Assets
folder of theProject View
, right-click and selectCreate | C# Script
-
Rename it to
MineBlock
.Its default name is
NewBehavior
. Just type over that to change it toMineBlock
.Now double-click the
MineBlock
C# asset. That will cause the script to be loaded in Mono.There is a
Start
function and anUpdate
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.
-
Go back to Unity and select the
Block
prefab.Now click and drag the
MineBlock
script asset over to theAdd Component
button in theInspector View
for theBlock
prefab and drop it there.The
MineBlock
script will be added as a component to theBlock
prefab.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.) -
Go back to Mono and add the following
OnMouseDown
function to theMineBlock
script.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.
-
Save the script in Mono.
-
Go back to Unity and run the game by clicking on the play button.

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

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.
- Save the scene and the project.
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.)
-
In the
Hierarchy View
, select theBlock
game object. -
In the
Inspector View
, uncheck the checkbox next to the game object's name field.That game object should no longer appear in the scene. It is still listed in the
Hierarchy View
although dimmed.
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.
-
Hierarchy | Create | 3D Object | Cube
Create another
Cube
game object. -
Rename it
DroppedBlock
. -
Inspector | Transform | Scale (0.5,0.5,0.5)
Make it smaller.
-
Inspector | Transform | Rotate (15,0,5)
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.
-
Make a prefab from the
DroppedBlock
game object by dragging it into theAssets
folder of theProject View
. -
Select the source
DroppedBlock
Game Object and hide it. -
Go to Mono and edit the
MineBlock
script by adding this linepublic GameObject droppedBlockPrefab;
before the Start function:
-
Go back to Unity and select the
Block
prefab.Look at the
Inspector View
and see theDropped Block Prefab
field in theMine Block (Script)
component.That field was put there automatically by the Unity editor after we declared the
droppedBlockPrefab
variable in theMineBlock
script.Now drag the
DroppedBlock
prefab into thatDropped Block Prefab
field.This will cause the
droppedBlockPrefab
variable in theMineBlock
script to be initialized to theDroppedBlock
prefab when the game runs. It is in this way that our script will have access to that prefab. -
Finally, add this line
Instantiate( droppedBlockPrefab, transform.position, droppedBlockPrefab.transform.rotation);
to the
OnMouseDown
function of theMineBlock
script right before theDestroy
statement.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 theInspector
for theDroppedBlock
prefab. -
Save the script.
-
Go back to Unity and save the scene and project.
-
Play the game.
See that when you click a
Block
game object, aDroppedBlock
game object appears in its place. -
Stop the game.
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
:
and download/import Standard Assets
from there instead.
-
Assets | 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 theAsset Store
. -
Click the "None" button to uncheck all of the options.
-
Click the checkbox next to
FirstPersonCharacter
.Now just the
FirstPersonCharacter
asset is selected. -
Click the
Import
button.Notice the new
StandardAssets
folder inside yourAssets
folder of theProject View
.You will also notice an error message in the Unity status bar. If you click the
Console
tab next to theProject
tab, you will see other messages, too. There are a couple of dependencies that we need to import before we can use theFirstPersonCharacter
standard asset. -
Assets | Import Package | CrossPlatformInput
And now there is a new folder named
Editor
inside theAssets
folder of theProject View
. -
Assets | Import Package | Utility
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.
-
Under the
Assets
folder in theProject View
, expandStandardAssets
,Characters
,FirstPersonCharacter
, and then selectPrefabs
.Notice the
FPSController
prefab. That's what we are going to use. -
Drag the
FPSController
prefab into the scene.Drop it somewhere near the current camera.
-
Remove the old camera which is called
Main Camera
.The
FPSController
prefab comes with its own camera built in. -
Adjust the
y
coordinate of theFPSController
position so that it is completely above the plane, e.g.,y=2
.It's okay if it starts higher than the plane. It will fall to the surface when the game begins.
-
Save the scene and project.
-
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 theSPACE
bar to make it jump. -
Stop the game.
-
Adjust the scale of the
FPSController
to(0.5,0.9,0.5)
.This will make it possible for the character to fit through one block wide and two block high openings (eventually).
-
Save.
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).
-
Select the
Assets
folder in theProject View
and create a newC# Script
. -
Rename the new script to
MouseLock
. -
Select the FPSController game object.
-
Scroll down in the
Inspector View
until theAdd Component
button is visible. -
Drag the
MouseLock
asset onto theAdd Component
button of theInspector
for theFPSController
.Now the
Mouse Lock (Script)
component should appear in the list of components for theFPSController
. -
Double-click the
MouseLock
C# asset in theProject View
to open it in Mono.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 newMouseLock
script that we will edit now. -
To lock the mouse cursor when the game begins, put this line
Cursor.lockState = CursorLockMode.Locked;
in the
Start
function. -
To unlock the mouse cursor when the user presses the
ESC
key, put these linesif( Input.GetKeyDown("escape")) { Cursor.lockState = CursorLockMode.None; }
in the
Update
function. -
Save the script.
-
Go back to Unity and save the scene and the project.
-
Run the game.
If you're lucky, the mouse cursor will lock in the middle of the
Game View
until you hit theESC
key.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. -
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.)
-
File | Build Settings...
From the
File
menu, selectBuild Settings...
. -
PC, Mac & Linux Standalone
.From the
Platform
list, selectPC, Mac & Linux Standalone
. -
Target Platform
Select your operating system from the
Target Platform
menu. -
Click the
Build And Run
button. -
Name the application something like
MakingMinecraft
. -
Click
Save
. -
Select your desired resolution from the
Configuration
dialog that pops up. -
Check the
Windowed
check box.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.)
-
Play!
Click the
Play!
button and enjoy playing the game as a native application.When finished playing, press
ESC
to unlock the cursor and then close the application. -
Back in Unity, close the
Build Settings
window.
When the player runs into a dropped block, the dropped block game object should disappear as the player “picks up” the item.
-
Select the
DroppedBlock
prefab in theAssets
folder of theProject View
. -
In the
Inspector View
, check theIs Trigger
check box of theBox Collider
component. -
In the
Assets
folder, create a new C# Script. -
Rename it to
PickUp
. -
Select the
DroppedBlock
prefab again. -
Drag the
PickUp
script over to theAdd Component
button in theInspector
for theDroppedBlock
prefab.Then the
Pick Up (Script)
component should appear in the list of components in theInspector
for theDroppedBlock
prefab. -
Save the scene and project.
-
Double-click the
PickUp
script to open it in Mono.Now you will see three tabs in Mono with the one for the
PickUp
script in front. -
Add the following
OnTriggerEnter
functionvoid OnTriggerEnter() { Destroy( gameObject); }
after the
Update
function like this: -
Save the script.
-
Back in Unity, 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.
-
Stop the game.
Breaking blocks and collecting dropped items is much more satisfying with sound effects!
-
Download the following two
wav
files:Save them in the
Assets
folder.Do that with both files:
dig_grass1.wav
andpop.wav
. Then you will see both of those files in theAssets
folder on your harddrive.They will also appear in the
Assets
folder inside the Unity editor.
-
In the
MineBlock
script in Mono, add this linepublic AudioClip mineSound;
at the top of the
MineBlock
class: -
Save the
MineBlock
script in Mono. -
Go back to Unity. Select the Block prefab from the
Assets
folder and notice theMine Sound
field in theMine Block (Script)
component in theInspector
. -
Drag the
dig_grass1
asset into that field. -
Go back to Mono and add this line
AudioSource.PlayClipAtPoint( mineSound, transform.position);
inside the
OnMouseDown
function before theDestroy
statement. -
Save.
-
Go back to Unity and save the scene and project.
-
Play 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.
-
Stop the game.
Challenge: As an exercise, see if you can now add the sound effect for picking up dropped blocks without looking at the following instructions.
-
In the
PickUp
script in Mono, add this linepublic AudioClip pickupSound;
at the top of the
PickUp
class: -
Save.
-
Back in Unity, select the
DroppedBlock
prefab and see thePickup Sound
field in thePickUp (Script)
component in theInspector
. -
Drag the
pop
asset into that field. -
Go back to Mono and add this line
AudioSource.PlayClipAtPoint( pickupSound, transform.position);
in the
OnTriggerEnter
function before theDestroy
statement: -
Save.
-
Go back to Unity and save the scene and project.
-
Play 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.
-
Stop the game.
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.
-
Select the
FPSController
game object in theHeirarchy View
. -
In the
Inspector View
, adjust theVolume
slider in theAudio Source
componenent.About half volume feels right to me, but adjust to suit yourself.
-
Save the scene and project.
-
Play the game.
-
Stop the game.
-
If unsatisfied with the volume balance, go back to step 2, otherwise continue to the next section.
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.
-
Create a new C# Script called
GenTerrain
. -
Select the
Plane
game object. -
Add the
GenTerrain
script as a componenet on thePlane
game object. -
Double click the
GenTerrain
script to open it in Mono. -
Add this line
public GameObject block;
at the top of the
GenTerrain
class just before theStart
function. -
Save.
-
Go back to Unity and see the
Block
field in theGenTerrain
component in theInspector
for thePlane
game object. -
Drag the
Block
prefab into that field. -
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 theGenTerrain
class: -
Save.
-
Back in Unity, select the
FPSController
game objectand adjust its
Position
so that the player starts in the middle of the world and up high.
-
Delete the manually placed blocks.
-
Save the scene and project.
-
Play the game.
-
Stop the game.
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.
-
If you wish, you may turn off shadows for the
Block
and/orDroppedBlock
prefabs.In the
Mesh Renderer
component, you can toggle both whether the object casts shadows and whether the object receives shadows.
-
Put this line
transform.RotateAround( transform.position, Vector3.up, 100*Time.deltaTime);
in the
Update
function of thePickUp
class:The first argument
transform.position
specifies the center of the rotation. The second argumentVector3.up
specifies the axis of rotation. The third argument, a multiple ofTime.deltaTime
specifies the speed of the rotation. Adjust that multiple100
to suit.
-
Right click in the
Assets
folder and select toCreate
aMaterial
asset.It will be named
New Material
by default.Rename it to
BlockMaterial
. -
Click the white color box toward the top of the
Inspector
for theBlockMaterial
. -
Choose a color.
-
Close the
Color
selector. -
Select the
Block
prefab in theAssets
folder. -
Click the little triangle to expand the
Materials
property of theMesh Renderer
component.See the
Element 0
field. -
Drag the
BlockMaterial
asset into that field -
Save the scene and project.
-
Play the game.
The blocks should now appear in whatever color you selected for the material.
-
Stop the game.
Exercise: Complete this task on your own. Make the game play the pop.wav
sound when the player picks up a dropped block.
-
Create | UI | Text
Create a
UI
Text
game object in theHiearchy View
. It will appear as a child of aCanvas
object which get automatically created for this purpose.There is also an
EventSystem
game object that is created automatically at this point which we will ignore for now. -
Set an
Anchor Preset
.Select the
Anchor Preset
menu in theInspector
for theText
game object.Hold down the
Alt
key. See how the annotations change to signify position.Select a desired position. I propose the bottom middle since that is where the Minecraft hotbar is displayed.
-
Change the contents of the
Text
field fromNew Text
to0
. -
Increase the font size a bit:
-
Center the text by clicking the center
Alignment
button in theParagraph
section. -
Go to Mono and select the
PickUp
script tab. -
Add this
using
directiveusing UnityEngine.UI;
at the top of the file:
This will allow us to access the
Text
component of theText
game object. -
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: -
Put this line
numCollectedText = GameObject.Find("Text").GetComponent<Text>();
in the Start function:
-
Finally, put these lines
numCollected++; numCollectedText.text = numCollected.ToString();
in the
OnTriggerEnter
function: -
Save.
-
Go back to Unity and save the scene and project.
-
Play the game.
See the counter increment whenever you pick up a dropped block.
-
Stop the game.
We will replace the cursor pointer with crosshairs and allow for relocking after unlocking.
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.)
-
Run GIMP and create a new image.
Adjust the size to something fairly small and probably square is best. For the tutorial, we'll do a 16×16 image.
Click
Okay
to create the new image.In the zoom dropdown menu select 800%.
That way we can edit the image pixels easily.
-
Select the
Pencil Tool
from theToolbox
window.Make sure that under
Tool Options
theMode
isNormal
and theBrush
is1. Pixel
and theSize
is1.00
. -
Draw horizontal and vertical lines for crosshairs.
Maybe decorate them a bit.
Feel free to draw your crosshairs however you like. They don't have to look the same as this.
-
Make the white background of the crosshairs transparent.
Select
Color To Alpha...
from theColors
menu.It should default to white as the color to convert to
Alpha
, i.e., make transparent, so just clickOkay
. -
Export the image to a
PNG
file.Expand the
Select File Type
menu.Expanded, it will show a list of file types to select from:
Select
PNG image
.Now name the file
crosshairs.png.bytes
.Select the
Assets
folder of your project to save it in and then click theExport
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.You will be presented with another dialog window containing various options.
Just click the
Export
button to accept the defaults. -
Go to Unity and notice the new
crosshairs.png
asset in theAssets
folder. -
Go to the
MouseLock
script in Mono and add these linespublic TextAsset crossHairsRaw; private Texture2D crossHairs;
at the top of the
MouseLock
class: -
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 theMouseLock
class after the line that sets the cursor lock state: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 theVector2
argument in theSetCursor
function call. TheVector2
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. -
Put this line
Cursor.SetCursor( null, Vector2.zero, CursorMode.Auto);
inside the
if
statement of theUpdate
function after the line that unlocks the 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. -
Save.
-
Now go back to Unity and select the
FPSController
in theHierarchy View
.Scroll down in the
Inspector View
for theFPSController
and notice theCross Hairs Raw
field in theMouse Lock (Script)
component. -
Drag the
crosshairs.png
asset into thatCross Hairs Raw
field of theMouse Lock (Script)
component. -
Save the scene and project.
-
Play the game.
The cursor should change to the crosshairs shape.
-
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 theGame View
.
-
Mouse click to lock cursor. Add
else if
clauseelse if( Input.GetMouseButtonDown(0)) { Cursor.lockState = CursorLockMode.Locked; Cursor.SetCursor( crossHairs, new Vector2(8,8), CursorMode.Auto); }
after
if
statement in theUpdate
function:As usual, this might not work flawlessly when running the game in the Unity editor. Try doing a
File | Build & Run
.
We will use the Unity GL graphics library.
-
Create a new C# script.
-
Call it
WireFrame
. -
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 theFirstPersonCharacter
. (See the Unity GL documentation for more information) -
Double-click the
WireFrame
script asset to open it in Mono and add the following linespublic Material wireMaterial; public GameObject targetBlock;
at the top of the class:
The
wireMaterial
object will be used for draw lines with GL. ThetargetBlock
object will be the block which lines are to be drawn around. -
Save.
-
Go back to Unity and create a new Material asset.
Name it
WireMaterial
.Change it to black.
-
Select the
FirstPersonCharacter
object and drag theWireMaterial
asset into the corresponding field of theWireFrame
script. -
With the
FirstPersonCharacter
still selected, drag theBlock
prefab into theTarget Block
field of theWireFrame
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. -
Open the
MineBlock
script in Mono and add the following linepublic GameObject fpsController;
at the top of the class:
-
Add this line
fpsController = GameObject.Find("FirstPersonCharacter");
to the
Start
function: -
Add functions
OnMouseEnter
andOnMouseExit
void OnMouseEnter() { } void OnMouseExit() { }
at the bottom of the class after the
OnMouseDown
function: -
Add this line
fpsController.GetComponent<WireFrame>().targetBlock = gameObject;
to the
OnMouseEnter
function:This assigns the
Block
game object that the player is pointing at to become thetargetBlock
in theWireFrame
script. Now we need to code theWireFrame
script to actually draw a wireframe around that block. (There is a loose end to the mechanism inMineBlock
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 theWireFrame
script is actually drawing something.) -
Back in the
WireFrame
script add this functionvoid OnPostRender() { }
at the end of the class:
-
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: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.
-
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 theOnPostRender
function with the above lines of code results in this:The
if
statement checks to be suretargetBlock
exists before attempting to wire frame it. This prevents Unity from becoming confused bytargetBlock.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. -
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: -
Add this line
drawWireFrame = false;
to the
Start
function: -
Set
drawWireFrame
totrue
inOnMouseEnter
and set it tofalse
inOnMouseExit
. -
Now, in the
WireFrame
script, augment the condition in theif
statement as follows:if( targetBlock && targetBlock.GetComponent<MineBlock>().drawWireFrame)
- TODO