前回の記事では、タイトルメニューにコマンドを追加する方法をまとめました。
プラグインの作り方入門その3:コマンドを追加する
目次
今回の目標(スリップダメージにSE追加)
RPGツクールMV・MZでは戦闘中のスリップダメージ(毒とかターン毎で受けるダメージ)にサウンドエフェクト(SE)がありません。
これを追加したいというリクエストがあったので、プラグインを作った時の流れの情報をまとめます。
検索するキーワードの選定
この記事のコードの内容はMVのものですが、調べ方や多くの関数はMZと大差ありません。
ともあれ、リファレンスを見ます。
katai5plate.github.io/RPGMV-CoreScript-Reference/
やはり最初に目につくのは Damage ですよね。
RPG.Damage Sprite_Damage がありました。
しかし、中を見ると何かが違う… 仕方がないので、先輩のプラグインを探してみます。
(ちなみに、今回のお題のプラグインは当時は無かったので作りました)
ツクプラでスリップダメージで検索すると、リジェネ(自動回復)と並んで書かれているものが目に付きます。
ここで気づく方も多いと思いますが「リジェネとスリップダメージが同時にステートがかかったらどうなるんだろう?」 関係は深そうですね。
いくつかプラグインを見ているとSlipDamageというワードはあるようです。
関数を探す
SlipDamageでコア全体をGrepしてみます。
2行出てきました。
Game_Battler.prototype.maxSlipDamage を見ると、
Game_Battler.prototype.maxSlipDamage = function() {
return $dataSystem.optSlipDeath ? this.hp : Math.max(this.hp - 1, 0);
};
ダメージ値を計算してる? スリップでの戦闘不能は許可してる?みたいな? しかも、return って、この関数を呼んでるところに、値を返してるってことなんですよね。
なので maxSlipDamage を呼んでいる場所を探します。
検索結果のもう一行を開いてみましょう。
Game_Battler.prototype.regenerateHp = function() {
var value = Math.floor(this.mhp * this.hrg);
value = Math.max(value, -this.maxSlipDamage());
if (value !== 0) {
this.gainHp(value);
}
};
やはりリジェネと一緒に計算されているっぽいですね。
ここに追記しちゃうか?と思ったところで、思いとどまってください。
ここでダメージか回復かを計算してますよね。
ということは、このダメージを変更したりする他のプラグインと競合する可能性が高そうですよね。
どうしたら良いでしょうか… まず、この関数を呼び出している場所を探します。
regenerateHp でGrepします。
結果は2行で片方は上記の関数なので、呼び出している行を開きます。
Game_Battler.prototype.regenerateAll = function() {
if (this.isAlive()) {
this.regenerateHp();
this.regenerateMp();
this.regenerateTp();
}
};
なるほど、ここでHPだけでなく、MP・TPの計算も呼び出しているようですね。
関数の目星が合っているか確認(console.log)
この当たりをつけた場所が正しいのか、関数をテンプレートに貼ってconsole.logで確認します。
(() => {
"use strict";
Game_Battler.prototype.regenerateAll = function () {
if (this.isAlive()) {
this.regenerateHp();
console.log('this.regenerateHp()');
console.log(this.regenerateHp());
this.regenerateMp();
this.regenerateTp();
}
};
Game_Battler.prototype.regenerateHp = function () {
var value = Math.floor(this.mhp * this.hrg);
value = Math.max(value, -this.maxSlipDamage());
console.log('value');
console.log(value);
if (value !== 0) {
this.gainHp(value);
}
};
})();
戦闘前に毒ステートを付与して、戦闘を開始します。
F8キーでデベロッパーツールを開きます。
まだ、何もログが出ていません。
戦闘を進めます。
この時、ウィンドウを並べてどのタイミングでログが出るのかも確認できるようにしましょう。
アクター2人と敵2体とで戦闘し、ターン終了時にログが一気に出ました。
目星はついたようです。
追加の関数を作成
まず、regenerateHpの関数名をregenerateHpSeに変えます。
実はこのオリジナル関数名が他のプラグインやコアと被ると、競合します。
なので、オリジナリティのある名前のほうが危険性は低くなるでしょう。
今回は「この名前使う人は同じ目的じゃないとつけなくない?」という安直な考えでこのままいきます。
呼び出し元にも一行足します。
this.regenerateHpSe();
(() => {
"use strict";
Game_Battler.prototype.regenerateAll = function () {
if (this.isAlive()) {
this.regenerateHpSe(); //オリジナル関数を呼ぶ
this.regenerateHp();
this.regenerateMp();
this.regenerateTp();
}
};
//オリジナル関数
Game_Battler.prototype.regenerateHpSe = function () {
var value = Math.floor(this.mhp * this.hrg);
value = Math.max(value, -this.maxSlipDamage());
if (value !== 0) {
this.gainHp(value);
}
};
})();
SEを追加する
どうやって、SEを鳴らすのか調べます。
「RPGツクールMV スクリプト SE 再生」で検索すると下記が出てきます。
rpgmaker-script-wiki.xyz/playse_mv.php
試しにサンプルコードをコピーして貼ってみましょう。
(() => {
"use strict";
Game_Battler.prototype.regenerateAll = function () {
if (this.isAlive()) {
this.regenerateHpSe(); //オリジナル関数を呼ぶ
this.regenerateHp();
this.regenerateMp();
this.regenerateTp();
}
};
//オリジナル関数
Game_Battler.prototype.regenerateHpSe = function () {
var value = Math.floor(this.mhp * this.hrg);
value = Math.max(value, -this.maxSlipDamage());
if (value !== 0) {
// this.gainHp(value);
AudioManager.playSe({ "name": "Cat", "volume": 90, "pitch": 100, "pan": 0 })
}
};
})();
テストプレイをします。
鳴りました。
条件分岐を変更する
しかし、このままだと value がプラス(回復)でも同じSEが鳴ってしまいます。
ですので、条件分岐を書き換えます。
(() => {
"use strict";
Game_Battler.prototype.regenerateAll = function () {
if (this.isAlive()) {
this.regenerateHpSe(); //オリジナル関数を呼ぶ
this.regenerateHp();
this.regenerateMp();
this.regenerateTp();
}
};
//オリジナル関数
Game_Battler.prototype.regenerateHpSe = function () {
var value = Math.floor(this.mhp * this.hrg);
value = Math.max(value, -this.maxSlipDamage());
// if (value !== 0) {
if (value < 0) {
// this.gainHp(value);
AudioManager.playSe({ "name": "Cat", "volume": 90, "pitch": 100, "pan": 0 })
}
};
})();
ダメージを受けている状態でSEが鳴り、受けていなければ鳴らないのが確認できました。
競合対策(重複コードをフック)
今回も処理を追加しているので、競合対策をします。
(() => {
"use strict";
const _Game_Battler_regenerateAll = Game_Battler.prototype.regenerateAll;
Game_Battler.prototype.regenerateAll = function () {
if (this.isAlive()) {
this.regenerateHpSe(); //オリジナル関数を呼ぶ
}
_Game_Battler_regenerateAll.call(this);
};
//オリジナル関数
Game_Battler.prototype.regenerateHpSe = function () {
var value = Math.floor(this.mhp * this.hrg);
value = Math.max(value, -this.maxSlipDamage());
// if (value !== 0) {
if (value < 0) {
// this.gainHp(value);
AudioManager.playSe({ "name": "Cat", "volume": 90, "pitch": 100, "pan": 0 })
}
};
})();
呼び出し元を追加処理する形に書き換えました。
オリジナル関数は、名前が被らなければ競合しないので、オリジナルにするだけで競合対策になっています。
あとはSEの設定を好きに変更すれば完了です。
デプロイメント対策
このままだと、このコードで使っているSEのファイルは「未使用ファイルを除外する」機能で除外されてしまいます。
この対策はプラグインパラメーターを使用します。
@requiredAssets で指定したファイルは、未使用ファイルと判断されません。
(厳密な調査はしていませんが、どうやらデフォルトで生成されるフォルダのみに対応しているような動作を経験しています)
/*:
* @requiredAssets audio/se/Cat
*/
(() => {
"use strict";
const _Game_Battler_regenerateAll = Game_Battler.prototype.regenerateAll;
Game_Battler.prototype.regenerateAll = function () {
if (this.isAlive()) {
this.regenerateHpSe(); //オリジナル関数を呼ぶ
}
_Game_Battler_regenerateAll.call(this);
};
//オリジナル関数
Game_Battler.prototype.regenerateHpSe = function () {
var value = Math.floor(this.mhp * this.hrg);
value = Math.max(value, -this.maxSlipDamage());
// if (value !== 0) {
if (value < 0) {
// this.gainHp(value);
AudioManager.playSe({ "name": "Cat", "volume": 90, "pitch": 100, "pan": 0 })
}
};
})();
完成品
MV用
fungamemake.com/archives/12162
MZ用
fungamemake.com/archives/12164
次のステップ
メモタグを使って、敵キャラ毎に消滅音を変更するプラグインを作ります。
プラグインの作り方入門その5:敵キャラ毎に消滅音を変更(メモタグ)
コメントを投稿するにはログインしてください。