Wednesday 17 April 2013

Raspberry Pi - Minecraft Cannon

I had this idea about using Minecraft: Pi Edition and its API to show how trigonometry, mechanics and mathematics can actually be useful and given that everyone likes to blow stuff up....  I thought I would make a cannon. 
A cannon which could point in any direction (0-360 degrees), angle upwards (0-90 degrees) and when fired would send a cannon ball upwards, falling in-line with the laws of gravity and then explode when it hit the ground.

http://youtu.be/6NHorP5VuYQ

I liked the idea of a command line interface, its a cannon after all they are not meant to be hi-tech devices, to control the cannon you use the following commands:
  • start - create [start-up] the cannon
  • rotate [0-360 degress] - rotate the cannon
  • tilt [0-90 degress] - tilt the cannon upwards
  • fire - FIRE!
  • exit - exit and clear the cannon

The code contains 4 classes written in Python:
  1. CannonCommands - used to control the command line interface, based on python's cmd module
  2. MinecraftDrawing - a generic class I'm building up which supports many generic drawing functions (drawLine, drawFace, drawSphere, etc)
  3. MinecraftCannon - a class which controls the building and changing of the cannon base and its gun, this contains all the code required to 'point' the gun to a specific point on the a sphere based on the direction and tilt angles
  4. MinecraftBullet - a class which controls the flight of the bullet through the air and its eventual explosion, including the maths to manage general mechanics of velocity and gravity

Download and run
You can download the code direct from github, https://github.com/martinohanlon/minecraft-cannon, so run minecraft, open/create a world and follow the instructions:

sudo apt-get install git-core
cd ~
git clone https://github.com/martinohanlon/minecraft-cannon.git
cd minecraft-cannon
python minecraft-cannon.py


34 comments:

  1. Hey, how do you make it so the TNT blows up?

    ReplyDelete
    Replies
    1. Its not tnt! Its actually a block of glowing obsidian, but it could be any block, the code i wrote calculates the next position of the cannon ball and if its not air it creates an explosion by creating a sphere of air! Its all coded basically even the explosion. Download it and have a look at the bullet class in the program.

      Delete
  2. Martin,
    Really great achievement!! You are an inspiration to me an my son (the resident minecrafter :-))

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Hi Martin. My daughter and I enjoy following your tutorials. She is wanting to code an elevator for her very enormous house. Any ideas on where to start??

    ReplyDelete
    Replies
    1. Elevators are so yesterday, what about a transporter?

      Delete
    2. to do an elevator, you'd need to move the player up, draw the new platform over the old one, and then clear the old platform, rinse and repeat.

      A transporter is much easier. Give me a few days for my exams to be over, and i'll write one to show you. (star ship enterprise anyone?)

      Actually, youve just given my an idea for a coooooool project :) will be even cooler if survival mode ever makes it to minecraft (might have to see if thats code-able too)

      Delete
    3. Code for a teleporter (including download) with a GUI rather than command line interface. http://pi-projects.blogspot.co.uk/2013/06/minepi-beam-me-up-scotty.html

      Hope you like it

      If anyone wants to rip it appart and make it better, please do. Just drop me a message on my blog to let me know your results :D

      Delete
  5. you are so epic Martin, hey do you know if there is a way to make a pi server that is.not connected by lan?

    ReplyDelete
    Replies
    1. What do you mean? Do you mean a minecraft server running on a Pi?

      Delete
  6. Should I use a command line terminal or a python code editor to type in the cannon's code?

    ReplyDelete
    Replies
    1. Either. If you run the program from the command line e.g. by using python minecraft-cannon.py, just type the commands into the command line. If you are running the code from Idle, type it into the Python run window.

      Delete
  7. Hi Martin. Nice Cannon.
    I found I had to modify the code slightly in order to fire/adjust the weapon though. Problem was the call to self.mc.setBlock on line 38, which doesn't work if blockData is None, i.e. if the preceding call to drawPoint3d is made without a blockData argument. Here is a diff against my working version which may or may not clarify things:

    def drawPoint3d(self, x, y, z, blockType, blockData=None):
    - self.mc.setBlock(x,y,z,blockType,blockData)
    + if blockData == None:
    + self.mc.setBlock(x,y,z,blockType)
    + else:
    + self.mc.setBlock(x,y,z,blockType,blockData)

    Do you have any insight as to why I need to do this? Am thinking maybe something changed in mcpi 0.1.1. Anyways, thanks for your tutorials!

    ReplyDelete
    Replies
    1. I have no idea why you need to do this! I use the same MinecraftDrawing class in loads of my projects and I have never seen this issue. Its using the minecraft.py and block.py api libraries which came with 0.1.1. What version are you using? Also what version of python were you using?

      Delete
    2. This is with Python 2.7.3 on up-to-date Raspbian, mcpi 0.1.1 and the code from your github. It's very odd, and I would like to understand it better, but handling of None vs actual nothing is hard. With your code, if I start the cannon and then issue the fire command, then the bullet draw() function triggers the error, which ultimately is thrown by math.floor being called with an empty list, which is clearly wrong.

      Delete
    3. I have just retried the code, got it fresh out of github and no problems. Sorry dont know what to suggest.

      Delete
    4. Finally figured this out -- in your github the file minecraft/minecraft.py is from v0.1.0. Check line 5: Minecraft PI low level api v0.1_0
      Where as I am using 0.1.1 which amongst other things has a fussier setTilePos()

      Delete
    5. I see. Ill have to update the code when I get 2 mins.

      Delete
    6. Ok. At some point I must have come across the same issue, because I have modded by minecraft-stuff class to take care of the issue, so change:

      def drawPoint3d(self, x, y, z, blockType, blockData=None):

      to

      def drawPoint3d(x, y, z, blockType, blockData=0):

      Delete
  8. This comment has been removed by the author.

    ReplyDelete
  9. Hi Martin,
    Just came across this post and thought I would try it out at my code club.
    I am running the latest raspbian wheezy build.

    I have entered start and the cannon is created, then rotate 10, at this point I get the following error messages

    File "minecraft-cannon.py", line 393, in
    CannonCommands().cmdloop()
    File "/usr/lib/python2.7/cmd.py", line 142, in cmdloop
    stop = self.onecmd(line)
    File "/usr/lib/python2.7/cmd.py", line 221, in onecmd
    return func(arg)
    File "minecraft-cannon.py", line 382, in do_rotate
    self.cannon.setDirection(int(direction))
    File "minecraft-cannon.py", line 342, in setDirection
    self.clearGun()
    File "minecraft-cannon.py", line 336, in clearGun
    self.drawGunInMC(block.AIR)
    File "minecraft-cannon.py", line 330, in drawGunInMC
    blockType, blockData)
    File "minecraft-cannon.py", line 100, in drawLine
    self.drawVertices(self.getLine(x1, y1, z1, x2, y2, z2), blockType, blockData)
    File "minecraft-cannon.py", line 96, in drawVertices
    self.drawPoint3d(vertex.x, vertex.y, vertex.z, blockType, blockData)
    File "minecraft-cannon.py", line 39, in drawPoint3d
    self.mc.setBlock(x,y,z,blockType,blockData)
    File "/home/pi/minecraft/minecraft.py", line 138, in setBlock
    self.conn.send("world.setBlock", intFloor(args))
    File "/home/pi/minecraft/minecraft.py", line 22, in intFloor
    return [int(math.floor(x)) for x in flatten(args)]
    TypeError: a float is required

    I am using Python 2.7 not 3
    cheers
    Steve Gale

    ReplyDelete
    Replies
    1. The error is because I wrote the cannon against v0.1.0 of the API and you are using v0.1.1 of the api. If you use the API version which is included in the minecraft folder in github it'll work fine.

      Or you can fix it by rounding the values passed in setBlock in the drawPoint3d function.

      Delete
  10. My 7 year old isn't very good with the command line and it takes him a couple of seconds to switch between Terminal and Minecraft server so I added a countdown (5 seconds to get in a good viewing position after firing) and a GUI.
    Here's the repo if anyone wants it (it's essentialy your work)
    https://github.com/Shane-Lester/Cannon-gui.git
    Needs Qt so:
    sudo apt-get install python-pyside

    Thanks for you work on this, I've enjoyed it.

    Shane

    ReplyDelete
  11. Hey Martin i am completely new to the raspberry pi and have only just got minecraft up and running, I love my pi to bits and would be seriously grateful if you could give me a step by step guide to making this cannon work?

    ReplyDelete
    Replies
    1. Or if anyone else could help that would be great!

      Delete
    2. Have you followed the Download and run instructions above? This should download the code from github.com and run it. You will need to be in a minecraft world when you run it.

      Delete
    3. Yes and its a little more complex than i thought, it started flickering my screen so i stopped it? is that normal?!

      Delete
  12. Hi Martin, I'm a dad of 2 boys 8 and 11 who are starting to work through your great book Adventures in Minecraft. The cannon does not seem to work, even after adjusting the code at the top for mcpi. instead of minecraft. We still get a number of errors. We're on Mac Yosemite with the bukkit / python 2.7.6 setup recommended from the book, including downloading the starter zip, so we're saving .py files to the MyAdventures sub-folder of the Desktop. I was trying to get this working for them as an inspiration to what they'll be able to work and understand as they master the book... I showed them the Blocks to Bombs in the same environment, and they were thrilled / inspired. I think it would be great if we could get the Cannon working in the Adventures in Minecraft environment - I think the different API might be the issue, per some of the comments above. Could you please make suggestions to how we might fix it to work for the AiM setup - please understand I'm a relative Noob as well, so I'm learning as I go with them. Or perhaps we could get another branch on Git for those wanting to add on to the AiM recommended envinroment? I'm sure it would be a study inspiration for others as well. Thanks so much for the awesome Adventures in Minecraft and the great site / code.

    ReplyDelete
    Replies
    1. Hi Derek,

      The reason the cannon program doesnt work when you copy it to the MyAdventures folder is a simple one. I wrote it a long time ago using v0.1 of the api the api with AIM is v0.1.1. This morning I updated the code on github to use v0.1.1 so you should be able to re-download it and try again.

      Martin

      Delete
    2. Thanks SO MUCH, Martin - I got it started and to start, stop (exit), tilt, and rotate, but _not_ to fire - it seemed to throw a number of exceptions in Bukkit and would freeze in the python shell, but then produced the following stack trace:

      Traceback (most recent call last):
      File "/Users/username/Desktop/AdventuresInMinecraft/MyAdventures/minecraft-cannon-updated.py", line 393, in
      CannonCommands().cmdloop()
      File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/cmd.py", line 142, in cmdloop
      stop = self.onecmd(line)
      File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/cmd.py", line 221, in onecmd
      return func(arg)
      File "/Users/username/Desktop/AdventuresInMinecraft/MyAdventures/minecraft-cannon-updated.py", line 377, in do_fire
      while(bullet.update()):
      File "/Users/username/Desktop/AdventuresInMinecraft/MyAdventures/minecraft-cannon-updated.py", line 264, in update
      if self.mc.getBlock(newDrawPos.x, newDrawPos.y, newDrawPos.z) == block.AIR:
      File "/Users/username/Desktop/AdventuresInMinecraft/MyAdventures/mcpi/minecraft.py", line 123, in getBlock
      return int(self.conn.sendReceive("world.getBlock", intFloor(args)))
      ValueError: invalid literal for int() with base 10: ''

      I also saved the various errors from Bukkit terminal if those would be helpful.

      Hopefully it is an easy fix to get the firing working - Thanks again!! So exciting to show the boys!!

      Delete
    3. So I tested using Bukkit (I only tested it on a Pi) and as you reported Bukkit ended up reporting a load of errors. It turns out it was because I was using GLOWING_OBSIDIAN for the bullet and unfortunately glowing obsidian doesn't exist as a block on the full version of Minecraft. So I've change it to TNT.

      I dont know why you received the error in Python though.

      I have updated it in github.

      Delete
  13. Martin,
    1) Thanks SO MUCH!!
    2) Seems to work great on Bukkit!
    3) You Rock!! I told my sons that the author of the "amazing book" responded to our inquiry and updated the code to help them learn, and they were speechless (which is rare... :=) )
    They said they want to try to prepare a "special creation" for you based on what they're learning, so something interesting may be coming your way....

    Can't wait to go over the code with them in detail as they work through the rest of the book to help them really "get it". You've already gone over the top in helping with the inspiration!
    Thanks again!

    ReplyDelete

Note: only a member of this blog may post a comment.