Minecraft on the Raspberry Pi is a little different to the version you might have played on another computer or games console. As well as there being no creepers to contend with, there’s also the built-in ability to hack and modify Minecraft.
The full article can be found in The MagPi 41
In the past, we’ve shown you some simple ways to interact with Minecraft using Python; however, you can connect up much more than a simple Python script. Whether it’s other software, such as Sonic Pi, controlling the game with hardware like the Sense HAT, or even having Minecraft control things in the real world, there’s a lot more to try out. So get your Raspberry Pi out and let’s mash up some Minecraft!
Minecraft Python API
here are a few ways to program Minecraft on Raspberry Pi, and we’ll be talking about those in the rest of the feature. The most popular way to mod it, however, is by using the included Python library. If you’ve ever used Python, the syntax and logic of the code remains the same, only now there are functions that link directly into Minecraft!
As we’re programming in Python, we can also connect Minecraft to the real world via the GPIO pins or any attached hardware that works with Python, such as the Pi Camera or Sense HAT. Here’s how to get started...
Code: Location
Usage: getPos()
Example: position = mc.player.getPos() will give a list of coordinates for the player’s current position
from mcpi.minecraft import Minecraft mc = Minecraft.create() print mc.player.getPos() Vec3(5.67561,0.0,6.55693)
This returns the player’s position in the world as three numbers. The first number on the X-axis indicates how far forward or back the player is from the centre. The second number is how far left or right they are, or the Y-axis. The last number, the Z-axis, is the height in blocks from ground level.
Code: Teleport
Usage: .setPos(x,y,z)
Example: mc.player.setPos(0.0, 0.0, 0.0) will teleport the player to the centre of the map
mc.player.setPos(10.0,12.0,5.0) mc.player.setPos(10.0,12.0,-5.0)
Using the same coordinate system of X, Y and Z from getPos(), you can move the player around the map as you see fit. You’ll have to figure out the coordinates you want to move to via testing, or by using getPos() at the desired spot.
Code: Block type
Usage: getBlock(x,y,z)
Example: block = mc.
getBlock(0,0,0) sets variable block as the type of block at the centre of the map
print mc.getBlock(10.0,3.0,-5.0) 3 print mc.getBlock(5,-1,7) 12
Each block type has a name and identification number for it; for example, AIR has the ID of 0. Using the getBlock function, you can figure out what kind of block is at certain coordinates: this is useful for figuring out where a player is in your code if you need to trigger a certain event.
Code: Create a block
Usage: .setBlock(x,y,z,ID)
Example: mc.setBlock(0,0,0, block.OBSIDIAN.id) will create a block of obsidian in the centre of the map
mc.setBlock(10.0,0.0,-1.0, block.OBSIDIAN.id) mc.setBlock(10.0,0.0,-2.0, block.OBSIDIAN.id) mc.setBlock(9.0,2.0,-2.0, block.ICE.id)
Create any kind of block wherever you want it in the world. You can see how this works in CrazySqueak’s code next, as he has created lava, water, and empty spaces as part of the Natural Disasters program. You can also create a chunk of blocks with a range of coordinates.
Create natural disaster in Minecraft
I have created natural disasters in Minecraft using Python,” ten-year-old CrazySqueak writes on his blog. “It adds many disasters to your Minecraft that happen randomly, wherever you are in your world. The program randomly starts disasters on its own, so you should keep moving to avoid getting hit.”
This excellent Python script for Minecraft does something very different from other Python hacks that require player interaction: it actually adds to the world in the way a normal PC game mod might. With earthquakes, sinkholes, meteors, geysers, and volcanic eruptions each acting differently and independently, a lot of work has gone into this program.
The code works by setting up the parameters of each disaster. Each type has individual timing for when it occurs, once triggered, and how long it works for. They all use the Minecraft Python API (discussed over the page) to create or remove blocks, such as creating lava for the eruption and meteor, or creating an empty space with the sinkhole and earthquake.
All the disasters are triggered at random in the code, and are based around your location in the game – that’s why CrazySqueak suggests staying on the move! You can also trigger each function individually to see how it works, and some even come with sound clips to further add to the effect of the mod.
As well as creating natural disasters, CrazySqueak received a Highly Commended award for a submission to Astro Pi. We can’t wait to see what other mashups he creates for Minecraft in the future.
Code listing
You can download the full code, along with the accompanying sound clips, from CrazySqueak's website. The code is also below for reference.
import mcpi.minecraft as minc import mcpi.block as block mc = minc.Minecraft.create() import random, time, pygame pygame.mixer.init() earthSound = pygame.mixer.Sound('earthquake.ogg') eruptSound = pygame.mixer.Sound('lava.ogg') meteorSound = pygame.mixer.Sound('meteor.ogg') def earthquake(x, z): mc.postToChat('Earthquake!') y = mc.getHeight(x, z) endtime = time.time() + 60 nearthtime = time.time() while endtime > time.time(): if time.time() > nearthtime: earthSound.play() nearthtime = time.time() + 5 ppos = mc.player.getPos() if ppos.x < x+15 and ppos.x > x-15: if ppos.y < y+15 and ppos.y > -60: if ppos.z < z+15 and ppos.z > z-15: mc.player.setPos(ppos.x, ppos.y, ppos.z) bx = random.randint(x-15, x+15) by = y bz = random.randint(z-15, z+15) if mc.getHeight(bx, bz) > -50: by = mc.getHeight(bx, bz) if mc.getBlock(bx, by, bz) in [block.GLASS.id, block.GLASS_PANE.id]: mc.setBlock(bx, by, bz, block.AIR.id) continue mc.setBlock(bx, by, bz, block.GRAVEL.id) mc.setBlocks(bx, by-1, bz, bx, -60, bz, block.AIR.id) def sinkhole(x, z): blks = [] y = mc.getHeight(x, z) xdist = random.randint(1, 5) for bx in range(-xdist, xdist+1): zdist = random.randint(1, 5) for bz in range(-zdist, zdist+1): blks.append([x+bx, z+bz]) earthSound.play() for blk in blks: mc.setBlocks(blk[0], mc.getHeight(blk[0], blk[1]), blk[1], blk[0], -60, blk[1], block.AIR.id) mc.setBlocks(blk[0], -55, blk[1], blk[0], -60, blk[1], block.LAVA.id) for blk in blks: mc.setBlock(blk[0], y, blk[1], block.GRAVEL.id) def geyser(x, z): y = mc.getHeight(x, z) mc.setBlocks(x-2, y+5, z-2, x+2, -60, z+2, block.WATER.id) time.sleep(25) mc.setBlocks(x-2, y+5, z-2, x+2, -60, z+2, block.AIR.id) def eruption(x, z): y = mc.getHeight(x, z) for i in range(3): eruptSound.play() mc.setBlocks(x-2, y+9, z-2, x+2, y+9, z+2, block.LAVA.id) eruptSound.play() for i in range(15): time.sleep(1) eruptSound.play() eruptSound.play() mc.setBlocks(x-2, y+10, z-2, x+2, y+10, z+2, block.WATER.id) eruptSound.play() for i in range(5): time.sleep(1) eruptSound.play() eruptSound.play() mc.setBlocks(x-2, y+10, z-2, x+2, y+10, z+2, block.AIR.id) eruptSound.play() for i in range(5): time.sleep(1) eruptSound.play() eruptSound.play() y += 1 eruptSound.play() def meteor(x, z): mc.postToChat('Meteor approaching!') y = 64 h = mc.getHeight(x, z) x -= (64 - h) meteorSound.play() while y > h: y -= 1 x += 1 mc.setBlocks(x-2, y-2, z-2, x+2, y+2, z+2, block.OBSIDIAN.id) time.sleep(0.05) mc.setBlocks(x-2, y-2, z-2, x+2, y+2, z+2, block.AIR.id) mc.setBlocks(x-2, y-2, z-2, x+2, y+2, z+2, block.LAVA.id) mc.setBlocks(x-1, y-1, z-1, x+1, y+1, z+1, block.OBSIDIAN.id) def meteor_shower(x, z): for i in range(10): mx = random.randint(x-15, x+15) mz = random.randint(z-15, z+15) meteor(mx, mz) def heatwave(x, z): y = mc.getHeight(x, z) endtime = time.time() + random.randint(50, 90) while time.time() < endtime: blkid = block.AIR.id while blkid == block.AIR.id: bx = random.randint(x-10, x+10) by = random.randint(y, y+10) bz = random.randint(z-10, z+10) blkid = mc.getBlockWithData(bx, by, bz).id blk = blkid blkd = mc.getBlockWithData(bx, by, bz).data if blkid == block.GRASS.id: blk = block.DIRT.id blkd = 0 elif blkid in [block.WATER.id, block.WATER_FLOWING.id, block.WATER_STATIONARY.id]: blk = block.WATER.id blkd = 1 elif blkid == block.LEAVES.id: blk = block.COBWEB.id blkd = 0 elif blkid == block.WOOD.id: blk = block.LAVA_STATIONARY.id blkd = 1 mc.setBlock(bx, by, bz, blk, blkd) def tsunami(x, z): tend = time.time() + 15 tx = x while time.time() < tend: h = mc.getHeight(tx, z) mc.setBlocks(tx, h-5, z-5, tx, h+5, z+5, block.WATER_STATIONARY.id) time.sleep(0.1) mc.setBlocks(tx, h-5, z-5, tx, h+5, z+5, block.AIR.id) time.sleep(0.1) tx += 1 hm = 5 while hm > -1: h = mc.getHeight(tx, z) mc.setBlocks(tx, h-int(hm), z-5, tx, h+int(hm), z+5, block.WATER_STATIONARY.id) time.sleep(0.1) mc.setBlocks(tx, h-int(hm), z-5, tx, h+int(hm), z+5, block.AIR.id) time.sleep(0.1) tx += 1 hm -= 0.2 disasters = [tsunami, heatwave, meteor, meteor_shower, geyser, earthquake, sinkhole] def main(disasters, mc): baseed = random.randint(1, 10000) while True: t = random.randint(15, 180) t = 15 time.sleep(t) random.seed(baseed + t) baseed = random.randint(1, 10000) random.shuffle(disasters) disaster = random.choice(disasters) ppos = mc.player.getTilePos() #mc.postToChat(str(disaster) + ' in') #for c in range(3, 0, -1): # mc.postToChat(str(c)) # time.sleep(0.33) disaster(ppos.x, ppos.z) try: import _thread as thread except ImportError: import thread thread.start_new_thread(main, (disasters, mc))
Carry on to Minecraft Mashups part two.