見出し画像

【ツクールMV・MZ】段差越しに開けない宝箱をつくろう

ツクールあるある。
段差があるのに開いてしまう宝箱!
さて、これを防ぐにはどうすればいいのでしょう?

単に、イベントとプレイヤーの間が通行不能であることを判定すればOKです。
具体的に見ていきましょう。

まず、プレイヤーの位置とイベントの位置で通行可能かどうかを判定する関数を書きます。

Game_Event.prototype.checkCanTouch = function(target) {
   const d = this.directionTowardCharacter(target);
   if(this.isObject()){
       return this.isMapPassable(this.x, this.y, d);
   }else{
       return true;
   }
};

Game_Character.prototype.directionTowardCharacter = function(character) {
   const sx = this.deltaXFrom(character.x);
   const sy = this.deltaYFrom(character.y);
   if (Math.abs(sx) > Math.abs(sy)) {
       return sx > 0 ? 4 : 6;
   } else if (sy !== 0) {
       return sy > 0 ? 8 : 2;
   }
};

キャラクターに対する向きを返り値に持つ関数は初期実装されてなかったと思うのでこれも実装します(directionTowardCharacter )。
checkCanTouch() イベントがマップ上でプレイヤーの方向に動けるかどうかを判定しています。
また、すべてのイベントに適用されるとそれはそれで厄介ですのでisObject()で適用したいイベントにだけ適用します。

画像1

適用されて厄介な場面というのはたとえばこういうときです。
机は通行不能なタイルです。
その上にある本は、当然プレイヤーの方向へは動けません。
プレイヤーもまた机の上には歩けません。
ですが、机の上の本は「調べられる」はずです。
段差の宝箱と状況は同じですが、直感としては異なるため、それを差別化するためにisObject()による判定が必要になります。

Game_Event.prototype.isObject = function() {
   return this.event().meta.object;
};

isObject()は例によってこうです。

画像2

宝箱に適用したい場合はメモ欄に<object:true>と記述します。

さて、checkCanTouch() を実際に組み込んでみましょう。プレイヤーが接触したり決定キーを押したりしてイベントを発動させる際の処理はGame_PlayerstartMapEvent()になります。

Game_Player.prototype.startMapEvent = function(x, y, triggers, normal) {
   if (!$gameMap.isEventRunning()) {
       for (const event of $gameMap.eventsXy(x, y)) {
           if (
               event.checkCanTouch(this) && //@追加
               event.isTriggerIn(triggers) &&
               event.isNormalPriority() === normal
           ) {
               event.start();
           }
       }
   }
};

そこにこうです。
まず前提として、イベントと隣接していたり重なっていたりという判定があります。
そのうえで、イベントがプレイヤーの方へ動けないような位置にある、という場合にはイベントがはじまらないというふうに書きます。
以上で、「段差越しには開けない宝箱」が完成です。

次は、主にシンボルエンカウントなどで必要になる「イベントからの接触」です。

Game_Event.prototype.checkEventTriggerTouch = function(x, y) {
   if (!$gameMap.isEventRunning()) {
       if (this._trigger === 2 && $gamePlayer.pos(x, y) && this.checkCanTouch($gamePlayer)){//@追加 
           if (!this.isJumping() && this.isNormalPriority()) {
               this.start();
           }
       }
   }
};

こうです。
敵シンボルにもまた同様に<object:true>と書くことで、段差越しに戦闘がはじまる、というようなことはなくなります。

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