『RPGツクールMZ』マップイベントの構成と更新
はじめに
『RPGツクールMZ』の[イベント]が JavaScript 上でどのように実装されているか調べていきます。
[イベント]はマップ上の[イベント]と全体で使える[コモンイベント]および戦闘時の[バトルイベント]があります。
さすがに全部は大変なので、本記事ではマップ上の[イベント](以下マップイベント)のみ調べます。
ツール上のマップイベントについては、次の記事にまとめています。
この辺についてはすでに理解しているものとして書いていきます。
『RPGツクールMZ』非公式JavaScriptリファレンス
適宜このリファレンスのページにクラスなどリンクします。
用語
イベント … 画像とその挙動を組み合わせたもの。マップに貼るシールみたいなもので、住人や宝箱などに使います。
イベントコマンド…ゲーム中に実行される内容を書き記すもの、いわゆるプログラムで[実行内容]に書かれます。
コモンイベント…ゲーム中どのイベントからでも呼び出せるイベントコマンドです。プログラム的には大域(グローバル)関数に当たります。
マップイベント…マップ上に置かれる[イベント]の別名。
EVページ … イベントページを省略したものです。(バトル)イベントの[実行内容]をEVページ単位でまとめて切り替えられます。
出現条件… 複数のEVページのうちどれを使うか判断するための条件です。バトル中は単に条件と書かれます。
JavaScript… Webブラウザを中心に使われるプログラミング言語です。Java は別の言語の名前で JavaScript の略称ではありません。
コアスクリプト…『RPGツクールMZ』で作ったゲームに必要なクラスを定義しているスクリプトです。事実上、これを操作するのが『RPGツクールMZ』での JavaScript です。逆に一般の JavaScript プログラマは知らないので、質問しても「なにそれ」って言われる確率が高いです。プラグインは含みません。
プラグイン… ゲームの機能を拡張するプログラムです。付属しているもの、ユーザが公開しているものがあります。自作もできます。『RPGツクールMZ』 のプラグインは JavaScript で書かれています。
オブジェクト…関係する値(プロパティ)と機能(メソッド)をまとめたもの。JavaScript のプログラムはこれを組み合わせてできてます。
プロパティ…オブジェクトに付随した変数です。ただし変数と違ってオブジェクトの状態で値が変わるものもあります。逆に設定することでオブジェクトの他のプロパティなどの状態が変わる場合もあります。オブジェクトに . をつけた後に指定します。例:object.property
メソッド…オブジェクトに付随した関数です。だいたいはプロパティを加工します。オブジェクトに . をつけた後に指定し、()の中で引数を指定します。例:object.method()
クラス…オブジェクトの設計図とか型とか説明される、プログラムのひとまとまり。
継承…クラスのプロパティ・メソッドを引き継いで、さらに機能を追加したクラスを作ることです。
大域変数…プログラムのどの領域からでも扱える変数が、大域(グローバル)変数です。
クラスツリー
RPGツクールMZ 非公式JavaScriptリファレンス - クラスツリーからマップイベント関連のクラスを抜粋したものが次のリストです。
データベース
画像
その他オブジェクト
- Game_Map ($gameMap)
- Game_Interpreter
- Game_CharacterBase
- Bitmap
- Graphics
- DataManager
- ImageManager
- SceneManager
マップイベントはマップ上に定義されているので、非常に強くマップと結びついています。
なので実際はイベントの上位にあるだけで、あまり気にしなくてもいいクラスもあります。
マップイベントまでのクラスの包含関係
クラスの継承関係はだいたいわかったとして、稼働している状態でどのオブジェクトがどのオブジェクトを抱えているのかを追っていきます。
マップイベントなので、大まかな部分は『RPGツクールMZ』マップの構成と更新記事の内容と被ります。
被っている部分は、おさらい程度で飛ばしますので、わからなかったらマップの方の記事をお読みください。
SceneManager→Scene_Map→Spriteset_Map→Sprite→Tilemap→Sprite_Character
という感じでマップイベントを表示しているオブジェクトにたどり着きます。
SceneManagerからプロパティをつなげていくと次の通りで、JavaScriptコンソールで配列の中を確認できます。
SceneManager._scene._spriteset._characterSprites
このコードだとSpriteとTilemapクラスが飛んでますが、Spriteset_MapがSprite_Characterに直接アクセスできるプロパティを持っているためです。
詳しくは豆知識にまとめました。気になる方は読んでみてください。
豆知識
Sprite_CharacterはTilemapクラスのchildrenプロパティにも含まれているのですが、前記の通りSpriteset_Mapクラスがプロパティとして持っているのでアクセスするのにSceneManager._scene._spriteset._baseSprite.children[n].children[n]とする必要はありません。
またTilemap.childrenプロパティにはその他に、タッチした時に光るマーカーやマップ(低層・高層)、飛行船の影なども含まれていますが、これらもSpriteset_Mapクラスのプロパティとしてアクセスできます。
| プロパティ | クラス | 説明 | 
|---|---|---|
| _characterSprites | Sprite_Character | キャラ | 
| _shadowSprite | Sprite | 飛行船の影 | 
| _destinationSprite | Sprite_Destination | タッチマーカー | 
| _balloonSprites | Sprite_Balloon | フキダシ | 
| _animationSprites | Sprite_AnimationMV / | Sprite_Animation | 
オブジェクトそのものはTilemap.childrenに含まれているのと同じものです。
常に存在するものもありますが、状況によって追加・削除されるものもあります。
ちなみに他にもSpriteset_Mapクラスには次のようなプロパティが設定されています。
| プロパティ | クラス | 説明 | 
|---|---|---|
| _weather | Weather | 天気 | 
| _parallax | TilingSprite | 背景 | 
| _blackScreen | ScreenSprite | フェードなどのエフェクト用 | 
| _timerSprite | Sprite_Timer | タイマー | 
| _pictureContainer | Sprite | ピクチャ表示 | 
| _baseSprite | Sprite | マップ本体 | 
Spriteset_Mapがプロパティとして持っているオブジェクトがchildlenとして追加されている場所をツリー表示すると、次のようになります。
- 
_spriteset(Spriteset_Map)- _weather
- _blackScreen
- _timerSprite
- _pictureContainer
- 
_baseSprite- _parallax
- 
_tilemap- _characterSprites
- _shadowSprite
- _destinationSprite
- _balloonSprites
- _animationSprites
 
 
 
ちなみに、別の方法でアクセスできるようにしているのは、childlenを辿ってアクセスするよりSpriteset_Mapからプロパティとしてアクセスできた方が分かりやすいし短く書けて便利という程度の理由だと思います。
ただしプログラムとしては、分かりやすいのも短いのも、とても大事です。
マップイベントのデータ構造
'MapXXX.json'のJSONデータは大域変数$dataMapに入っています。
マップイベントの情報はMapのeventsプロパティに入っていて、さらにその下の構成は次の通り。
- 
events:Event配列- 
pages:EventPage配列- 
conditions:EventPage.Conditions
- 
image:EventPage.Image
- 
list:EventCommand
 
- 
 
- 
大体、データベースのウィンドウの内容そのままです。
イベントID:10のEventは次のようなコードで取得できます。簡単ですね。
$dataMap.events[10].name
マップイベントの画像とデータを繋ぐクラス
SceneManagerの下に画像を扱うクラスがあり、そして大域変数$dataMapに JSONデータが格納されていました。それらを繋ぐクラスがGame_Mapです。
これは大域変数$gameMapに登録されているので、簡単にアクセスできます。
Game_Mapの_eventsプロパティにGame_Eventが配列型式で入っていて、添字はイベントIDです。
イベントID:10のマップイベント(Game_Event)は次のようなコードで取得できます。簡単ですね。
$gameMap._events[10]
Game_Eventはマップイベントの現在の状態を持っていますが、固定値や初期値については_eventIdプロパティを使って、上記$dataMapにある同じイベントIDのデータを参照しています。
マップイベントの挙動を追う
構造がわかったので、今度はマップイベントの動作の仕組みを追ってみます。
『RPGツクールMZ』マップの構成と更新で説明した部分は簡単におさらい程度で。
マップイベントのupdate()
『RPGツクールMZ』はupdate() というメソッドが毎フレーム呼ばれます。
SceneManager→Scene_Map→Game_Map→Game_Eventオブジェクトのupdate()が順次起動されます。
Game_Mapのupdate()メソッドでもマップイベント関連の処理が行われます。
refreshIfNeeded()はスイッチ・変数などの変化があった場合、EVページの切り替えが行われます。
このEVページ切り替え処理はマップ上のすべてのGame_Eventオブジェクトのrefresh()メソッドが呼ばれます。
マップイベントに関してはGame_MapクラスのupdateEvents()メソッドからGame_Eventのupdate()が呼ばれます。
継承元のGame_CharacterBaseのupdate()から呼ばれるupdateAnimation()に[移動ルート]の処理は記述されています。
なのでGame_CharacterBaseを継承しているGame_Player(プレイヤー)も[移動ルート]の対象として指定できるわけです。
ならばGame_Follower(隊列メンバー)やGame_Vehicle(乗り物)も移動ルートの指定ができて良さそうなのですが『RPGツクールMZ』のエディタ上ではできません。
TF_CharEx.jsというプラグインを使えば[移動ルート]の対象に隊列メンバーや乗り物を指定できます。
[実行内容]の処理については後述します。
マップイベントの描画メソッド
update()と似たメソッドでupdateTransform()やrender()というメソッドがあります。
Sprite_Characterに関しては、Game_Event(など)の方で値を変更しておけば、それを参照して画面に反映してくれます。
この辺りの処理はロンチプラグインのEventEffects.jsが参考になると思います。
イベントコマンドの実行
マップイベントの重要な要素として画像の描画とともに[実行内容]の処理があります。
イベントコマンド自体は同じですが、Game_Mapで実行されるものとGame_Eventで実行されるものがあります。
マップでひとつだけの実行内容
Game_Mapのupdate()メソッドをみてみましょう。
Game_Map.prototype.update = function( sceneActive ) {
    this.refreshIfNeeded();
    if( sceneActive ) {
        this.updateInterpreter();
    }
    this.updateScroll();
    this.updateEvents();
    this.updateVehicles();
    this.updateParallax();
};
前述のrefreshIfNeeded()メソッドによるEVページの切り替えが行われます。
そしてupdateInterpreter()メソッドで[実行内容]の処理が行われます。
ここで処理される[実行内容]はマップにつきひとつだけ実行されるタイプのイベント、つまり[決定ボタン][プレイヤーから接触][イベントから接触][自動実行]のいずれかです。
マップイベントごとの実行内容
EVページ切り替え処理でGame_Eventのrefresh()→setupPage()→setupPageSettings()メソッドが呼ばれます。
ここで切り替えられたEVページに[並列処理]設定されているマップイベントの_interpreterメソッドには新規にGame_Interpreterオブジェクトが代入されます。
他のトリガーの_interpreterはnull(空)です。
そして今度はGame_Mapのupdate()→updateEvents()メソッドからGame_Eventのupdate()→updateParallel()メソッドが呼ばれます。
[並列処理]のマップイベントなら_interpreterが空ではないはずなので、([移動ルート]の処理と類似の処理である)トリガが[並列処理]の場合の[実行内容]の処理が行われます。
最後に
マップイベントは『RPGツクールMZ』の根幹のシステムだけあって、なかなか複雑です。
画像、動作、プログラミングコードの要素があり、さらにフキダシアイコンなどの周辺オブジェクトもあって大変です。
またこれらのものが昔のツクールから拡張を繰り返し、過剰増築の様相なのも問題です。
たとえば[移動ルート]とトリガ[並列処理]の[実行内容]は役割が丸かぶりしている部分があり、「なんで別になってるの?」「同時に動かしたらどっちが優先されるの?」と疑問が浮かび、理解のハードルを上げてきます。
仕様やJavaScriptのコードが整理されてないのに加え、用語に適切なものが使われていないことも理解を阻みます。
…次回作では整理して欲しいですね!
そんなわけで、今回の記事は核心の部分(Game_Interpreterクラス)を調べる前に終わった感ですが、核心の部分を調べて公開するかは未定です。
レッツエンジョイ ツクールライフ!


Discussion