⚔️

『RPGツクールMZ』タイルセットのデータ構造

2025/01/15に公開

『RPGツクールMZ』関連記事 目次

はじめに

別の記事『『RPGツクールMZ』マップの構成と更新』では、マップで使われるクラス、その包含関係および呼び出し関係を調べました。
今回は[タイルセット]のファイル読み込みとデータ構造について調べます。
とくにオートタイルなどは複雑な作りをしていて、コードをサラッと読んで理解できる物ではないので、丁寧にやります。

本記事では JavaScript での扱いを調べるので、ツール(『RPGツクールMZ』のエディタ)上での扱いは次の記事を参考にしてください。この辺りは理解している前提で書きます。

また例によって『RPGツクールMZ』非公式JavaScriptリファレンス
にクラスなど適宜リンクします。

用語

タイル属性…通行・梯子・カウンター・ダメージ床・地形タグといったタイルごとの性質です。
タイルセット…タイル画像とタイル属性をまとめたものです。
セット…タイルセットはA、B、C、D、E に分けられていて、[タイルパレット]や[データベース]-[タイルセット]ではタブで切り替えます。
領域 … セットAはA1、 A2、 A3、 A4、A5に分けられていて、たとえばA2領域と書きます。
オートタイル…配置した場所により、自動でタイルの形が選ばれるタイプのタイルで、主に地面・壁といったものに使われます。
フルオートタイル… 地面・壁の上面などに使われるオートタイル。
四角オートタイル…壁・屋根などの四角配置に限ったオートタイル。
滝オートタイル…アニメーションして縦に並べることを想定したオートタイル。
JavaScript… Webブラウザを中心に使われるプログラミング言語です。Java は別の言語の名前で JavaScript の略称ではありません。
コアスクリプト…『RPGツクールMZ』で作ったゲームに必要なクラスを定義しているスクリプトです。事実上、これを操作するのが『RPGツクールMZ』での JavaScript です。逆に一般の JavaScript プログラマは知らないので、質問しても「なにそれ」って言われる確率が高いです。プラグインは含みません。
プラグイン… ゲームの機能を拡張するプログラムです。付属しているもの、ユーザが公開しているものがあります。自作もできます。『RPGツクールMZ』のプラグインは JavaScript で書かれています。
オブジェクト…関係する値(プロパティ)と機能(メソッド)をまとめたもの。JavaScript のプログラムはこれを組み合わせてできてます。
プロパティ…オブジェクトに付随した変数です。ただし変数と違ってオブジェクトの状態で値が変わるものもあります。逆に設定することでオブジェクトの他のプロパティなどの状態が変わる場合もあります。オブジェクトに . をつけた後に指定します。例:object.property
メソッド…オブジェクトに付随した関数です。だいたいはプロパティを加工します。オブジェクトに . をつけた後に指定し、()の中で引数を指定します。例:object.method()
クラス…オブジェクトの設計図とか型とか説明される、プログラムのひとまとまり。
大域変数…プログラムのどの領域からでも扱える変数が、大域(グローバル)変数です。
配列…値に番号をつけて並べた値。例:[ 10, 4, 6 ] (これは値として数字を並べていますが他の値も並べられます)
添字…「そえじ」配列(を保持している変数)から値を取り出す際に使う数字。例:array[ 0 ] ( JavaScript の配列の添字は 0 から始まります)

タイルセットの読み込み

タイルセットはプロジェクトの'data/Tilesets.json'に入っています。
データの読み込みを管理しているのは、DataManagerクラスです。
マップの読み込みに関してはloadDataFile()というメソッドが使われます。
そして読み込みが完了するとonLoad()が呼ばれます。

ここで渡されるobject引数はタイルセットに限らず、ファイル読み込みされるさまざまなデータが入っている可能性があります。
タイルセットは大域変数$dataTilesetsに読み込まれているので、object === $dataTilesetsで判定できます。
もしタイルセットのデータを事前にいじっておきたいなら、ここで適当に前処理を入れます。
ただしデータをいじるにしても、データの構造がわかっていないとどうしようもないので、本記事ではこれからデータ構造の解説をじっくり行います。

タイルセットのデータ格納仕様

タイルセットは前述の通り、大域変数$dataTilesetsでアクセスできます。
$dataTilesetsは配列で、タイルセットIDを添字にすることで各タイルセットのデータを選択できます。

このデータの内容はざっと次のようなもので構成されています。

識別子 説明
id タイルセットのID
name タイルセットの名前
mode フィールドタイプ・エリアタイプ
tilesetNames タイルセットに使われる画像ファイル名
flags 個々のタイルの情報

詳しく知りたい場合はリファレンスTilesetのプロパティに書いてあるので参照してください。
その説明で分かりにくいのがflagsプロパティで、本記事はこれを詳細に説明します。

flagsプロパティは配列で、タイルIDを添字にしてアクセスできます。
つまり、次のようなコードで個々のタイルの情報にアクセスできるわけです。

$dataTilesets[タイルセットID].flags[タイルID]

タイルセットの領域

タイル領域(A1〜A5、B、C、D、E)はタイルIDによって決まっています。
具体的な領域開始タイルIDはTilemapの定数に設定してあり、以下のようなタイルIDになっています。

定数名 タイルID
TILE_ID_B 0
TILE_ID_C 256
TILE_ID_D 512
TILE_ID_E 768
TILE_ID_A1 2048
TILE_ID_A2 2816
TILE_ID_A3 4352
TILE_ID_A4 5888
TILE_ID_A5 1536
TILE_ID_MAX 8192
豆知識

このように各種タイルの数は固定という柔軟性に欠ける設計ですが、歴史のあるプロダクトにありがちな負の遺産というやつですね。
タイルIDが B から始まっているのはたぶん、以前のツクールにオートタイルがなくて、その仕様を引きずっているんじゃないかと思います。
ちなみに消しゴムがわりに使えるBの左上タイルにあたるflags[0]の値は16に固定です。

TILE_ID_Eの末尾(256足した所)からTILE_ID_A5の間に768個も使ってない配列があるのって、将来の拡張用としてももったいないというか、はっきり言ってムダというか…使ってないのに1536とかの4桁の数字がびっしり入ってて、そこはせめて0詰しません?
そもそも、このflagsって配列データは使ってようがいまいが、TILE_ID_MAXの8192まで全部びっしり詰まっていて、シェフの気まぐれ贅沢仕立て過ぎる!

オートタイルのタイルID

オートタイルがあるA1〜A4領域は、オートタイルひとつにタイルIDひとつではなく、オートタイルに含まれるパターンごとにタイルIDが使われています。

フルオートタイルにつき48、四角オートタイルにつき16、滝オートタイルにつき4つのパターンがあります。
ただしタイルIDとしてはフルオートタイル、四角オートタイル、滝オートタイルの区別なく48消費されます。
オートタイルのパターン番号はTilemap.getAutotileShape()メソッドにタイルIDを渡すと返してくれます。

タイルの順番は[タイルパレット]に表示される順と同じです。
具体的には『RPGツクールMZ』タイルセット規格のヘルプを参照ください。
A1領域の並びが直感的でないので、注意が必要です。

豆知識

フルオートタイルの48パターンに対して、四角オートタイルは16パターンでタイルID消費が少ない…と思いきや48個使ってるんですよ、正確にいうと使っているのは16個で、残りの32個は何も使ってなくて指定するとエラーが出るのです。
滝オートタイルに至っては4パターンしか必要ないのに48個使ってるので、44個のタイルIDをムダにしてる!
もちろんデータはムダに4桁詰だぞ!!なんで!?

つまりこんな感じのムダデータがあるということです。

オートタイル種別 使用データ(⚫︎:使用 ⚪︎:ムダ)
フルオートタイル ⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎
⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎
四角オートタイル ⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚫︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎
⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎
滝オートタイル ⚫︎⚫︎⚫︎⚫︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎
⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎⚪︎

なお、アニメーションするオートタイルだからといって3倍タイルIDが使われているわけではなく、フルオートタイルなら同じ48パターンです。

オートタイルの種類にかかわらずタイルIDを48消費するので、オートタイルの数 * 48で必要なタイルIDの数が算出できます(このために無駄なIDを使ってるとは思いたくないですが)

前記のTILE_ID_A1(2048)からこの式を使って必要なタイルID数を積み上げていくと、次のような表になります。

タイル領域 範囲計算
A1 16 2048 + 16 * 48 = 2816
A2 32 2816 + 32 * 48 = 4352
A3 32 4352 + 32 * 48 = 5120
A4 48 5888 + 48 * 48 = 8192

前に出た表の数字の意味がわかりますね。

オートタイルのパターン表現

オートタイルは基本のタイルサイズの縦横半分のパーツに4分割して、そのパーツを組み合わせてできています。
フルオートタイルなら次のようになります。

標準の48ピクセルのタイルの場合24ピクセルで分割されます

この座標[x, y]で分割したタイルの位置を指定します。
たとえば一番左上なら[0,0]右下なら[3,5]というわけです。

これを組み合わせ[左上, 右上, 左下, 右下]の順に並べた[[2,4],[1,4],[2,3],[1,3]]みたいな配列が1タイルを形成し、フルオートタイルなら48パターンがコアスクリプトで定義されています。
具体的にはTilemapの次のコードが定義箇所です。

Tilemap.FLOOR_AUTOTILE_TABLE = [
    [[2, 4], [1, 4], [2, 3], [1, 3]],
    [[2, 0], [1, 4], [2, 3], [1, 3]],
    [[2, 4], [3, 0], [2, 3], [1, 3]],
// …43行略…
    [[0, 2], [3, 2], [0, 5], [3, 5]],
    [[0, 0], [1, 0], [0, 1], [1, 1]]
];
豆知識

最後の47番には左上のアイコン部分[[0,0],[1,0],[0,1],[1,1]]が入ってますが、マップエディタでは使用できません。
ちなみに直接マップファイル(MapXXX.json)を書き換えると表示されます。
ひとつ作っておくと、エディタ上で右クリックでスポイトして使いまわせるので、JSON書き換えやってみるのもいいかもしれません。

タイル画像で見ると次の通り。

フルオートタイルの番号

4つのパーツの組み合わせは48よりもっと多くありますが、『RPGツクールMZ』の仕様としてはタイル単位に沿って綺麗につながる48パターンを抜粋して定義してある、ということです。

同様に四角オートタイルはWALL_AUTOTILE_TABLEで定義されています。
分割方法や番号の付け方に関してはサイズが(x:0〜3、y:0〜3)になっているだけでフルオートタイルと同じです。


四角オートタイルの番号

そして滝オートタイルはWATERFALL_AUTOTILE_TABLEで定義されています。
分割方法や番号の付け方に関してはサイズが(x:0〜3、y:0〜1)になっているだけでフルオートタイルと同じです。


滝オートタイルの番号

flagsの内訳

通行設定やタイル属性はflagsにビット情報として格納されていて、読み書きにはビット操作が必要です。

flagsの内容はリファレンスTileset#ビットフラグに書いてあるのでその表を引用します。

ビット 説明
0x0001 下通行不可
0x0002 左通行不可
0x0004 右通行不可
0x0008 上通行不可
0x0010 高層に表示[☆]
0x0020 梯子
0x0040 茂み
0x0080 カウンター
0x0100 ダメージ床
0x0200 小型船通行不可
0x0400 大型船通行不可
0x0800 飛行船着地不可
0xF000 地形タグ

ビット演算がわかってる人は「なるほどね」と思ってもらえると思います。
わかってない人はビット演算わかってから、また来てね。

豆知識

ビット演算について詳しいことは、ビット演算 - Wikipediaとか読んでください。
JavaScriptで使えるビット演算子についてはビット演算子 - JavaScript | MDNを読むと良いかと。

注意することとしては[通行(4方向)]設定の4ビット(下通行不可、左通行不可、右通行不可、上通行不可)はありますが、通行設定は別にないということです。
通行設定以外の設定はすべて0として、通行設定は次のように表されます。

ビット 説明
0x0000 通行可[⚪︎]
0x000F 通行不可[×]
0x0010 高層[☆]

ここで高層[☆]設定をした場合、[通行(4方向)]設定の4ビットは無視されます。

小型船通行不可、大型船通行不可、飛行船着地不可の値はツール側で自動でつけられ、ユーザ側での操作ができません。
小型船、大型船については公式のヘルプのA1タイルの項目に解説がありますが、飛行船に関しては着陸できるのは、歩行できる場所のみです。と今ひとつ要領を得ません。

豆知識

ここで気づいた方もいるかと思いますがパターン毎に違いが必要なのは[通行設定]だけなので
[カウンター]などのタイル属性はオートタイルのパターンを問わずひとつあれば十分なはずです。
そして勿論、皆様の予想に違わずパターンが違っても全部同じデータが入っています。
これはオートタイルのデータが4倍になる程度で、さほど大きな無駄ではない(感覚が麻痺)ですが、無駄ですよね。

そして地形タグは4ビット(0〜15)枠があるんですが、実際はご存知の通り3ビット(0〜7)しか使われていません。

最後に

このような感じで、タイルセットの JSON の中身はかなり複雑で無駄が多く柔軟性に欠ける設計です。
そのため直感を裏切る箇所が多く、仕様を調べるのに難儀しました。

マップのタイルの前後を歩けるようにするプラグイン TF_LayerdMap.js を作るために調べたのですが、制作に使った時間の半分ぐらい費やしてしまった気がします。
ちなみに高層[☆]設定をした場合に無視される[通行(4方向)]設定の4ビットが勿体無かったので、設定に利用しました。

では、レッツエンジョイ ツクールライフ!

Discussion