マイクラの高度に関する情報
テレポートカプセル(以下、tpcと記す)でいろいろ調査してみると、地下の深さがクリエイティブ・モードとサバイバル・モードで違う。
クリエイティブ・モードでは地下は-4までで、-5には設置もできない。 サバイバル・モードでは地下は-60くらいまではあるが、tpcで-65に行くと底が抜けて(底部分が設置できずに)奈落へ落ちてしまう。
上空もクリエイティブ・モードだと251まではブロックを設置できるけど、サバイバル・モードではtpcで190に行くと上半分が設置できない状態になる。
で、今日、この次のページを見つけてわかった。
マイクラでは、全体で0〜255まで設置可能で、pythonによる指定できる座標の原点がクリエイティブ・モードでは高度4の位置にあり-4〜251の256の範囲になり、サバイバル・モードでは高度62(?)の位置にあるため、-62〜192くらいのやはり256の範囲で設置可能になるということらしい。ただし、サバイバル・モードでのpython原点が固定かどうかは不明。
テレポートカプセル
サバイバルモードの制限を調査するのに、サバイバルモードでは飛行モードが無いので高い所に行くのにテレポート・コマンド(実際にはsetPos関数)で移動する前に足場を作らないといけないし、地下も足場を作って、自分の入る空間を作って、さらに松明を設置してからテレポートする。 これがめんどくさくて、指定した位置にガラス製のカプセルを作って、その中にsetPosで移動するスクリプトを書いた。
スクリプト(tpc.py)
# coding: utf-8 import mcpi.minecraft as minecraft import mcpi.block as block import sys if len(sys.argv) < 4: sys.exit("Usage: tcp.py x y z") x = int(sys.argv[1]) y = int(sys.argv[2]) z = int(sys.argv[3]) mc = minecraft.Minecraft() mc.setBlocks(x-1, y, z-1, x+1, y+3, z+2, block.GLASS) mc.setBlocks(x, y+1, z, x, y+2, z, block.AIR) mc.setBlock(x, y+1, z+1, block.GLASS) mc.setBlock(x, y+2, z+1, block.TORCH) mc.player.setPos(x+0.5, y+1.0, z+0.5)
実行すると、こんな感じ。
トーテムポール的なモノ
方位がわかるようなトーテムポール的なオブジェを剣+右クリックで設置できるといいなぁ〜と、まずはどんな形がいいかと作ってみた。
(もうちょっと上にしたい。)
いろいろ調整して、こんな感じになった。
夜になってもわかるように松明を付けた。
スクリプト
wood.pyと同じく、pycraパッケージにdirobj.pyモジュールとして作った。
pycra/dirobj.py
# coding: utf-8 import mcpi.minecraft as minecraft import mcpi.block as block def dirobj(mc, x, y, z): gy = y+12 # Green Arrow mc.setBlocks(x, gy, z, x, gy+11, z, block.HARDENED_CLAY_STAINED_GREEN) mc.setBlock(x-1, gy+10, z, block.HARDENED_CLAY_STAINED_GREEN) mc.setBlock(x+1, gy+10, z, block.HARDENED_CLAY_STAINED_GREEN) mc.setBlock(x, gy+10, z-1, block.HARDENED_CLAY_STAINED_GREEN) mc.setBlock(x, gy+10, z+1, block.HARDENED_CLAY_STAINED_GREEN) mc.setBlock(x-2, gy+9, z, block.HARDENED_CLAY_STAINED_GREEN) mc.setBlock(x+2, gy+9, z, block.HARDENED_CLAY_STAINED_GREEN) mc.setBlock(x, gy+9, z-2, block.HARDENED_CLAY_STAINED_GREEN) mc.setBlock(x, gy+9, z+2, block.HARDENED_CLAY_STAINED_GREEN) cy = gy+5 # Red Arrow mc.setBlocks(x-5, cy, z, x+6, cy, z, block.HARDENED_CLAY_STAINED_RED) mc.setBlock(x+5, cy+1, z, block.HARDENED_CLAY_STAINED_RED) mc.setBlock(x+5, cy-1, z, block.HARDENED_CLAY_STAINED_RED) mc.setBlock(x+4, cy+2, z, block.HARDENED_CLAY_STAINED_RED) mc.setBlock(x+4, cy-2, z, block.HARDENED_CLAY_STAINED_RED) # Blue Arrow mc.setBlocks(x, cy, z-5, x, cy, z+6, block.HARDENED_CLAY_STAINED_BLUE) mc.setBlock(x, cy+1, z+5, block.HARDENED_CLAY_STAINED_BLUE) mc.setBlock(x, cy-1, z+5, block.HARDENED_CLAY_STAINED_BLUE) mc.setBlock(x, cy+2, z+4, block.HARDENED_CLAY_STAINED_BLUE) mc.setBlock(x, cy-2, z+4, block.HARDENED_CLAY_STAINED_BLUE) # Pillar mc.setBlocks(x, y, z, x, gy-1, z, block.HARDENED_CLAY_STAINED_WHITE) # Torch mc.setBlock(x, gy+12, z, block.TORCH) mc.setBlock(x-3, gy+9, z, block.TORCH.id, 2) mc.setBlock(x+3, gy+9, z, block.TORCH.id, 1) mc.setBlock(x, gy+9, z-3, block.TORCH.id, 4) mc.setBlock(x, gy+9, z+3, block.TORCH.id, 3) mc.setBlock(x+7, cy, z, block.TORCH.id, 1) mc.setBlock(x+6, cy, z+1, block.TORCH.id, 3) mc.setBlock(x+6, cy, z-1, block.TORCH.id, 4) mc.setBlock(x, cy, z+7, block.TORCH.id, 3) mc.setBlock(x+1, cy, z+6, block.TORCH.id, 1) mc.setBlock(x-1, cy, z+6, block.TORCH.id, 2)
木の時と同じ感じに。
mkdirobj.py
# coding: utf-8 import mcpi.minecraft as minecraft import mcpi.block as block import pycra.dirobj as dirobj mc = minecraft.Minecraft() mc.events.clearAll() while True: blockHits = mc.events.pollBlockHits() if blockHits: blockHit = blockHits[0] if blockHit.face == 1: x = blockHit.pos.x y = blockHit.pos.y z = blockHit.pos.z blockId = mc.getBlock(x, y, z) while blockId != block.AIR: y = y + 1 blockId = mc.getBlock(x, y, z) dirobj.dirobj(mc, x, y, z)
軌道の中心線(1)
基盤地図情報の基本項目をダウンロードしてくると、基本項目のいろんなデータが一緒に入ったZIPファイルになっている。
軌道の中心線のデータは緯度経度で指定されているので、1次メッシュ番号、2次メッシュ番号から2次メッシュ上のインデックスへ変換して軌道用の配列へセットするまでを実装してみた。
ここに貼った段階で点が潰れてしまっているけど、まだ点をプロットしただけなのでこれから点を繋いでいく処理を入れないといけない。
スクリプト(railcl.py)
# coding: utf-8 import xml.etree.ElementTree as ET import numpy as np import matplotlib.pyplot as plot import pycra.npydata as nd import sys NPY_DATA = "npydata-5340-22.npy" XML_RAILCL = "FG-GML-534022-ALL-20170401/FG-GML-534022-RailCL-20170401-0001.xml" RCL_DATA = "npyrcl-5340-22.npy" class World: """ class for World coordinate """ def __init__(self, mesh1, mesh2, geo_array, rcl_array): self.mesh1 = mesh1 self.mesh2 = mesh2 self.geo_array = geo_array self.rcl_array = rcl_array self.origin1 = Position.convert_mesh1(mesh1) self.origin2 = Position.convert_mesh2(mesh1, mesh2) def convert_position(self, pos): offset = Position(pos.latitude - self.origin2.latitude, pos.longitude - self.origin2.longitude) index = Index(int(1499.0 * (1.0 - (offset.latitude / ((1.0/1.5)/8.0)))), int(2249.0 * offset.longitude / (1.0/8.0))) return index class RailCL: """ class for Rail Center Line """ def __init__(self, elem): e = elem.find("{http://fgd.gsi.go.jp/spec/2008/FGD_GMLSchema}vis") if e is None: raise Exception("{http://fgd.gsi.go.jp/spec/2008/FGD_GMLSchema}vis is not found") if e.text == "表示": self.vis = True else: self.vis = False e = elem.find("{http://fgd.gsi.go.jp/spec/2008/FGD_GMLSchema}loc/{http://www.opengis.net/gml/3.2}Curve/{http://www.opengis.net/gml/3.2}segments/{http://www.opengis.net/gml/3.2}LineStringSegment/{http://www.opengis.net/gml/3.2}posList") if e is None: raise Exception("{http://www.opengis.net/gml/3.2}posList is not found") self.array = text2array(e.text.strip()) class Position: """ class for Latitude, Longitude """ @classmethod def convert_mesh1(self, mesh1): return Position(float(mesh1//100)/1.5, float(mesh1%100)+100.0) @classmethod def convert_mesh2(self, mesh1, mesh2): pos = Position(float(mesh1//100)/1.5, float(mesh1%100)+100.0) offset = Position((1.0/1.5)/8.0 * (mesh2//10), 1.0/8.0 * (mesh2%10)) pos.add(offset) return pos def __init__(self, latitude, longitude): self.latitude = latitude self.longitude = longitude def add(self, offset): self.latitude += offset.latitude self.longitude += offset.longitude def __str__(self): return "({0:f}, {1:f})".format(self.latitude, self.longitude) class Index: """ class for Array index """ def __init__(self, y, x): self.y = y self.x = x def __str__(self): return "({0:d}, {1:d})".format(self.y, self.x) def text2array(text): lines = text.split() array = np.empty((len(lines)), dtype=np.float) i = 0 for l in lines: array[i] = float(l) i += 1 return array.reshape((len(lines)//2, 2)) geo_array = np.load(nd.NPY_DIR+"/"+NPY_DATA) tree = ET.parse(XML_RAILCL) root = tree.getroot() rails = [] for e in root.getiterator("{http://fgd.gsi.go.jp/spec/2008/FGD_GMLSchema}RailCL"): rc = RailCL(e) rails.append(rc) world = World(5340, 22, geo_array, rails) print("World.origin1="+str(world.origin1)) print("World.origin2="+str(world.origin2)) (y_max, x_max) = world.geo_array.shape print("World.geo_array.shape=({0}, {1})".format(y_max, x_max)) array = np.zeros(world.geo_array.shape) for r in rails: (y_max, x_max) = r.array.shape for y in range(y_max): pos = Position(r.array[y][0], r.array[y][1]) index = world.convert_position(pos) if r.vis: array[index.y][index.x] = 2 else: array[index.y][index.x] = 1 plot.imshow(array, interpolation='nearest') plot.colorbar() plot.show()
Pythonメモ
今回はクラスを使ってみた。
クラスについてはここを参考にした。
クラスメソッドについては、ここを参考にした。
余談
緯度・経度とlatitude, longitudeの覚え方。
道路や鉄道
土地利用細分メッシュでの森林の判定はイマイチだったので、とりあえず置いておいて、違う情報で道路や鉄道ができないか考える。
基盤地図情報の基本項目のデータ説明を見ると、道路の縁や軌道の中心線が取れるらしい。
軌道というのは鉄道の線路のことを指すらしい。
道路の縁ってあまり嬉しくないけど、軌道の中心線はありがたいのではないだろうか。
とりあえず、軌道の中心線を描けるように調べる。
なぜ普通の草が生やせないのか?
よく見る、この草。
見にくいので周りを土に変えて。
これが生やせない。
mcpipy/mcpi/block.py
を確認したけど、それらしいのはGRASS_TALL(31)
とFERN(31, 2)
くらいしかない。
で、GRASS_TALLを指定すると、枯れた木?が生えた。
ブロックID=32が「枯れ木」なので、バグ?
ちなみに、32を指定すると、同じく「枯れ木」。
で、しょうがないので自分で草を設置して、ブロックID(データも)を確認するように、getBlockWithDataを呼ぶスクリプト(getblockwd.py)を作って確認。 (ついでにsetblock.pyもデータ対応した。)
草を設置して。
getblockwd.pyで調べると、(31, 1)とわかった。
隣にsetblock 1 0 0 31 1すると、同じ草が生えた!
ということで、普通の草は(31, 1)で生やせる。
スクリプト
getBlockWithData対応のgetblockwd.py。
# coding: utf-8 import mcpi.minecraft as minecraft import mcpi.block as block import sys FORMAT = "getBlockWithData({0:d}, {1:d}, {2:d})=({3:d}, {4:d})" mc = minecraft.Minecraft() if len(sys.argv) < 4: sys.exit("Usage: getblockwd.py [x y z]") pos_x = int(sys.argv[1]) pos_y = int(sys.argv[2]) pos_z = int(sys.argv[3]) block = mc.getBlockWithData(pos_x, pos_y, pos_z) mc.postToChat(FORMAT.format(pos_x, pos_y, pos_z, block.id, block.data))
引数のデータ対応のsetblock.py。
# coding: utf-8 import mcpi.minecraft as minecraft import mcpi.block as block import sys FORMAT = "setBlock({0:d}, {1:d}, {2:d}, {3:d})" FORMAT2 = "setBlock({0:d}, {1:d}, {2:d}, {3:d}, {4:d})" mc = minecraft.Minecraft() if len(sys.argv) < 5: sys.exit("Usage: setblock.py [x y z b d]") pos_x = int(sys.argv[1]) pos_y = int(sys.argv[2]) pos_z = int(sys.argv[3]) block_id = int(sys.argv[4]) block_data = None if len(sys.argv) >= 6: block_data = int(sys.argv[5]) if block_data is None: mc.setBlock(pos_x, pos_y, pos_z, block_id) mc.postToChat(FORMAT.format(pos_x, pos_y, pos_z, block_id)) else: mc.setBlock(pos_x, pos_y, pos_z, block_id, block_data) mc.postToChat(FORMAT2.format(pos_x, pos_y, pos_z, block_id, block_data))
余談
「GRASS_TALLってどんな植物?」ってググってみると、文字通り背の高い草が…「こんなにデカい草だったのね…ちょっとイメージが違う」
FERNについても調べたら、こっちはシダだった。