I wanted to do something fun with it, so I decided to see if I could make some bombs! The concept is really simple, when you hit a block (right click with the sword), it turns it into a mini bomb, flashing for a few seconds, before exploding and destroying all the blocks around it. Boom!
With this and the programmable cannon I wrote, I'm really getting quite destructive.
The block event methods in the API are pretty easy to understand, after you have made a connection to the minecraft server:
mc = minecraft.Minecraft.create()
You can call the mc.events.pollBlockHits() method which returns you a list of BlockEvent objects. These objects represent the blocks position (x,y,z) and face which have been hit since it was last run. So, if you hit 2 blocks in between connecting to the minecraft server and running the command you would get a list with 2 BlockEvent objects in it, if you hadn't hit any you would get an empty list.
By creating a simple loop you can monitor the block events and then take whatever action you want:
while True:
#Get the block hit events
blockHits = mc.events.pollBlockHits()
# if a block has been hit
if blockHits:
# for each block that has been hit
for blockHit in blockHits:
# do something with the block
print blockHit.pos.x
print blockHit.pos.y
print blockHit.pos.z
print blockHit.face
print blockHit.type
print blockHit.entityId
#Get the block hit events
blockHits = mc.events.pollBlockHits()
# if a block has been hit
if blockHits:
# for each block that has been hit
for blockHit in blockHits:
# do something with the block
print blockHit.pos.x
print blockHit.pos.y
print blockHit.pos.z
print blockHit.face
print blockHit.type
print blockHit.entityId
The bombs are created by using a class which when passed a block position, it flashes the block, by setting the block to AIR and then back again, for a number of seconds (the fuse) and then creating a sphere of AIR destroying all blocks around it.
I used pythons threading module and run the Bomb class as a daemon (i.e. outside my main program) as I wanted to be able to create multiple bombs at the same time.
Download and run
You can download the code direct from github, https://github.com/martinohanlon/minecraft-bombs, so run minecraft, open/create a world and follow the instructions:
You can download the code direct from github, https://github.com/martinohanlon/minecraft-bombs, 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-bombs.git
cd minecraft-bombs
python minecraft-bombs.py
cd ~
git clone https://github.com/martinohanlon/minecraft-bombs.git
cd minecraft-bombs
python minecraft-bombs.py
The code
If you want learn and have a go yourself, here's how:
If you want learn and have a go yourself, here's how:
mkdir ~/minecraft-bombs
Copy the python api class library from minecraft to the programs directory
cp -r ~/mcpi/api/python/mcpi ~/minecraft-bombs/minecraft
Create minecraft-bombs.py python program
nano ~/minecraft-bombs/minecraft-bombs.py
or open Idle and save minecraft-bombs.py to the minecraft-bombs directory
Code
#www.stuffaboutcode.com
#Raspberry Pi, Minecraft Bombs - Turn any block into a bomb!
#import the minecraft.py module from the minecraft directory
import minecraft.minecraft as minecraft
#import minecraft block module
import minecraft.block as block
#import time, so delays can be used
import time
#import threading, so threads can be used
import threading
class ExplodingBlock(threading.Thread):
def __init__(self, pos, fuseInSecs, blastRadius):
#Setup object
threading.Thread.__init__(self)
self.pos = pos
self.fuseInSecs = fuseInSecs
self.blastRadius = blastRadius
def run(self):
#Open connect to minecraft
mc = minecraft.Minecraft.create()
#Get values
pos = self.pos
blastRadius = self.blastRadius
#Explode the block!
# get block type
blockType = mc.getBlock(pos.x, pos.y, pos.z)
# flash the block
for fuse in range(0, self.fuseInSecs):
mc.setBlock(pos.x, pos.y, pos.z, block.AIR)
time.sleep(0.5)
mc.setBlock(pos.x, pos.y, pos.z, blockType)
time.sleep(0.5)
# create sphere of air
for x in range(blastRadius*-1,blastRadius):
for y in range(blastRadius*-1, blastRadius):
for z in range(blastRadius*-1,blastRadius):
if x**2 + y**2 + z**2 < blastRadius**2:
mc.setBlock(pos.x + x, pos.y + y, pos.z + z, block.AIR)
if __name__ == "__main__":
time.sleep(5)
#Connect to minecraft by creating the minecraft object
# - minecraft needs to be running and in a game
mc = minecraft.Minecraft.create()
#Post a message to the minecraft chat window
mc.postToChat("Minecraft Bombs, Hit (Right Click) a Block, www.stuffaboutcode.com")
#loop until Ctrl C
try:
while True:
#Get the block hit events
blockHits = mc.events.pollBlockHits()
# if a block has been hit
if blockHits:
# for each block that has been hit
for blockHit in blockHits:
#Create and run the exploding block class in its own thread
# pass the position of the block, fuse time in seconds and blast radius
# threads are used so multiple exploding blocks can be created
explodingBlock = ExplodingBlock(blockHit.pos, 3, 3)
explodingBlock.daemon
explodingBlock.start()
time.sleep(0.1)
except KeyboardInterrupt:
print("stopped")
#Raspberry Pi, Minecraft Bombs - Turn any block into a bomb!
#import the minecraft.py module from the minecraft directory
import minecraft.minecraft as minecraft
#import minecraft block module
import minecraft.block as block
#import time, so delays can be used
import time
#import threading, so threads can be used
import threading
class ExplodingBlock(threading.Thread):
def __init__(self, pos, fuseInSecs, blastRadius):
#Setup object
threading.Thread.__init__(self)
self.pos = pos
self.fuseInSecs = fuseInSecs
self.blastRadius = blastRadius
def run(self):
#Open connect to minecraft
mc = minecraft.Minecraft.create()
#Get values
pos = self.pos
blastRadius = self.blastRadius
#Explode the block!
# get block type
blockType = mc.getBlock(pos.x, pos.y, pos.z)
# flash the block
for fuse in range(0, self.fuseInSecs):
mc.setBlock(pos.x, pos.y, pos.z, block.AIR)
time.sleep(0.5)
mc.setBlock(pos.x, pos.y, pos.z, blockType)
time.sleep(0.5)
# create sphere of air
for x in range(blastRadius*-1,blastRadius):
for y in range(blastRadius*-1, blastRadius):
for z in range(blastRadius*-1,blastRadius):
if x**2 + y**2 + z**2 < blastRadius**2:
mc.setBlock(pos.x + x, pos.y + y, pos.z + z, block.AIR)
if __name__ == "__main__":
time.sleep(5)
#Connect to minecraft by creating the minecraft object
# - minecraft needs to be running and in a game
mc = minecraft.Minecraft.create()
#Post a message to the minecraft chat window
mc.postToChat("Minecraft Bombs, Hit (Right Click) a Block, www.stuffaboutcode.com")
#loop until Ctrl C
try:
while True:
#Get the block hit events
blockHits = mc.events.pollBlockHits()
# if a block has been hit
if blockHits:
# for each block that has been hit
for blockHit in blockHits:
#Create and run the exploding block class in its own thread
# pass the position of the block, fuse time in seconds and blast radius
# threads are used so multiple exploding blocks can be created
explodingBlock = ExplodingBlock(blockHit.pos, 3, 3)
explodingBlock.daemon
explodingBlock.start()
time.sleep(0.1)
except KeyboardInterrupt:
print("stopped")
Hi Martin,
ReplyDeletecan you write the code for this:
When you right click, it gets the position of where you right-clicked. I have been trying over and over. I can make it so it runs code when you right click, but I can't seem to make it get the right position. I know I can get the coordinates where I right clicked using things like mc.events.pollBlockHits()[1] for the coordinate x. It's just that as soon as it rightclicks, the result of pollBlockHits changes.
EDIT: I think I might have a way. Just a second
Ive updated the example code in the post. If you want to get the position values out of the BlockEvent object, you use blockHit.pos.x [y or z]. Dont try and strip the values out of the string, it'll drive you mental and you dont need too.
DeleteThanks a lot Martin.
DeleteYou know, you should make it so the "explosion" also takes away random blocks, instead of being the same shape of explosion.
DeleteHi Martin,
ReplyDeleteForgive me if you've answered this elsewhere, but what do you use to do the video captures of the Pi?
Really hitech. Camera on tripod in front of screen!
DeleteMartin - I was just using my Pi with the 7yr old son of a friend of mine. Yesterday he'd never used Minecraft so I had him blowing things up using tnt on a laptop then I thought it might be interesting to show him the raspi version. Of course the first thing he wanted to do was blow things up again!
ReplyDeleteSo we used this script & he LOVED it.
Thanks for all your hard work on this blog dude -you're an absolute star!! :)))
Thanks I used this as a base code and now I have two programs, a tnt events program and a lapis lazuli to water program.
ReplyDeleteAs someone who wasted the better part of a Saturday and is not so familiar with Minecraft terminology, I'd just point out that HIT is right-click, not left-click. I thought the event handler was broken but I was simply not hitting... ugh.
ReplyDeleteThanks for the great tutorials though! Had a great time making various designs and worked out a teleport platform. More hours of fun ahead.
NOW....I see your text in fact says right click with the sword....it's all in the details....
Deletethanks again