独自ウィンドウを作成するためのプラグインを作る方法を紹介する第二段。前回は単一の様々な独自ウィンドウを表示するサンプルを紹介した。今回は複数のウィンドウを同時に表示し、各ウィンドウからウィンドウへの遷移、ウィンドウシーンから別ウィンドウシーンへの遷移の解説を行う。
複数のウィンドウやシーンをまたがるウィンドウの遷移
今回のサンプルはまずコマンドウィンドウ、ハロー表示ウィンドウ、動物一覧ウィンドウの3種類を常に表示するシーンを作成する。ユーザーはコマンドウィンドウで「空」「ハロー」を選択することによりハロー表示ウィンドウの表示文字を空にする、及びHelloと文字表示する切り替えを行う。及びコマンドウィンドウで「アニマル」を選択することでユーザーの操作できる箇所が動物一覧ウィンドウに切り替わる。動物一覧ウィンドウでキャンセルするとコマンドウィンドウに戻る。決定すると動物詳細画面へ遷移、その動物の詳細が表示される。なお、サンプルは簡単にするため動物一覧と表示する項目は同じだ。動物詳細画面でキャンセルすると前の画面に戻りつつ動物一覧の先ほど選択していた動物を選択している状態に戻る。
/*:
* @plugindesc サンプルPlugin
* @target MZ
* @help
* 独自コマンドウィンドウを表示するサンプル
*
* @command openScene
* @text シーン開始
* @desc サンプルシーンの開始。
*
*/
(() => {
const pluginName = document.currentScript.src.match(/^.*\/(.*).js$/)[1];
//動物の配列
const animal = ['あひる','ひよこ','犬','猫','ねずみ','牛','羊','豚','ライオン','いのしし'];
var windowFlg = -1; //-1:画面を開く 0以降:animalの番号
// Plugin Command
PluginManager.registerCommand(pluginName, "openScene", () => {
SceneManager.push(Scene_SampleMenu);
});
//サンプルウィンドウを管理するシーン
class Scene_SampleMenu extends Scene_MenuBase {
create() {
super.create();
this.createWindowLayer();
const rect = new Rectangle(10, 100, 200, 200);
this._commandWindow = new Window_CommandSample(rect);
//ウィンドウフラグによるアクティブウィンドウの制御
if (windowFlg == -1)
{
this._commandWindow.activate();
} else {
this._commandWindow.smoothSelect(2);
this._commandWindow.deactivate();
}
//コマンドウィンドウ
this._commandWindow.setHandler("cancel", this.popScene.bind(this));
this._commandWindow.setHandler("kara", this.OutputKara.bind(this));
this._commandWindow.setHandler("hello", this.OutputHello.bind(this));
this._commandWindow.setHandler("animalList", this.gotoAnimal.bind(this));
this._commandWindow.setHandler("back", this.popScene.bind(this));
this.addWindow(this._commandWindow);
//ハロー表示ウィンドウ
const rect2 = new Rectangle(250, 100, 100, 200);
this._helloWindow = new Window_Hello(rect2);
this.addWindow(this._helloWindow);
//アニマルリスト表示ウィンドウ
const rect3 = new Rectangle(400, 100, 400, 200);
this._animalWindow = new Window_AnimalList(rect3);
this._animalWindow.setHandler("ok", this.MoveAnimalStatus.bind(this));
this._animalWindow.setHandler("cancel", this.cancelAnimalWindow.bind(this));
if (windowFlg != -1)
{
this._animalWindow.smoothSelect(windowFlg || 0);
this._animalWindow.activate();
} else {
this._animalWindow.deactivate();
}
this.addWindow(this._animalWindow);
}
//ハローウィンドウを空にする。
OutputKara() {
this._helloWindow.contents.clear();
this._helloWindow.refresh('');
this._commandWindow.activate();
}
//ハローウィンドウにHelloと表示する。
OutputHello() {
this._helloWindow.contents.clear();
this._helloWindow.refresh('Hello World');
this._commandWindow.activate();
}
//動物リストウィンドウに移動
gotoAnimal() {
//コマンドウィンドウをデアクティベート
this._commandWindow.deactivate();
//1番目のアクターを選択状態にする
//アクターウィンドウをアクティベート
this._animalWindow.activate();
this._animalWindow.smoothSelect(0);
}
//動物詳細画面に移動
MoveAnimalStatus() {
SceneManager.push(Scene_AnimalStatus);
}
//動物一覧ウィンドウからコマンドウィンドウへ遷移
cancelAnimalWindow() {
this._animalWindow.deactivate();
this._commandWindow.activate();
}
}
//コマンドウィンドウ
class Window_CommandSample extends Window_Command {
makeCommandList(){
this.addCommand("空", "kara");
this.addCommand("ハロー", "hello");
this.addCommand("アニマル", "animalList");
this.addCommand("戻る", "back");
}
}
//ハロー表示ウィンドウ
class Window_Hello extends Window_Base {
initialize(rect) {
super.initialize(rect);
this.refresh('')
}
refresh(str) {
this.drawText(str, 10, 50 + this.lineHeight() * 0, 200);
}
}
//動物一覧ウィンドウ
class Window_AnimalList extends Window_Selectable {
initialize(rect) {
super.initialize(rect);
this.refresh();
}
//1行の高さ
itemHeight() {
return 80;
}
maxItems() {
//動物一覧を全て表示するため動物配列数をセット
return animal.length;
}
drawItem(index) {
//動物の一覧を表示
const rect = this.itemLineRect(index);
const numberWidth = this.textWidth("0000000");
this.drawText(index, rect.x, -15 + rect.y + this.lineHeight() * 0, numberWidth);
this.drawText(animal[index], rect.x, -15 + rect.y + this.lineHeight() * 1, numberWidth);
}
isCurrentItemEnabled()
{
return true;
}
//ユーザーが項目を実行した時はウィンドウフラグに動物IDを入れる。
processOk() {
super.processOk();
windowFlg = this.index();
}
//キャンセル(コマンドウィンドウに戻る)時はフラグを-1(初期化)する
processCancel() {
super.processCancel();
windowFlg = -1;
}
}
//動物ステータス詳細画面シーン
class Scene_AnimalStatus extends Scene_MenuBase {
create() {
super.create();
this.createWindowLayer();
const rect = new Rectangle(200, 100, 400, 200);
this._animalStatusWindow = new Window_AnimalStatus(rect);
this._animalStatusWindow.activate();
this._animalStatusWindow.setHandler("cancel", this.popScene.bind(this));
this.addWindow(this._animalStatusWindow);
}
}
//動物ステータス詳細画面
class Window_AnimalStatus extends Window_Selectable {
initialize(rect) {
super.initialize(rect);
this.refresh()
}
refresh() {
//テキスト出力時はwindowFlgを使ってどの動物が対象か判定する。
this.contents.clear();
this.drawText("アニマルステータス", 10, 50 + this.lineHeight() * 0, 200);
this.drawText(windowFlg, 10, 50 + this.lineHeight() * 1, 200);
this.drawText(animal[windowFlg], 10, 50 + this.lineHeight() * 2, 200);
}
}
})();
まず4つのウィンドウ、「コマンドウィンドウ」、「ハローウィンドウ」、「動物一覧ウィンドウ」、「動物詳細ウィンドウ」クラスを作成。次に「サンプルシーン」「動物一覧シーン」クラスを作成。
「サンプルシーン」クラスで「コマンドウィンドウ」、「ハローウィンドウ」、「動物一覧ウィンドウ」のインスタンスを作成、「動物一覧シーン」クラスで「動物詳細ウィンドウ」のインスタンスを作成している。ウィンドウの注意点としてはハローウィンドウがWindow_Baseを継承している点だ。前回のサンプルでは単一ウィンドウでWindow_Selectableを継承していたが、今回プレイヤーがハローウィンドウを触ることが無いため、継承先が変わった。ちなみにWindow_Selectableのままでも問題は無いので、慣れるまでは継承元を統一した方がよいかもしれない。
コマンドウィンドウによるハローウィンドウの制御
「空」、「ハロー」項目を押下した時の処理。コマンド項目のバインド定義をしたメソッドでハローウィンドウの表示処理を行えばよい。別のウィンドウを操作した場合フォーカスがズレてしまうことがあるため、再アクティベートが必要な点は注意。
this._commandWindow.setHandler("kara", this.OutputKara.bind(this));
this._commandWindow.setHandler("hello", this.OutputHello.bind(this));
....
//ハローウィンドウを空にする。
OutputKara() {
this._helloWindow.contents.clear();
this._helloWindow.refresh('');
this._commandWindow.activate();
}
//ハローウィンドウにHelloと表示する。
OutputHello() {
this._helloWindow.contents.clear();
this._helloWindow.refresh('Hello World');
this._commandWindow.activate();
}
コマンドウィンドウと動物一覧ウィンドウのアクティブ移動
「アニマル」項目を押下した時の処理。プレイヤーが操作するウィンドウ(アクティブウィンドウ)を変更する場合、元ウィンドウを非アクティブ化した上で、次ウィンドウをアクティブ化する必要がある。それぞれ、deactivate()、activate()メソッドで可能だ。
さらに動物一覧ウィンドウは一覧表示しているため複数の項目がある。smoothSelect(項目番号)メソッドを使用することでその番号の項目にフォーカスをセットしてくれる。番号は上から順に0,1,2…となる。
動物一覧からキャンセルでコマンドウィンドウに戻る場合もそれぞれ同様にdeactivate()、activate()メソッドを実行している。
this._commandWindow.setHandler("animalList", this.gotoAnimal.bind(this));
this._animalWindow.setHandler("cancel", this.cancelAnimalWindow.bind(this));
....
//動物一覧ウィンドウに移動
gotoAnimal() {
//コマンドウィンドウをデアクティベート
this._commandWindow.deactivate();
//1番目のアクターを選択状態にする
//アクターウィンドウをアクティベート
this._animalWindow.activate();
this._animalWindow.smoothSelect(0);
}
//動物一覧ウィンドウからコマンドウィンドウへ遷移
cancelAnimalWindow() {
this._animalWindow.deactivate();
this._commandWindow.activate();
}
サンプル画面と動物詳細画面の切り替え
動物一覧ウィンドウから項目を決定すると動物詳細画面へ遷移する。遷移はSceneManager.pushで行う。gotoだとこの画面に戻れないためだ。この時、大事なのが項目を決定した後にwindowFlgに項目のindexを代入することだ。具体的には欲しいのは項目のindexではなく動物配列の、その動物が代入されている位置だ。今回の場合はたまたまindexと位置が同じなのでindexを代入している。
シーンの移動時に保持しておきたい値は、コアスクリプトの場合シングルトンのクラスに代入される。プラグインの場合は同様のクラスを利用されてもらうかグローバル変数を定義する。今回はwindowFlgという変数を定義して利用した。
this.drawText以下は動物詳細画面で受け取ったwindowFlgを使ったサンプルだ。
this._animalWindow.setHandler("ok", this.MoveAnimalStatus.bind(this));
......
//動物詳細画面に移動
MoveAnimalStatus() {
SceneManager.push(Scene_AnimalStatus);
}
......
//ユーザーが項目を実行した時はウィンドウフラグに動物IDを入れる。
processOk() {
super.processOk();
windowFlg = this.index();
}
......
this.drawText(animal[windowFlg], 10, 50 + this.lineHeight() * 2, 200);
次は動物詳細画面から元のサンプル画面に戻った時の処理だ。この時サンプル画面は初めて呼ばれたのか、それとも動物詳細画面から戻ってきたのか判定し、初めて呼ばれた場合はコマンドウィンドウをアクティブに、戻ってきた場合は動物一覧ウィンドウにアクティブにする必要がある。加えて、動物一覧では動物詳細で見ていた動物を選択状態に、さらにキャンセルで戻った後はコマンドウィンドウのアニマルを選択状態にする必要がある。
判定方法はwindowFlgを使う。初期値を-1にしており、動物一覧画面に遷移している場合のみ動物IDが入っている。-1かどうかで初期か戻ってきたかを判定する。シーン開始時に、windowFlgを確認し、アクティブ状態や項目の選択状態を適宜変更する。
this._commandWindow.smoothSelect(2)は、コマンドウィンドウの3番目、アニマルを選択状態にしている。this._animalWindow.smoothSelect(windowFlg || 0);は動物一覧ウィンドウで詳細と同じ項目を選択状態にしている。
なお、戻ってきた後、判定箇所の処理を全て終えた後はwindowFlgを-1に戻す。windowFlgがそのままだと、一度メニューを閉じた後に再度開いた時に戻ってきた場合と同じ処理が走ってしまう。
//ウィンドウフラグによるアクティブウィンドウの制御
if (windowFlg == -1)
{
this._commandWindow.activate();
} else {
this._commandWindow.smoothSelect(2);
this._commandWindow.deactivate();
}
if (windowFlg != -1)
{
this._animalWindow.smoothSelect(windowFlg || 0);
this._animalWindow.activate();
windowFlg = -1;
} else {
this._animalWindow.deactivate();
}
関連リンク
当サイトのRPGツクールMZプラグイン開発のトップページ。他の記事へのリンクをまとめている。