Learning to program with Minecraft
Let's Get Fracking!
"Hello World!" programs are dumb, so you're going to dive right in and make a game within Minecraft – call it Treasure Hunt. The aim of the game is to find (and demolish!) a diamond block that has been hidden (buried) somewhere in the Minecraft world. Every 10 seconds, the program will post "Colder!" or "Warmer!" to the chat screen, depending on whether you are farther from or closer to the hidden block than the last time you checked (see the game program in Listing 1).
Listing 1
treasureHunt.py
01 import random, math, time 02 03 import mcpi.block as block 04 import mcpi.minecraft as minecraft 05 mc=minecraft.Minecraft.create() 06 07 v_height=0 08 09 while v_height <= 0: 10 (tx, tz)=(random.randint(-125,125), random.randint(-125,125)) 11 v_height=mc.getHeight(tx, tz) 12 13 mc.setBlock(tx, v_height-2, tz, block.DIAMOND_BLOCK) 14 15 vdistance = math.sqrt(math.pow(mc.player.getTilePos().x-tx, 2) + math.pow(mc.player.getTilePos().z-tz, 2)) 16 17 while mc.getBlock(tx, v_height-2, tz)!=0: 18 19 vnewdistance=math.sqrt(math.pow(mc.player.getTilePos().x-tx,2)+ math.pow(mc.player.getTilePos().z-tz, 2)) 20 21 if vnewdistance == 0: mc.postToChat("Dig!") 22 elif vdistance > vnewdistance: mc.postToChat("Warmer!") 23 elif vdistance < vnewdistance: mc.postToChat("Colder!") 24 else: mc.postToChat("Move!") 25 26 vdistance=vnewdistance 27 28 time.sleep(10) 29 30 mc.postToChat("Treasure found... And destroyed!") 31 mc.postToChat("Congratulations!")
Line 1 loads several standard Python modules you'll need later on. With the random
module, you'll pick a place to hide the treasure; math
comes with methods like sqrt
(square root) and pow
(power) that you'll need to calculate the distance from the player to the treasure. Finally, you'll need time
to post messages every 10 seconds.
Lines 3 and 4 import Minecraft-specific modules. The block
module allows you to manipulate blocks, and the minecraft
module allows you to know the player's position, to print messages to the chat window, and so forth.
Line 5 creates a connection to the running Minecraft server. Lines 3 to 5 will be pretty standard in all the Minecraft programs you write.
After loading all the necessary modules, the first thing you have to do is hide the treasure. The Pi version of Minecraft is 256 blocks wide on the x axis and 256 blocks deep on the z axis. Position (0,0) is the center of the grid. The y axis is up/down. I haven't been able to find the upper limit for the y axis, but 0 is sea level, which will be important later.
To keep things safe, the program will place the treasure within a square area that has 251 squares on a side (line 10). Even though you're avoiding the extreme edges (Minecraft Pi sometimes crashes when you play too close to the limits of the world), you still have a playing field of 63,001 blocks, and the treasure can be anywhere … or almost. To avoid burying the treasure under the sea (because that would be evil), you check to make sure the highest point of the chosen location is above sea level (lines 9 to 11) with getHeight()
, which is part of the Minecraft API.
So that the diamond is not immediately visible, you push it two layers under the surface (line 13). The setBlock
method used in this instruction is part of the Minecraft API (Table 2) and takes the x, y, z position of the block you want to modify, plus the type of block you want to transform it into. For a full list of the types of blocks you can use, check out the Minecraft: Pi Edition wiki [5].
Tabelle 2
Minecraft API Methods
Method | Arguments | Returns | Description |
---|---|---|---|
Minecraft Class: mc.[method] |
|||
|
x, y, z |
blockId: int |
Get the block ID at the named coordinates |
|
x, y, z |
vec3: obj |
Get a block object at named coordinates |
|
x0, y0, z0, x1, y1, z1 |
[int] |
Get block IDs in cuboid between two coordinates |
|
x, y, z, id, [state] |
|
Sets a block at coordinates; optional argument state is between 0 and 15 |
|
x0, y0, z0, x1, y1, z1, id, [state] |
|
Sets blocks between two sets of coordinates; optional argument state is between 0 and 15 |
|
x,z |
int |
Returns the highest block at a point |
|
|
[int] |
Returns the IDs of all players connected to the game |
|
|
|
Saves the current state of the game |
|
|
|
Restores the game to the latest saved state |
|
message: str |
|
Posts a message to the chat |
|
key, stat: bol |
|
Changes the settings of the world; key values: world_immutable, nametags_visible |
Player Class: mc.player.[method] |
|||
|
x, y, z |
vec3: obj |
Returns the player's position as an object with floats |
|
x, y, z |
|
Sets the player's position using floats |
|
x, y, z |
vec3: obj |
Returns the player's position as an object with integers |
|
x, y, z |
|
Sets the player's position using integers |
|
key, stat: bol |
|
Changes the player's settings; key value: autojump |
Events Class: mc.events.[method] |
|||
|
|
|
Clears all events from buffer |
|
|
[vec3: obj] |
Returns an array of block hits; block hits created with sword right-click |
Camera Class: mc.camera.[method] |
|||
|
[entityID] |
|
Sets the camera to normal for a list of player entities |
|
|
|
Sets the camera to fixed |
|
[entityId] |
|
Sets the camera to follow for a list of player entities |
|
x, y, z |
|
Sets the camera position to coordinates |
Entity Class: mc.entity.[method] |
|||
|
id: int |
vec3: obj |
Gets the position of the entity as floats |
|
entityId:int, x, y, z |
|
Sets the position of the entity |
|
entityId: int |
vec3: obj |
Returns the position of an entity as a vector with integers |
|
entityId:int, x, y, z |
|
Sets the position of an entity with integers |
|
entityId: int, key, stat: bol |
|
Changes the entity's settings; key value: autojump |
An unexpected effect of the code as described is that the diamond is not only underground but can also be hidden under a tree. Because this adds a little more challenge to the game, I decided to leave it as is.
Minesweep
Before entering the main loop of the game, you first measure the distance from the point at which the player starts to the diamond stash (line 15). Note that the distance to the treasure is as the crow flies. Vertical distance is not taken into account. The coordinates of the treasure are stored in tx
and ty
, and you can determine player position by using the player.getTilePos()
Minecraft method. This method returns a vector with three attributes: x
, y
and z
. So, you can find out the x component of your player's coordinates by calling:
mc.player.getTilePos().x
Just change the trailing x
, for y
or z
to get the corresponding components of the player's coordinates. This, by the way, is called dot notation.
You will have learned from geometry that the way to calculate a distance between two points (your player and the diamond) on a grid is by using the Pythagorean theorem (Figure 2). The difference between mc.player.getTilePos().x
and tx
is the length of one of the legs of a right triangle and the difference between mc.player.getTilePos().z
and tz
is the length of the other leg. The hypotenuse of your imaginary triangle is the distance between the two points: In Python, that calculation looks like line 15.
The aim of the game is to locate and destroy the diamond, so now you create a loop that uses the Minecraft method getBlock()
to check the content of the diamond's location (line 17). As soon as the location contains air (i.e., 0
, which is the numeric value for a block of type AIR
[5]), the diamond has been destroyed and the loop will exit. Meanwhile, you must check the player position every 10 seconds to see if it is any closer to or farther from the treasure (lines 21-24).
If the distance is 0 (i.e., the player has arrived at the correct location), the program uses the postToChat()
Minecraft method to show a Dig! message in the chat window. If the distance has decreased since the last time you checked, you post Warmer! (Figure 3); if it has increased (i.e., the player has moved farther away from the goal), you'll post Colder!. If the distance hasn't changed, you can assume the player hasn't moved and you post the incentive Move!.
The new distance becomes the old distance (line 26), then the program waits for 10 seconds (line 28) for the player to move, and the cycle starts again.
As soon as the player locates (Figure 4) and destroys the diamond, the loop exits, and the program congratulates the player (Figure 5) and ends.
« Previous 1 2 3 Next »
Buy this article as PDF
Pages: 6
(incl. VAT)