ツクールMVでネオエクスデスを実装するには

あなたは「RPGツクールMV」を持っています。

よーし、かっこいいラスボスをつくるぞ!
ネオエクスデスみたいにパーツが分かれてるタイプのラスボスをつくろう!

そしてかっこいいグラフィックも用意しました。
本体があって、赤い顔は多分攻撃力がすごくて、緑の顔はデバフとか状態異常を使ってきて、青いのは回復かな?
それぞれをパーツ分けして敵グループに配置してみよう!

ちがう、そうじゃない。
本体が手前に来て顔が隠れとるやないかい!

と、ツクールMVでの敵グループはY座標で「手前」か「奥」かを判定しているため、ふつうにやるとこうなります。
ではどうすればいいのか?
方法はいろいろありますが、こうなったらその判定基準を新しくつくりましょう

// エネミー表示位置調整
Game_Enemy.prototype.setup = function(enemyId, x, y) {
   this._enemyId = enemyId;
   this._screenX = x;
   this._screenY = y;
   this.front = $dataEnemies[enemyId].meta.front;
   this.recoverAll();
};

Sprite_Enemy.prototype.setBattler = function(battler) {
   Sprite_Battler.prototype.setBattler.call(this, battler);
   this._enemy = battler;
   this.front = $dataEnemies[battler._enemyId].meta.front; //追加
   this.setHome(battler.screenX(), battler.screenY());
   this._stateIconSprite.setup(battler);
};

Spriteset_Battle.prototype.compareEnemySprite = function(a, b) {
   if(a.front && b.front){
       return a.front - b.front; //追加
   } else if (a.y !== b.y) {
       return a.y - b.y;
   } else {
       return b.spriteId - a.spriteId;
   }
};

つまりこうです。
「compareEnemySprite」という関数が「どっちが手前?」というのを判定しています。
ここに「Y座標」以外に「metaのfrontを参照する場合」を追加しました。

うわ! 急に専門用語を連発するな!
えーっと、まずmetaってなんやねんって話ですが。

これです。
ツクールMVでは、既存の機能では表現できないことがあるとだいたいこのメモ欄に<>で括った記述をつけ足してナントカします。
この場合はfrontというのを追加して、それぞれの敵キャラに数値を振ってます。

本体は<front:0>、手前の顔パーツは<front:1>です。
こうすることで……?

はい、できました。
できましたが……

位置がめちゃくちゃやないかい!
ただ、これと同じことしようとするとわかると思いますが……

GUIはこのありさまです。
ふつうに位置合わせするのは困難です。
ではどうすればいいのか?

数値を直接入力してしまいましょう。
つまりこうです。

えーっと、これだけ見せられてもなにやってるのか全然わかんないとは思いますが。
僕もめちゃくちゃ混乱しました。

xとyというのはそのまま座標を意味していますが、敵グループに関しては原点が特殊です。
ふつう、画像の原点は左上を指しますが……
この場合、xは中心、yは下です。

どうしてそんな仕様になってるかはよく知りませんが、そうなってます。
そういうわけで、まずは本体の位置を設定しましょう。

真ん中なので816/2=408です(一行目)。
yの位置は……まあ、適当でいいでしょう。500くらいにしておきます(二行目)。
で、それぞれを基準点とするためローカル変数x,yを宣言します(三、四行目)。
以降はパーツごとの座標設定です。
この数値を入力するためには以下のような計測を必要とします。

パーツそれぞれの大きさと、左上の座標です。
例として青い顔を見てみましょう。

$dataTroops[1].members[1].x = x + 240/2 + 360;
$dataTroops[1].members[1].y = y + 250;

xの240というのは画像の幅(width)です。x座標は原点が中心なので/2してます。
360というのは画像の左上のx座標です。
yの方はシンプルに、基準に対して高さ(height)とy座標分を足せばOKです。

図示するとこうです。
うーん、ややこしい。

$dataTroops[1].members[0].x = 408;
$dataTroops[1].members[0].y = 500;
var x = $dataTroops[1].members[0].x - 600/2;
var y = $dataTroops[1].members[0].y - 563;
$dataTroops[1].members[1].x = x + 240/2 + 360;
$dataTroops[1].members[1].y = y + 250;
$dataTroops[1].members[2].x = x + 190/2;
$dataTroops[1].members[2].y = y + 230 + 147;
$dataTroops[1].members[3].x = x + 180/2 + 304;
$dataTroops[1].members[3].y = y + 200 + 290;

全体ではこんな感じです。

完成!

とまあ、やってみてわかりましたがめちゃくちゃめんどくさかったです。
そのうえ、YEP_BattleEngineCoreを導入していると競合します。

this._battleField.children.sort(this.battleFieldDepthCompare);

具体的にはこの行です。
たぶんZ軸カメラに関する関数です。「そんなん使わねえなあ!」って場合はコメントアウトしちゃってください。
使う場合は……頑張ってください(投げやり)。

あとはそうですね、クリック選択をしようとする場合も「手前のが選べねえ!」と悲惨なことになります。

Window_BattleEnemy.prototype.getClickedEnemy = function() {
   var clickEnemies = this._enemies.concat();
   clickEnemies.sort(this.clickSort.bind(this));
   for (var i = 0; i < clickEnemies.length; ++i) {//変更
     var enemy = clickEnemies[i];
     if (!enemy) continue;
     if (this.isClickedEnemy(enemy)) {
       if (this._selectDead && !enemy.isDead()) continue;
       var index = this._enemies.indexOf(enemy)
       if (this._inputLock && index !== this.index()) continue;
       return index;
     }
   }
   return -1;
};

Window_BattleEnemy.prototype.clickSort = function(a,b) {
 if(a.front && b.front){//変更
   return b.front - a.front;
 } else if (a.y !== b.y) {
   return b.y - a.y;
 } 
};

なので、こうです。
手前の方を優先してクリックするというふうに書き換えます
手前かどうかはmeta.frontを参照します。

えっと、やっぱめんどくさいね……?
でもまあ、それでもネオエクスデスみたいなラスボスに憧れてやまないツクラーも多いかと思いますので、ここにノウハウを共有しておきます!

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