RPGツクールMVで独自のウィンドウを作成するためのメモ
RPGツクールMVでプラグインで拡張しようとなると、独自のウィンドウを作成していく必要が出てくる。
この記事ではWindowの特徴についてまとめていく。
今回の記事では以下の組み込みクラスについて紹介していく。
Window_Base
Window_Selectable
Window_Command
Window_Base クラス
さて、独自のWindowクラスを自作するには、まずはWindow_Base
クラスを継承したクラスを作ることを検討していくとよい。
Window_Base
は名前の通り、ウィンドウを作成するのにベースとなるクラス。
ツクールMVでは様々なウィンドウの元となるクラスを用意してくれているが、全ての大元となるクラスといえる。
例えばWindow_ShopDetails
というウィンドウを作成したい場合は以下のようにする。
Window_Base
を継承して、initialize
メソッドを作成する。
引数のx
とy
はウィンドウの表示の開始位置、width
とheight
はウィンドウの大きさを示している。
そして、描画のためにrefresh
メソッドを用意してあげる。
これはinitialize
メソッドで自力で呼んであげる必要があるが、ツクールMVの都合で何かしらと再描画しないと
行けなくなったときに、refresh
メソッドが自動で呼ばれる。
function Window_ShopDetails() {
this.initialize.apply(this, arguments);
}
Window_ShopDetails.prototype = Object.create(Window_Base.prototype);
Window_ShopDetails.prototype.constructor = Window_ShopDetails;
// x, y ウィンドウの開始位置 width, height ウィンドウの大きさ
Window_ShopDetails.prototype.initialize = function (x, y, width, height) {
Window_Base.prototype.initialize.call(this, x, y, width, height);
this._item = null;
this.refresh();
};
Window_ShopDetails.prototype.setItem = function (item) {
if (this._item !== item) {
this._item = item;
this.refresh();
}
};
Window_ShopDetails.prototype.refresh = function () {
this.contents.clear();
if (this._item) {
// アイテム画像の表示(アイコンとして)
var iconY = 20;
var iconSize = 96; // 大きめのアイコン
var iconBoxWidth = iconSize + 4;
var iconBoxHeight = iconSize + 4;
this.drawIcon(this._item.iconIndex, (this.width - iconBoxWidth) / 2, iconY, iconSize);
// アイテム名
this.drawText(this._item.name, 0, iconY + iconBoxHeight + 20, this.contents.width, 'center');
// アイテムの説明
var descY = iconY + iconBoxHeight + 60;
this.drawTextEx(this._item.description, 10, descY);
// 追加情報(効果など)
var effectY = descY + this.lineHeight() * 3;
if (this._item.effects) {
this._item.effects.forEach(function (effect) {
if (effect.code === Game_Action.EFFECT_RECOVER_HP) {
this.drawText("HP回復: " + effect.value1 * 100 + "%", 10, effectY);
effectY += this.lineHeight();
}
// 他の効果の表示も追加可能
}, this);
}
}
};
Windowの描画のために覚えておいたほうがよいメソッドは以下の通り。
// Windowの中身をすべて削除する
this.contents.clear();
// テキストを描画する
this.drawText(name, x, y, width, height);
// テキストの色を変える
this.changeTextColor(this.systemColor());
// テキストの色をもとに戻す
this.resetTextColor();
// ラインの高さを取得する。色々とそろえるのに便利
this.lineHeight();
// img/pictures/ にある sample.png を取得する
var bitmap = ImageManager.loadPicture("sample");
// より柔軟に画像を取得したい場合は以下のやり方
var bitmap = Bitmap.load("img/pictures/image1.png");
// 画像を表示する
this.contents.blt(
bitmap,
0, 0, // 元画像の切り取り開始位置
bitmap.width, bitmap.height, // 切り取るサイズ
x, y, // 描画位置
iconSize, iconSize // 描画サイズ
);
Window_Selectable
Window_Selectable
はアイテム一覧などの一覧表示を良い感じにやってくれる。
ここではWindow_ShopItemList
クラスを作成する例を示す。
function Window_ShopItemList() {
this.initialize.apply(this, arguments);
}
Window_ShopItemList.prototype = Object.create(Window_Selectable.prototype);
Window_ShopItemList.prototype.constructor = Window_ShopItemList;
// 例として、this._goodsプロパティを作成して、ここに一覧にしたいデータを格納していく。
// ここはthis._goodsという名前でなくてもよい。
Window_ShopItemList.prototype.initialize = function (x, y, width, height) {
Window_Selectable.prototype.initialize.call(this, x, y, width, height);
this._goods = [];
this._hoverHandler = null;
this.refresh();
};
Window_ShopItemList.prototype.setGoods = function (goods) {
this._goods = goods;
this.refresh();
};
そして、重要なのがdrawItem
メソッドとmaxItems
メソッドを定義してあげることだ。
drawItem
メソッドは一覧の各アイテムを描画するときに呼ばれるメソッドで、
maxItems
メソッドは一覧のアイテムの総数を表すメソッドだ。
Window_ShopItemList.prototype.maxItems = function () {
return this._goods.length;
};
Window_ShopItemList.prototype.drawItem = function (index) {
var item = this._goods[index];
var rect = this.itemRect(index);
var priceWidth = 96;
rect.width -= priceWidth;
this.drawItemName(item, rect.x, rect.y, rect.width);
this.drawText(item.price + ' G', rect.x + rect.width, rect.y, priceWidth, 'right');
};
処理の中でthis.itemRect(index)
が使われているが、これは現在描画中のアイテムの部分のx, y, width, height
の情報を格納してくれているRectangle
クラスを返してくれる。
また、アイテムを選択した時やキャンセルボタン(右クリック)を押したときの挙動を設定したい場合は、
this.sethandler("ok", function)
やthis.sethandler("cancel", function)
を使って設定できる。
setHandler
に鑑定はWindow_Selectable
クラスの中で設定するよりも、そのWindowクラスを使っている
Sceneクラス内で設定するのが良いだろう。
雰囲気としては以下の感じのコードになる。
Scene_CustomShop.prototype.createItemListWindow = function () {
var wx = Graphics.boxWidth / 2;
var wy = 0;
var ww = Graphics.boxWidth / 2;
var wh = Graphics.boxHeight - this._goldWindow.height;
this._itemListWindow = new Window_ShopItemList(wx, wy, ww, wh);
this._itemListWindow.setGoods(this._goods);
this._itemListWindow.setHandler('ok', this.onBuyClick.bind(this));
this._itemListWindow.setHandler('cancel', this.popScene.bind(this));
this._itemListWindow.setHoverHandler(this.onItemHover.bind(this));
this.addWindow(this._itemListWindow);
};
Scene_CustomShop.prototype.onBuyClick = function () {
this._buyWindow.show();
this._buyWindow.select(0);
this._buyWindow.activate();
};
また、Window_Selectable
でどのアイテムが選択されているかを他のクラスから取得したい場合がある。
その時はindex
メソッドを使うとよい。
const index = this._itemListWindow.index();
実際にはindex番号よりも、選択されているアイテムのオブジェクトが欲しいことが多いので、以下のようなメソッドを作成 しておくと便利。
Window_ShopItemList.prototype.getItem = function () {
return this._goods[this.index()];
};
Window_Command
コマンドに特化したWindowクラス。先ほど紹介したWindow_Selectable
を継承している。
Window_SimpleCommand
を例にして解説する。使い方は簡単で、makeCommandList
メソッドを
ユーザーから定義してあげればよい。
makeCommandList
メソッドには、this.addCommand("はじめる", "start");
のように
コマンドを定義してあげるとよい。
addCommand
の第1引数は、表示するコマンド名で、第1引数はシンボル名だ。
// 1. 基本的なコマンドウィンドウの作成
function Window_SimpleCommand() {
this.initialize.apply(this, arguments);
}
Window_SimpleCommand.prototype = Object.create(Window_Command.prototype);
Window_SimpleCommand.prototype.constructor = Window_SimpleCommand;
// 初期化
Window_SimpleCommand.prototype.initialize = function(x, y) {
Window_Command.prototype.initialize.call(this, x, y);
};
// コマンドリストの作成
Window_SimpleCommand.prototype.makeCommandList = function() {
// コマンドの追加
this.addCommand("はじめる", "start"); // 表示名, コマンドID
this.addCommand("設定", "options");
this.addCommand("終了", "exit");
};
そして、Window_SimpleCommand
を使うシーンにおいて、先ほどと同じようにthis._commandWindow.setHandler
などの
ようにしてあげるとよい。
例えば、Scene_SimpleMenu
クラスと作ったとすると、以下のような感じで定義してあげる。
function Scene_SimpleMenu() {
this.initialize.apply(this, arguments);
}
Scene_SimpleMenu.prototype = Object.create(Scene_MenuBase.prototype);
Scene_SimpleMenu.prototype.constructor = Scene_SimpleMenu;
Scene_SimpleMenu.prototype.initialize = function() {
Scene_MenuBase.prototype.initialize.call(this);
};
Scene_SimpleMenu.prototype.create = function() {
Scene_MenuBase.prototype.create.call(this);
this.createCommandWindow();
};
/**
* ここでsetHandlerの登録をする。
*
*/
Scene_SimpleMenu.prototype.createCommandWindow = function() {
// コマンドウィンドウの作成(中央に配置)
var x = (Graphics.boxWidth - 240) / 2;
var y = (Graphics.boxHeight - 200) / 2;
this._commandWindow = new Window_SimpleCommand(x, y);
// コマンドが選択されたときの処理を設定
this._commandWindow.setHandler('start', this.commandStart.bind(this));
this._commandWindow.setHandler('options', this.commandOptions.bind(this));
this._commandWindow.setHandler('exit', this.commandExit.bind(this));
this.addWindow(this._commandWindow);
};