見出し画像

【ツクールMV・MZ】「飛行」する敵シンボルイベントを実装しよう

シンボルエンカウントのRPGにおいて、たとえばこうもりや鳥みたいな敵はプレイヤーには通過できない段差や穴などの障害物を通り抜けて近づいてくるとそれっぽいですよね。
ただ、そういったイベントを実装しようとすると……意外とややこしかったりします。

今回はそういったシンボルイベントを実装する方法です。

Game_CharacterBase.prototype.isMapPassable = function(x, y, d) {
   var x2 = $gameMap.roundXWithDirection(x, d);
   var y2 = $gameMap.roundYWithDirection(y, d);
   var d2 = this.reverseDir(d);
   if(this.isFly()){
       return $gameMap.isCanFly(x, y) && $gameMap.isCanFly(x2, y2);
   }else{
       return $gameMap.isPassable(x, y, d) && $gameMap.isPassable(x2, y2, d2);
   }
};

Game_Character.prototype.isFly = function() {
   return false;
};

Game_Event.prototype.isFly = function() {
   return this.event().meta.fly;
};

Game_Map.prototype.isCanFly = function(x, y) {
   return this.terrainTag(x, y) !== 7;
};

さっさと答えを書くとこうです。
さて、具体的になにをしているのかを見ていきます。

まず、isMapPassable ()という関数はプレイヤーやイベントなどのキャラクターのマップタイルでの移動可能判定をしているところです。
つまり、独自の通行判定を持つ飛行キャラを実装する場合にはここをif文で判定して分岐出せます。
isFly()という関数がそれです。
これはイベントのメモ欄をみて判定しています。

画像1

メモ欄では<>で括ることでmetaデータとして利用することができます。
よって、上のイベントはthis.event().meta.flyでtrueが返ってくることになります。
それ以外はundefined(未定義)かfalseです。

Game_Character.prototype.isFly = function() {
   return false;
};

また、これが結構重要です。
詳しく説明すると長くなるのですが、要はバグ防止のためのデフォルト設定みたいなものです。
「メモ欄に<fly:true>とか書いていないキャラは飛行キャラじゃないよ」という設定です。

Game_Map.prototype.isCanFly = function(x, y) {
   return this.terrainTag(x, y) !== 7;
};

そしてこれは、飛行キャラが通れるかどうかを判定する関数です。
飛行キャラでも、たとえば洞窟の壁などは通り抜けられないはずです。
ここでは仮に「地形タグ7番だけは通れないよ」という設定にしています。

画像2

このように設定するとよいでしょう。

画像3

というわけで、無事「穴の上を飛行するイベント」が実装できました。

ちなみに、以上のようなものを実装する場合はrmmz_objects.jsを直接書き換えるのではなく、なんらかのjsファイルを自分でつくり、プラグインとして導入する形が無難です。
コアスクリプトを直接いじるとどこでなにをいじったかわからなくなり、バグの原因となりかねないからです。
また、上のは「オーバーライド」という手法で実装しているため、他のプラグインと競合する可能性があります。

const _Game_CharacterBase_isMapPassable = Game_CharacterBase.prototype.isMapPassable
Game_CharacterBase.prototype.isMapPassable = function(x, y, d) {
   var x2 = $gameMap.roundXWithDirection(x, d);
   var y2 = $gameMap.roundYWithDirection(y, d);
   var d2 = this.reverseDir(d);
   if(this.isFly()){
       return $gameMap.isCanFly(x, y) && $gameMap.isCanFly(x2, y2);
   }else{
       return _Game_CharacterBase_isMapPassable.apply(this, arguments);;
   }
};

競合防止のためには上のように書くのが無難でしょう。
これは「エイリアス」という手法です。
つまり元の処理を一端、今回では_Game_CharacterBase_isMapPassableという変数に入れて(関数を変数にぶち込めるとかどうなってんだJS)、オーバーライドした関数のなかで元の処理を呼び出すとかそんな感じです。

また、今回紹介した手法を応用すれば「水の中しか移動できない魚」「壁も通過する幽霊」なども実装可能です。

この記事が気に入ったらサポートをしてみませんか?