RPGツクールプラグイン制作過程紹介 第5回
前回は、プレイヤーの目の前にイベントが存在するかどうかを判定する関数を作成し、コモンイベントに組み込みました。
今回は、それをさらにブラッシュアップしていきます。
現在の挙動
これまではマップにイベントを一つだけ設置した状態でテストしていましたが、せっかく関数を作成したのですからもっとたくさん置いてみましょう。
これらは例のたきぎイベントを単にコピーしただけのものです。早速テストしてみましょう。
ご覧の通りすべてのたきぎに同時に火がついてしまってますね! これは期待通りの挙動とは言えませんので設定に変更を加えてみます。
まずは、それぞれのイベントに設定しているゲームスイッチの番号をずらします。
こうすれば、それぞれ別々に発火させられるはずですね。続いてコモンイベント側を見てみましょう。
前回の関数の条件分岐内にスイッチを設定しているわけですが、これをどう変更すえばたきぎの区別がつけられるでしょうか。
例えば「1〜6すべてのスイッチをオンにする」という処理にしたらまた同時に発火してしまいます。
それを防ぐためには「目の前にあるイベントに設定されているスイッチ番号を取得し、その番号のスイッチだけをオンにする」という処理にする必要がありそうです。
ではどうすればスイッチ番号を取得できるでしょうか。イベント自身に「キミに設定されているスイッチは何番かな?」と質問して、「ボクに設定されているスイッチは1番ダヨ!」と答えてくれるようにお願いでもしてみますか?
…冗談のようですが、それがおそらく最も手っ取り早い方法です。実際にはイベントがしゃべるわけではありませんが、外部からの参照(設定されているスイッチは何番か?)に対応するプロパティ(スイッチ番号)を返す、というやりとりはまさにプログラムとの対話と言えます。
これを実現するためには、まずイベントにプロパティを設定する必要があります。
挙動の改善
ツクールMVやMZでは、「メモ」という項目がデータベースの各ページに用意されていますよね? ここに所定の書式を記述すると、そのデータに任意のプロパティを設定することができるのです。以下のフォーマットになります。
<プロパティ名:値>
例えばアクターに、ツクール標準には存在しないパラメータ「age(年齢)」を追加したいとします。リードは15歳、プリシアは14歳…という設定をする場合、以下のように記述します。
このメモ欄を利用したプロパティを「メタデータ」といい、メモが存在するすべてのデータで利用できます。もちろん、設定したプロパティは取得することもできます(詳細は後述)。
この方法によるプロパティの追加は非常に便利であり公式・個人を問わず多くのプラグインで利用されているため、導入したプラグインにてこの書式を見たり書いたりしたことがおありの方もいらっしゃることでしょう。
今回はこの方法を使用して、イベントにゲームスイッチ番号プロパティを追加してみたいと思います。早速やってみましょう。
イベントのメモに以下の記述を追加しました。
<skillSwitchId:スイッチ番号>
スイッチ番号の部分は、そのイベントの2ページ目の条件として設定されているゲームスイッチ番号にします。もちろん、すべてのたきぎに対して設定しておきます。
これでイベントのプロパティを取得することができました。続いて、このプロパティを取得する方法を実装します。
イベントはGame_Eventクラスです。このクラスにメタデータからのプロパティ取得関数を定義することで、イベント自身にお返事してもらいましょう。まずは関数名と枠をFieldAction.jsに定義します。場所はどこでもいいのですが前回作成したisFacingSkillTargetsの下にしました。関数名はskillSwitchIdという、先程のプロパティ名と同名となっていますが、必ずしも同名である必要はありません。
メタデータから上記にて設定したプロパティを取得して返すので、以下のようなコードを記述します。
Game_Event.prototype.skillSwitchId = function() {
return this.event().meta.skillSwitchId;
};
Game_Eventクラスの関数においてメタデータは上記のように、this.event().meta.プロパティ名という形式で取得できます。このevent()という関数が何であるのかについては、かなり込み入った解説になってしまうので今回は割愛します。今後の回でご紹介できればいいな、と考えています。
プロパティ取得の準備はこれでできましたので、続いては実際にこのプロパティの値をコモンイベント内で取得する方法について考えていきましょう。
前回はisFacingSkillTargetsという関数にてイベントに直面しているかどうかを判定しましたが、実際にどのイベントに面しているのかについては特に気にしていませんでしたね。ただしこの関数内で取得自体はしていたのです。改めて見てみましょう。
Game_Player.prototype.isFacingSkillTargets = function() {
const direction = this.direction();
const x1 = this.x;
const y1 = this.y;
const x2 = $gameMap.roundXWithDirection(x1, direction);
const y2 = $gameMap.roundYWithDirection(y1, direction);
const events = $gameMap.eventsXy(x2, y2);
return events.length > 0;
};
上記のeventsという定数には、$gameMap.eventsXy()の戻り値である配列を代入しています。この関数内ではあくまでこの配列の要素数が0よりも大きいのかどうかしか判定せず、中身までは見ていませんでした。今回はこの中身を利用したいと思います。
以下のような処理をすれば目的の機能が実現できるのではないでしょうか。
つまりこの関数内でスイッチのオンまでやってしまうわけです。その方が同じイベントコマンドを何度も繰り返さなくて済む分ラクでしょうね。
では実際に関数を作っていきましょう。まず、isFacingSkillTargetsを丸ごとコピーします。
場所もisFacingSkillTargetsの真下がちょうど良さそうですね。関数名ですが、今回はtoggleSwitchesByFacingSkillTargetsとします。先程のコピー関数の名前をこちらに変更します。
また、今回は配列要素数が0より大きいかどうかの判定は関係ありませんので、一番下のreturn文を削除します。
Game_Player.prototype.toggleSwitchesByFacingSkillTargets = function() {
const direction = this.direction();
const x1 = this.x;
const y1 = this.y;
const x2 = $gameMap.roundXWithDirection(x1, direction);
const y2 = $gameMap.roundYWithDirection(y1, direction);
const events = $gameMap.eventsXy(x2, y2);
};
配列内の要素の操作ですので、イテレータを使います。今回はfor of文を使ってみましょう。
// 中略
const events = $gameMap.eventsXy(x2, y2);
for (const event of events) {
}
まずはskillSwitchIdプロパティによってスイッチ番号を取得します。
for (const event of events) {
const switchId = event.skillSwitchId();
}
そしてその番号のスイッチをオンにしましょう。普段イベントコマンドで当然のように設定している処理ですが、これをスクリプトで実行するにはどうすればいいのでしょうか?
結論を言ってしまうと以下のコードにて実行できるのですが、覚えておくと便利です。
$gameSwitches.setValue(スイッチ番号, 値)
値はtrue(オン)かfalse(オフ)です。では早速組み込んでみましょう。
for (const event of events) {
const switchId = event.skillSwitchId();
$gameSwitches.setValue(switchId, true);
}
上記でスイッチ番号を代入したswitchId定数をsetValueの第一引数にしています。これでこのイベントのスイッチをオンにできるはずです。これでこの関数はひとまず完成です。以下のようになりました。
Game_Player.prototype.toggleSwitchesByFacingSkillTargets = function() {
const direction = this.direction();
const x1 = this.x;
const y1 = this.y;
const x2 = $gameMap.roundXWithDirection(x1, direction);
const y2 = $gameMap.roundYWithDirection(y1, direction);
const events = $gameMap.eventsXy(x2, y2);
for (const event of events) {
const switchId = event.skillSwitchId();
$gameSwitches.setValue(switchId, true);
}
};
ところでfor文より上の部分ですが、isFacingSkillTargets関数のreturn文以外の部分と同一ですよね? この場合、両者の処理を共通化した方がスッキリします。そこでもう一度isFacingSkillTargetsをコピーし、最後のreturn文を削除します。関数名はfacingSkillTargetsとします。
Game_Player.prototype.facingSkillTargets = function() {
const direction = this.direction();
const x1 = this.x;
const y1 = this.y;
const x2 = $gameMap.roundXWithDirection(x1, direction);
const y2 = $gameMap.roundYWithDirection(y1, direction);
const events = $gameMap.eventsXy(x2, y2);
};
そして最後にeventsという定数をreturn文で返します。
Game_Player.prototype.facingSkillTargets = function() {
const direction = this.direction();
const x1 = this.x;
const y1 = this.y;
const x2 = $gameMap.roundXWithDirection(x1, direction);
const y2 = $gameMap.roundYWithDirection(y1, direction);
const events = $gameMap.eventsXy(x2, y2);
return events;
};
これによってこの関数を呼び出したとき、プレイヤーの目の前にあるイベントをすべて取得できます。
続いてこれまでに作成した2つの関数内の処理を書き変えましょう。まずはisFacingSkillTargetsです。この関数内の一番上に以下の文を追加します。
const events = this.facingSkillTargets();
そしてもともと存在したconst eventsまでを丸ごと削除してしまいます。以下のようになります。
Game_Player.prototype.isFacingSkillTargets = function() {
const events = this.facingSkillTargets();
return events.length > 0;
};
とてもスッキリした見た目になりましたね。これでも動作はこれまでと全く同じです。というのも、今削除した部分を先程作成したfacingSkillTargets関数にすべて移し替えた上で、その関数の戻り値をevents定数に代入しているからです。同様にtoggleSwitchesByFacingSkillTargets関数の同じ処理の部分も置き換えましょう。以下のようになるはずです。
Game_Player.prototype.toggleSwitchesByFacingSkillTargets = function() {
const events = this.facingSkillTargets();
for (const event of events) {
const switchId = event.skillSwitchId();
$gameSwitches.setValue(switchId, true);
}
};
さて、実際にコモンイベントに組み込んでみましょう。コモンイベント2番の、これまでゲームスイッチをオンにしていた部分を削除し、イベントコマンドのスクリプトを挿入します。以下のコードを貼り付けます。
$gamePlayer.toggleSwitchesByFacingSkillTargets();
それではテストしてみましょう!
きちんと個別に火がつけられるようになりましたね!
まとめ
というわけで今回は課題①の解消に向けた処理を追加しました。お疲れ様でした。
これでもまだ全ての問題が解決したわけではないのですが、あらかた期待通りの動作になってきたと言えるでしょう。
ところでイベントコマンドのスクリプトに毎回同じコードを書くのはややおっくうだと思いませんか? それに、プラグイン利用者の人にとってもコードを打ち込むのは手間だと思います。そこで次回はこのスクリプトを「プラグインコマンド」にする手順をご紹介したいと考えています。
何かありましたらお気軽にコメントください。それではまた次回お会いしましょう!
今回までの最終コード
//=============================================================================
// RPG Maker MZ -
//=============================================================================
/*:
* @target MZ
* @plugindesc
* @author
*
* @help
*
*
*
*
*/
/*:ja
* @target MZ
* @plugindesc
* @author
*
* @help
*
*
*
*
*/
(() => {
'use strict';
Game_Player.prototype.facingSkillTargets = function() {
const direction = this.direction();
const x1 = this.x;
const y1 = this.y;
const x2 = $gameMap.roundXWithDirection(x1, direction);
const y2 = $gameMap.roundYWithDirection(y1, direction);
const events = $gameMap.eventsXy(x2, y2);
return events;
};
Game_Player.prototype.isFacingSkillTargets = function() {
const events = this.facingSkillTargets();
return events.length > 0;
};
Game_Player.prototype.toggleSwitchesByFacingSkillTargets = function() {
const events = this.facingSkillTargets();
for (const event of events) {
const switchId = event.skillSwitchId();
$gameSwitches.setValue(switchId, true);
}
};
Game_Event.prototype.skillSwitchId = function() {
return this.event().meta.skillSwitchId;
};
})();
この記事が気に入ったらサポートをしてみませんか?