Linux Format

Drawing with loops

Calvin Robinson mods Minecraft Pi to work on Linux, building 3D pixel art and shapes with Python loops and hoops.

- Calvin Robinson is a former assistant principal and Computer Science teacher with a degree in Computer Games Design and Programmin­g BSC (Hons).

Calvin Robinson mods Minecraft Pi to work on Linux, then builds 3D pixel art and shapes with Python, loops and pyramids.

This issue we’ll take our Minecraft pixel art into the third dimension, by building Pyramids with Python loops. We previously built some pixel art in Minecraft with two dimensions, so now we’re going to take a look at building 3D pixel art. Technicall­y, everything in Minecraft is 3D, but our previous pixel art was ‘flat’; this time we’re adding another axis to build upwards/outwards. We’re then going to hack our pixel art into another player’s game.

We’re going to start by building a pyramid using while loops and for loops in Python. The idea is that the loops will save us typing lots of similar lines of code, which will make life easier for us to create our prefabrica­ted designs. Spawning in our coded creations is so much faster than placing each individual block manually in Minecraft’s Creative mode.

If you’re using Minecraft Pi edition on a Raspberry Pi, no additional software is necessary. We’ve also put together a number of tools to ensure this hack works on Linux, with a retail version of Minecraft. Therefore as a prerequisi­te, we assume you’ve installed Mcpifomo from our previous three issues. Mcpifomo includes MCPIPY by ‘fleap’ and ‘bluepillra­bbit’ of Mcpipy.com and Raspberry Jam, developed by Alexander Pruss. Martin O’hanlon of www.stuffabout­code.com has put together some prefabrica­ted shape functions, which we’ll be using in this tutorial, available on Github.

All Python scripts should be saved in ~/home/ .Minecraft/mcpipy/, regardless of whether you’re running Minecraft Pi edition or retail Linux Minecraft. Be sure to run Minecraft with the Forge 1.8 profile that’s included in our Mcpifomo package.

Spawning variables

Git yourself a copy of Minecraft Stuff: git clone https://github.com/martinohan­lon/ minecraft-stuff

You could also visit Github and manually download Minecrafts­tuff.py, as that’s all we’ll need for this tutorial. Just make sure you pop it in the ~/home/ .Minecraft directory along with Mcpifomo.

Another way of installing Minecraft Stuff would be to use Python’s package index tool with sudo pip install Minecrafts­tuff or sudo pip3 install Minecrafts­tuff . We’re going to want to create a new PY file in our favourite text editor/idle and import all the relevant

Minecraft-related Python modules. Save your Python file in ~/home/.minecraft/mcpipy/. import mcpi.minecraft as Minecraft from mcpi import minecraft import mcpi.block as block import server import time import minecrafts­tuff

We’ll want to connect to our Minecraft world: mc = minecraft.minecraft.create()

Here we’re creating an instance with the variable mc

that we can use later on to spawn shapes directly into our open world. We’ll want to use this variable when initiating an instance of Minecrafts­tuff: mcdrawing = Minecrafts­tuff.minecraftd­rawing(mc) .

Now track our current location in-game and we’re good to go: playerpos = mc.player.gettilepos() . For our starter pyramid, we’re going to initiate a bunch of variables, collecting the player’s standing position pos = mc.player.gettilepos() , and breaking that down into x,y,z coordinate­s x = pos.x + 2, y = pos.y z = pos.z . x = pos.x + 2 y = pos.y z = pos.z

height = 29

count = 0 blockid = 24 blocktype = 1

We’ve also got variables for the height of our pyramid – we’ll get to that shortly. Below that we have blockid and blocktype , which will affect the blocks used to create our pyramid. Block ID 24:1 would be broken down to blockid 24, blocktype 1. We chose this as we felt Chiselled Sandstone looked quite ‘pyramid-y’ to begin with.

Let’s create our first loop to get the basic pyramid spawning, starting with a large base and then each row getting smaller and smaller until we reach the peak of the pyramid. while height - (2 * count) > 0: for block in range(height - (2 * count)): for row in range(height - (2 * count)): blockx = x + block + count blocky = y + count blockz = z + row + count mc.setblock(blockx, blocky, blockz, blockid, blocktype)

count += 1

We’ve already initialise­d variables for height and count. By changing the height, we can make our pyramid larger or smaller. count is used in the loop to make sure our pyramid stops on the number of rows we specified in height , starting at 0 and incrementi­ng upward with each cycle of the loop.

If we wrap our setblock command in conditiona­l if / else statements, we can alternate rows, using the

count variable to see if the row is an even number or an odd. We can place a different blockid on each row. Replace the current mc.setblock(blockx, blocky, blockz, blockid, blocktype line with:

if count % 2 == 0: mc.setblock(blockx, blocky, blockz, woolblockb­lack, woolblockb­lacktype) else: mc.setblock(blockx, blocky, blockz, woolblockg­reen, woolblockg­reentype)

Alternatin­g colours

Rather than setting the colour based on odds/evens, we can get more creative and make each row a different colour. Alter the if statement to include elif s for each row that you’d like to colour, but don’t forget to initialise blockid / blocktype variables: woolblock = 35 woolblockw­hitetype = 0 woolblockg­reentype = 5 if count == 0: mc.setblock(blockx, blocky, blockz, woolblock, woolblockb­lacktype) elif count == 1:

mc.setblock(blockx, blocky, blockz, woolblock, woolblocky­ellowtype) elif count == 2:

mc.setblock(blockx, blocky, blockz, woolblock, woolblockb­luetype) elif count == 3:

mc.setblock(blockx, blocky, blockz, woolblock, woolblockg­reentype) else:

mc.setblock(blockx, blocky, blockz, woolblock, woolblockw­hitetype)

Having a fancy if statement is great, but don’t forget the variables: woolblock = 35 woolblockg­reentype = 5 woolblockb­lacktype = 15 woolblocky­ellowtype = 4 woolblockb­luetype = 3 woolblockw­hitetype = 0

We should now be in a position to alter the height of our pyramids and the types of block used for each individual row, or to alternate the colour of rows depending on what suits our needs. Now is the time to get really creative and put that together to produce something original. You could also try reversing the for

loops to create an inverted pyramid.

When everything is pieced together, we should end up with something that looks a little like the following: import mcpi.minecraft as Minecraft from mcpi import minecraft import mcpi.block as block import server import time import minecrafts­tuff mc = minecraft.minecraft.create() pos = mc.player.gettilepos() x = pos.x + 2 y = pos.y z = pos.z height = 30 count = 0 woolblock = 35 woolblockw­hitetype = 15 woolblockg­reentype = 13 woolblockb­luetype = 4 woolblocky­ellowtype = 14 woolblockb­lacktype = 15

while height - (2 * count) > 0: for block in range(height - (2 * count)): for row in range(height - (2 * count)): blockx = x + block + count blocky = y + count blockz = z + row + count if count == 0: mc.setblock(blockx, blocky, blockz, woolblock, woolblockb­lacktype) elif count == 1: mc.setblock(blockx, blocky, blockz, woolblock, woolblocky­ellowtype) elif count == 2: mc.setblock(blockx, blocky, blockz, woolblock, woolblockb­luetype) elif count == 3: mc.setblock(blockx, blocky, blockz, woolblock, woolblockg­reentype) elif count == 4: mc.setblock(blockx, blocky, blockz, woolblock, woolblocky­ellowtype) elif count == 5: mc.setblock(blockx, blocky, blockz, woolblock, woolblockb­luetype) elif count == 6: mc.setblock(blockx, blocky, blockz, woolblock, woolblockg­reentype) elif count == 7: mc.setblock(blockx, blocky, blockz, woolblock, woolblocky­ellowtype) elif count == 8: mc.setblock(blockx, blocky, blockz, woolblock, woolblockb­luetype) elif count == 9: mc.setblock(blockx, blocky, blockz, woolblock, woolblockg­reentype) elif count == 10: mc.setblock(blockx, blocky, blockz, woolblock, woolblocky­ellowtype) elif count == 11: mc.setblock(blockx, blocky, blockz, woolblock, woolblockb­luetype) elif count == 12: mc.setblock(blockx, blocky, blockz, woolblock, woolblockg­reentype) else: mc.setblock(blockx, blocky, blockz, woolblock, woolblockw­hitetype) count += 1

We’ve got our pyramids down, so let’s take a look at the prefabrica­ted shapes we have available to us: drawline , drawsphere , drawcircle and frawface . We can spawn these shapes in our world with the

mcdrawing variable we set up a moment ago, but we’ll need to make sure we pass the coordinate­s to the function, as well as the type of blocks we’d like to use. For example:

mcdrawing.drawsphere(playerpos.x, playerpos.y, playerpos.z, 15, BLOCK.DIAMOND_BLOCK.ID)

The drawface function is a great tool for filling in surfaces. Think of it as a paint bucket from Photoshop. mcdrawing.drawline(x1,y1,z1,x2,y2,z2,blockid) mcdrawing.drawsphere(x,y,z,radius,blockid) mcdrawing.drawcircle(x,y,z,radius,blockid) mcdrawing.drawface(shapepoint­s,true,blockid)

The prefab shapes are great, but you might want to draw a custom shape of your own. We can do that by setting coordinate­s of each point and then filling in the blanks with drawface . shapepoint­s = [] shapepoint­s.append(minecraft.vec3(x1,y1,z1)) shapepoint­s.append(minecraft.vec3(x2,y2,z2)) shapepoint­s.append(minecraft.vec3(x3,y3,z3))

Now that we’ve set the coordinate­s of the points, drawface will connect up the dots and fill within the lines with your chosen blockid. mcdrawing.drawface(shapepoint­s,true,blockid)

However, if you merely want to draw the outline of the shape you can change the True to False and

drawface will create lines but not fill them in.

Shapes are brilliant, but sometimes you might want to literally just create lines in any given direction, with a specific type of block. We can do that with the

drawline function:

mcdrawing.drawline(playerpos.x, playerpos.y + 2, playerpos.z, playerpos.x + 2, playerpos.y + 2, playerpos.z, block. DIAMOND_BLOCK.ID)

Combined with drawface , this function provides us with some pretty powerful tools to get completely creative in our Minecraft worlds, without spending too much time placing blocks or calculatin­g where they should go.

You may have noticed that we imported the ‘time’ module when we were setting up our Python scripts. That’s so we can slow things down (or indeed speed them up) when needed. When using the drawline or

drawface functions, it’s best to include a slight pause after each line, otherwise your game could have problems playing catch-up and the lag would result in a messy creation. Just insert a time.sleep(x) after each instance, where x is an integer. Any number between 1 and 5 usually suffices.

Keep it neat

As your Python script becomes more and more complex with the addition of different prefab and custom shapes, it’s good practice to comment the code, but it’s also a nice touch to update the current player with a status update. mc.posttochat(“spawning X_shape in the player world”) where X_shape is the name of whatever you’re spawning. We could create a different function for each shape and call them with commands: def circles():

mc.posttochat(“spawning circles in the player world”)

mcdrawing.drawsphere(x,y,z,radius,blockid) mcdrawing.drawcircle(x,y,z,radius,blockid)

Then run the circles() command in the code whenever you want to spawn that shape. You could of course have a different function for each shape or set of shapes, then set up user commands to call said functions.

So far we’ve mostly been making use of the Minecraftd­rawing class, with useful functions for drawing shapes, but the Minecraft-stuffs module also comes complete with a class specifical­ly designed for

creating shapes, Minecrafts­hape , taking the variable inputs (mc, position, shapeblock­s=none, visible=true) . This is designed more for manipulati­ng shapes; for example the function draw() will draw the shape in

Minecraft, then you can use move(x, y, z) to move that shape to another position and finally redraw() to clear all the blocks and redraw them. reset() puts the shape back to its original position.

Some other functions include moveby() which moves a shape in relative terms, as opposed to absolute coordinate­s. rotate and rotateby offer relative vs absolute degrees for turning a shape around. clear() removes the shape entirely. from minecrafts­tuff import Minecraftd­rawing from mcpi.minecraft import Minecraft from mcpi import block mc = Minecraft.create() pos = mc.player.gettilepos() mcdrawing = Minecraftd­rawing(mc) mcdrawing.drawcircle(pos.x, pos.y + 15, pos.z, 10, block. WOOD.ID)

Have fun with your building!

 ??  ?? No manual labour required!
No manual labour required!
 ??  ??
 ??  ?? Adding some colour to our pyramid.
Adding some colour to our pyramid.
 ??  ?? How pretty can you make a pyramid made out of blocks?
How pretty can you make a pyramid made out of blocks?
 ??  ?? Customisin­g the height and depth of our pyramids.
Customisin­g the height and depth of our pyramids.
 ??  ?? Mathematic­al patterns translate well to the Minecraft environeme­nt.
Mathematic­al patterns translate well to the Minecraft environeme­nt.
 ??  ?? A diamond square coded with lines.
A diamond square coded with lines.
 ??  ?? Using drawlines to create 3D pixel art.
Using drawlines to create 3D pixel art.

Newspapers in English

Newspapers from Australia