読者です 読者をやめる 読者になる 読者になる

頼りないニモニック

はっきりいって個人の日記レベル

MinecraftのMODを作ってみた (2日目)

f:id:nanase_t:20130316214314p:plain

昨日に引き続き、MODについて勉強してみました。今日はチャンクから高度データと光量データを取得します。
余談ですが、昨日までその都度リコンパイルを行なっていたために開発効率が悪かったのですが、Eclipseからそのまま実行できることを知り効率が上がりました。

テストコード

必要な部分にだけ注釈を振りました。プレイヤーが異なるチャンクに移動した時、チャンクの高度データの最初8個の値、そしてプレイヤーが立っている地点の晴天光量と暗黒光量(後述)をチャット欄に流します。

processメソッドがコア部分です。以下、解説します。

高度データ

高度を取得する際はチャンクオブジェクトを取得してから heightMap という配列を取り出す方法がベストです。チャンクオブジェクトはgetChunkFromChunkCoordsメソッドで取得します。引数にはチャンク番号のX, Zを指定します。チャンク番号はブロック座標とは異なり、逆にブロック座標でチャンクオブジェクトを取得したい時はgetChunkFromBlockCoordsメソッドで取得します。
チャンクはX, Z軸方向に16の長さを持っているため、ブロック座標からチャンク番号への変換は各座標値を4ビット右シフト(≒16で除算)したものと等しいです。

heightMapで取得した配列は一辺16の正方形、256の長さ(面積)を表しています。要素は最も高い位置に存在するブロックのY座標を表します。これはたとえ、浮島のように地面と接しているかは関係がありません。また奈落まで貫通している場合は最小値の 0 となります。

高さが1に満たないブロックは例外があり、たとえば、

  1. ハーフブロックのように0.5ブロックの高さをもつものは四捨五入されて 1 ブロックの高さ
  2. レールや感圧式スイッチなど0.5ブロック未満のものは 0 ブロックの高さ
  3. Minecraft 1.5 から8つで1ブロックとなる雪ブロックは いくつ積み重ねても 0 ブロックの高さ

となっています。

エンティティはこの高さに当てはまりません。そのためプレイヤー、敵、動物はもちろん、トロッコや動作中のTNTなどは当てはまりません。また要素は北西方向(地図の左上)から南東方向(右下)へ走査しています。

光量データ

光量は 0 から 15 の数値で、詳しくはこちらでまとめられています。
テストコード66、67行目が光量の取得となっています。光量には2種類あり、ここでは便宜上 晴天光量暗黒光量と呼びます(実際にこのように呼ばれているわけではありません)。

それぞれの特徴をまとめると、

  • 晴天光量 - 晴天の日中、明るさ15の太陽によって照らされた時のブロック表面の明るさ。頭上が空である場合は常に 15 となり、天候や別光源に非依存。逆に頭上に障害物がある場合は別光源(松明など)による光量。
  • 暗黒光量 - 太陽や月など天体による光源が全く無い場合のブロック表面の明るさ。松明やグロウストーンなどによる光源から照らされた場合の光量。

しかし実際にゲーム中で使われる光量を現実光量とすると 「現実光量 = 晴天光量 > 暗黒光量 ? 晴天光量 : 暗黒光量」となっているようです。すなわち、屋根のある構造物や地下などは晴天光量は 0 となりますから、「現実光量 = 暗黒光量」となります。

プログラム中では getBlockLightValueメソッドを使うとブロック表面の光量を取得できます。ただし、パラメータの座標はブロック表面と接しているチャンク座標系の座標を指定します。チャンク座標系はチャンク内での座標で、ブロック座標系の下位4ビットが対応します。コード上では 0xf (15) でAND演算しています。また、ブロックが存在する座標ではブロック内部の光量となりますから、透過ブロックでない場合は常に 光量 0 となります(未検証)。

第4パラメータは「15 - 光源からの明るさ」を指定します。晴天光量の場合、太陽の明るさは 15 ですから 0 を指定します。月光であれば 15 - 4 で 11 を指定します。暗黒光量であれば、そのまま 15 を指定します。


ブロック座標系、チャンク座標系は別物ですが、変換は一度理解すれば簡単です。チャンクオブジェクトの持つメソッドで座標が必要なものはほとんどがチャンク座標系です。
当初目標は今回取得したデータを外部に出力できれば完了です。