進撃の巨大ブタさん

,,
今回は3Dカラープリンターの時に作った巨大なブタさんを動かしてみます。 ブロックを動かすには、minecraftstuff.pyというものを使います。Martin O'Hanlonさんというイギリスの方が作成して、こちらで紹介されています。 minecraftstuff.pyを手に入れて、mcpiフォルダの中に入れておいてください。まずはブロックの動かし方です。2×2×2の赤いサイコロを作って動かします。 [python] import mcpi.minecraft as minecraft import mcpi.minecraftstuff as stuff import mcpi.block as block import time from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() pos = mc.player.getTilePos() cubelocks = [ stuff.ShapeBlock(0,0,0,block.REDSTONE_BLOCK), stuff.ShapeBlock(1,0,0,block.REDSTONE_BLOCK), stuff.ShapeBlock(0,1,0,block.REDSTONE_BLOCK), stuff.ShapeBlock(0,0,1,block.REDSTONE_BLOCK), stuff.ShapeBlock(1,1,0,block.REDSTONE_BLOCK), stuff.ShapeBlock(0,1,1,block.REDSTONE_BLOCK), stuff.ShapeBlock(1,0,1,block.REDSTONE_BLOCK), stuff.ShapeBlock(1,1,1,block.REDSTONE_BLOCK) ] cubeShape = stuff.MinecraftShape(mc, pos + Vec3(5,5,5), cubelocks) for i in range(0, 20): time.sleep(0.5) cubeShape.moveBy(1,0,0) cubeShape.clear() [/python] こんな赤いサイコロが まで進んでいきます。 さて、いよいよブタさんを動かします。コードはこんな感じです。 [python] import mcpi.minecraft as minecraft import mcpi.minecraftstuff as stuff import mcpi.block as block import time import csv from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() pos = mc.player.getTilePos() def shape3D(start, data, inc): shape = [] for y in range(0,len(data)): for z in range(0,len(data[y])): for x in range(0,len(data[y][z])): if data[y][z][x] != 0: shape.append(stuff.ShapeBlock(x,y,z,inc[data[y][z][x]])) return shape; inc_pig = {1:block.WOOL_PINK, 2:block.WOOL_BROWN, 3:block.WOOL_BLACK, 4:block.WOOL_WHITE, 5:block.WOOL_RED} data =[] with open('pig.csv', 'r') as f: file = csv.reader(f) plane = [] for line in file: if len(line) == 0: data.append(plane) plane = [] else: plane.append(line) data.append(plane) data_conved = [[[int(elm) for elm in l] for l in p] for p in data] pigBlocks = shape3D(mc.player.getPos() + Vec3(1,0,1), data_conved, inc_pig) pigShape = stuff.MinecraftShape(mc, pos + Vec3(-10,0,5), pigBlocks) for i in range(0, 100): time.sleep(0.2) pigShape.moveBy(-1,0,0) pigShape.clear [/python] shapeを作るところは、カラープリンターの時のprint3Dとほとんど同じです。 では、 おおー、本当にブタさんが進んでいきます。ブタさんのぶつかった所はブロックが無くなってしまうみたいです。

3Dスキャナとプリンターでなんでもコピー

,,
前回はカラー3Dプリンターを作りました。今回はスキャナーを作ります。積み上げられているブロックの範囲を指定して、スキャン。スキャンしたデータを使って、好きな場所に3Dプリントするという流れでやっていきます。 まず、スキャンする相手ですが、前回作ったブタさんにします。 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() class Obj3D: def __init__(self, data, ink): self.data = data self.ink = ink def getData(self): return self.data def getInk(self): return self.ink def scan3D(start, dist): data = [] ink_inv={} for y in range(0, dist.y): plane=[] for z in range(0, dist.z): line=[] for x in range(0, dist.x): blk = mc.getBlockWithData(start.x + x, start.y + y, start.z + z) if not blk in ink_inv: ink_inv[blk] = len(ink_inv) line.append(ink_inv[blk]) plane.append(line) data.append(plane) ink = {v:k for k, v in ink_inv.items()} obj = Obj3D(data, ink) return obj def print3D(start, data, inc): for y in range(0, len(data)): for z in range(0, len(data[y])): for x in range(0, len(data[y][z])): if data[y][z][x] != 0: mc.setBlock(start.x + x, start.y + y, start.z + z, inc[data[y][z][x]]) start = mc.player.getTilePos() obj = scan3D(start, Vec3(20, 20, 20)) [/python] こんな感じでブタさんをスキャンします。scan3Dではデータとインクの2つを戻したいので、クラスとしてObj3Dを作って、そのオブジェクトを戻しています。 [python] ink = {v:k for k, v in ink_inv.items()} [/python] はink_invのキーと値を入れ替えて、インクを作っています。 ポイントになるのが、主人公の向き(方角)です。F3を押して、eastになっていると読み込みやすいです。 読み取ったデータをprintしてみると、 [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0] この部分はブタさんの足のウラですね。 スキャンできているので、このデータをプリントしてみます。 無事にブタさんがコピーできました。続いて、自分で積んだブロックをスキャンしてみます。頑張って新しく羊さんを作っておきました。 ブタさんと同じようにスキャンしてプリントできるはずですが、スキャンした後、ブタさんのpigのようにファイルに出力してみます。では実行します。 見事に羊さんもコピーされました。ファイルはsheep.csvです。 と作ってきました。これがあれば、csvで設計した形や、目の前の形をいつでもコピー(スキャンして、プリントすることができます。クリーパー(creeper.csv)などの敵キャラも形を作ってからコピーできますし、 氷原のような珍しい地形(バイオーム)を草原の中に持ってくることもできます。

3Dカラープリンター

,,
3Dプリンターでものづくり(モノクロ)では、1種類のブロックだけを積み上げましたが、今度はいろんなブロックを使ってみます。3Dプリンターのカラー対応って感じです。では早速。プログラムはあまり変わりませんが、ディクショナリを使って、数字とブロックのつながりを決めています。0は何も置かない、1なら赤色の羊毛、2ならオレンジ色の羊毛。 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() def print1D(start, data, inc): for x in range(0,len(data)): if data[x] != 0: mc.setBlock(start.x + x, start.y, start.z, inc[data[x]]) inc_rainbow = { 1:block.WOOL_RED, 2:block.WOOL_ORANGE, 3:block.WOOL_YELLOW, 4:block.WOOL_LIME, 5:block.WOOL_LIGHT_BLUE, 6:block.WOOL_BLUE, 7:block.WOOL_PURPLE } rainbow = [1, 2, 3, 4, 5, 6, 7] print1D(mc.player.getPos() + Vec3(1,0,0), rainbow, inc_rainbow) [/python] 実際に置いてみると、こんな風に虹色になります。 次は2次元ですが、スマイルマークをきれいにしてみます。 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() def print2D(start, data, inc): for z in range(0,len(data)): for x in range(0,len(data[z])): if data[z][x] != 0: mc.setBlock(start.x + x, start.y, start.z + z, inc[data[z][x]]) inc_smile = { 1:block.WOOL_YELLOW, 2:block.WOOL_BLACK, 3:block.WOOL_RED } smile_fill = [ [0,0,0,1,1,1,1,1,0,0,0], [0,0,1,1,1,1,1,1,1,0,0], [0,1,1,1,1,1,1,1,1,1,0], [1,1,1,2,1,1,1,2,1,1,1], [1,1,1,2,1,1,1,2,1,1,1], [1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1], [1,1,1,3,3,3,3,3,1,1,1], [0,1,1,1,3,3,3,1,1,1,0], [0,0,1,1,1,1,1,1,1,0,0], [0,0,0,1,1,1,1,1,0,0,0] ] print2D(mc.player.getPos() + Vec3(1,0,10), smile_fill, inc_smile) [/python] 中身も色が塗られて、口も赤くなりました。3色使っています。 では最後に、これはどうなるでしょうか。pig.csvというファイルをダウンロードして、.pyと同じ場所に置いて下さい。 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() import csv def print3D(start, data, inc): for y in range(0,len(data)): for z in range(0,len(data[y])): for x in range(0,len(data[y][z])): if data[y][z][x] != 0: mc.setBlock(start.x + x, start.y + y, start.z + z, inc[data[y][z][x]]) inc_pig = {1:block.WOOL_PINK, 2:block.WOOL_BROWN, 3:block.WOOL_BLACK, 4:block.WOOL_WHITE, 5:block.WOOL_RED} data =[] with open('pig.csv', 'r') as f: file = csv.reader(f) plane = [] for line in file: if len(line) == 0: data.append(plane) plane = [] else: plane.append(line) data.append(plane) data_conved = [[[int(elm) for elm in l] for l in p] for p in data] print3D(mc.player.getPos() + Vec3(1,0,1), data_conved, inc_pig) [/python] 豚さんです。ちょっと巨大過ぎますね。この豚が動いたりしたらもっと楽しいですが・・・、それはまた今度。

3Dプリンターでものづくり(モノクロ)

,,
金のなる木を植えるではプログラムでブロックの置き方を一個ずつ決めていましたが、もっと簡単に好きな形を作れるプログラミングをしてみます。簡単に言うと、配列と繰り返しを使います。 1,1,1,0,1,0,1 というような配列があったときに、1のところでブロックを置き、0のところでは置かない。次のようなプログラムになります。 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() def print1D(start, data, blk): for x in range(0,len(data)): if data[x]: mc.setBlock(start.x + x, start.y, start.z, blk) dotline = [1,1,1,0,1,0,1] print1D(mc.player.getPos() + Vec3(1,0,0), dotline, block.WOOL_RED) [/python] これは線(1次元)でしたが、次のプログラミングでは面(2次元)になります。 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() def print2D(start, data, blk): for z in range(0,len(data)): for x in range(0,len(data[z])): if data[z][x]: mc.setBlock(start.x + x, start.y, start.z + z, blk) smile = [ [0,0,0,1,1,1,1,1,0,0,0], [0,0,1,0,0,0,0,0,1,0,0], [0,1,0,0,0,0,0,0,0,1,0], [1,0,0,1,0,0,0,1,0,0,1], [1,0,0,1,0,0,0,1,0,0,1], [1,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,1], [1,0,0,1,0,0,0,1,0,0,1], [0,1,0,0,1,1,1,0,0,1,0], [0,0,1,0,0,0,0,0,1,0,0], [0,0,0,1,1,1,1,1,0,0,0] ] print2D(mc.player.getPos() + Vec3(1,0,10), smile, block.WOOL_YELLOW) [/python] 配列を遠目で見てもスマイルマークかな?って見えますね。プログラムは実はあまり変わっていないことがわかります。さて、では次に3D:立体(3次元)にチャレンジしてみます。 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() def print3D(start, data, blk): for y in range(0,len(data)): for z in range(0,len(data[y])): for x in range(0,len(data[z])): if data[y][z][x]: mc.setBlock(start.x + x, start.y + y, start.z + z, blk) tent = [ [ [1,1,1,1,1], [1,0,0,0,1], [1,0,0,0,1], [1,0,0,0,1], [1,1,0,1,1], ],[ [1,1,1,1,1], [1,0,0,0,1], [1,0,0,0,1], [1,0,0,0,1], [1,1,0,1,1], ],[ [0,0,0,0,0], [0,1,1,1,0], [0,1,0,1,0], [0,1,1,1,0], [0,0,0,0,0], ],[ [0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0], ] ] print3D(mc.player.getPos() + Vec3(1,0,20), tent, block.WOOL_WHITE) [/python] もう配列を見ても何ができるのか想像がつきませんね。テントのような形になります。これで、たった6行のプログラムで、どんな形でもブロックを積み上げて作ることができます。 最後に、配列をプログラムではなくて、ファイルから読み込ませてみます。こんなファイルをmt_tsukuba.csvという名前で置いておけば、 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() import csv data = [] with open('mt_tsukuba.csv', 'r') as f: file = csv.reader(f) plane = [] for line in file: if len(line) == 0: data.append(plane) plane = [] else: plane.append(line) data.append(plane) data_conved = [[[int(elm) for elm in l] for l in p] for p in data] print3D(mc.player.getPos() + Vec3(1,0,1), data_conved, block.WOOL_GREEN) [/python] 茨城県のシンボル、つくば山です。小さいのであまりそれっぽく見えないですね。今度もっと大きく作ってみます。地形図を電子国土Web地理院地図から入手しました。それをExcelの背景画像に設定して、トレーシングペーパーのように高さを書いて作っています。 こんな感じの地道な作業。

金のなる木を植える

,,
面白いプログラミングをしてみます。 このコードを実行すると、 [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() pos = mc.player.getTilePos() + Vec3( 3, 0, 0 ) #1 mc.setBlock( pos, block.WOOD ) #2 mc.setBlock( pos + Vec3( 0, 1 , 0 ), block.WOOD ) #3 mc.setBlocks( pos + Vec3( -2, 2, -2 ), pos + Vec3( 2, 2, 2 ), block.LEAVES ) mc.setBlock( pos + Vec3( 0, 2, 0 ), block.WOOD ) #4 mc.setBlock( pos + Vec3( 0, 3, 0 ), block.WOOD ) #5 mc.setBlocks( pos + Vec3( -1, 4, -1 ), pos + Vec3( 1, 4, 1 ), block.LEAVES ) mc.setBlock( pos + Vec3( 0, 4, 0), block.WOOD ) #6 mc.setBlock( pos + Vec3( 0, 5, 0 ), block.LEAVES ) [/python] こんな感じで木を作ることができます。 setBlock(), setBlocks()でオークの原木、オークの葉を順番に置いています。 setBlocks()は2つの位置を指定して、直方体にブロックを置く関数です。 ブロックの種別を変えたらどうでしょう。オークの葉を金ブロックに変えると 他にもカボチャのなる木、TNTのなる木などなど。マグマのなる木は危険です。 せっかくなので、色々な木を作るコードを関数にまとめてみます。 関数にまとめると [python] import mcpi.minecraft as minecraft import mcpi.block as block from mcpi.vec3 import Vec3 mc = minecraft.Minecraft() def createTree( start, wood = block.WOOD, leaf = block.LEAVES ): mc.setBlock( start, wood ) mc.setBlock( start + Vec3( 0, 1, 0 ), wood ) mc.setBlocks( start + Vec3( -2 ,2, -2 ), start + Vec3( 2, 2, 2 ), leaf ) mc.setBlock( start + Vec3( 0, 2, 0 ), wood ) mc.setBlock( start + Vec3( 0, 3, 0 ), wood ) mc.setBlocks( start + Vec3( -1, 4, -1 ), start + Vec3( 1, 4, 1 ), leaf ) mc.setBlock( start + Vec3( 0, 4, 0 ), wood ) mc.setBlock( start + Vec3( 0, 5, 0 ), leaf ) createTree( mc.player.getPos() + Vec3( 1, 0, 1 ), block.WOOD, block.LEAVES ) createTree( mc.player.getPos() + Vec3( 10, 0, 1 ), block.WOOD, block.GOLD_BLOCK ) createTree( mc.player.getPos() + Vec3( 20, 0, 1 ), block.WOOD, block.TNT) createTree( mc.player.getPos() + Vec3( 30, 0, 1 ), block.WOOD, block.PUMPKIN_ACTIVE) createTree( mc.player.getPos() + Vec3( 40, 0, 1 ), block.WOOD, block.LAVA_STATIONARY) [/python] このように引数を変えるだけで色々な木(もう木じゃないけど)を簡単に作ることができるようになります。