RPGツクールMV

RPGツクールMVのプラグインで一覧から項目を選択するウィンドウを作る

RPGツクールMVのWindow_Selectableクラスを使うと、項目を選択可能なウィンドウを作ることができます。

この記事ではサンプルとしてアクターをお金で雇えるプラグインEmployActor.jsを作りつつ、Window_Selectableの主要なメソッドを紹介します。

このブログの記事は厳密な正確さよりも、わかりやすさを重視して書いてあるので、あらかじめご了承ください。

EmployActor.jsの仕様をザックリまとめておきます。

  • アクターのメモ欄に<EASalary:>タグで賃金を設定する
  • プラグインコマンドopenでアクターの一覧、所持金ウィンドウを開く
  • 雇いたいアクターにカーソルをあわせて決定ボタンを押すと「雇う」コマンドを表示する
  • 雇うコマンドで決定ボタンを押すと、所持金が減って選択したアクターが仲間に加わる
  • お金が足りない場合とパーティ人数がいっぱいの場合は、アクターの一覧をグレーアウトする

完成イメージとしては、こんな感じ。
Window_Selectableで項目を選択可能なウィンドウを作る 完成イメージ

必要なものはシーン、一覧ウィンドウ、所持金ウィンドウ、コマンドウィンドウの4つです。

シーンはScene_MenuBaseを元にしてScene_EmployActorを作っていきます。

所持金を表示するウィンドウはWindow_Goldというクラスがあるので、それをそのまま使います。

アクターの一覧をWindow_Selectableを元にしたWindow_EmployActorIndexクラス、コマンドウィンドウをWindow_Commandを元にしたWindow_EmployActorCommandクラスで作ります。

EmployActor.jsのクラスまとめ
シーン・ウィンドウ クラス名
シーン Scene_EmployActor
(Scene_MenuBaseをベースに作成)
一覧ウィンドウ Window_EmployActorIndex
(Window_Selectableをベースに作成)
所持金ウィンドウ Window_Gold
コマンドウィンドウ Window_EmployActorCommand
(Window_Commandをベースに作成)

ウィンドウ作成とボタンを押した時の処理を定義する

まずはScene_EmployActorにウィンドウの生成処理を作り、ボタンを押した時に呼び出す処理を定義していきます。

サンプルコード1

ウィンドウを3つも作ったからコードが長いですが、やっていることは単純です。

プラグインコマンドの定義では、「EmployActor open」とプラグインコマンドを入力したらSceneManagerにScene_EmployActorをpushし、シーンを呼び出すようにしています。

Scene_EmployActorではウィンドウごとにcreate〇〇Windowメソッドを作り、 create メソッドから呼び出しています。

SceneManagerにpushした時にシーンのcreateメソッドが呼び出され、ウィンドウが生成されます。

雇うボタンは最初は見えている必要はないのでコマンドウィンドウは最初は非表示にしておき、一覧ボタンで決定ボタンが押されたら表示するようにします。

ウィンドウ生成処理の中で、一覧ウィンドウとコマンドウィンドウはキーが押されたときに呼び出される処理を setHandler で定義しています。

各ボタンの処理は、アクティブなウィンドウを切り替えるのが主な内容です。

ウィンドウ表示・非表示はメソッド化しておけば、コードを何回も書かなくてすみます。

それぞれ activateIndexWindowactivateCommandWindowhideCommandWindowというメソッドを作りました。

アクター一覧ウィンドウ(indexWindow)のボタン処理

アクター一覧ウィンドウでは決定ボタンが押されたら onIndexOk、キャンセルボタンが押されたら onIndexCancelを呼び出します。

onIndexOkでは activateCommandWindowを呼び出し、コマンドウィンドウを表示してアクティブにします。

onIndexCancelでは popSceneメソッドを呼び出してシーンを終了します。

コマンドウィンドウ(commandWindow)のボタン処理

コマンドウィンドウでは雇うボタンが押されたら onCommandEmploy、キャンセルボタンが押されたら onCommandCancelを呼び出します。

onCommandEmployでは雇うボタンを非表示にして employメソッドを呼び出します。

employメソッドの内容はあとで考えるのでメソッド名だけ先に定義し、 // あとで書く というコメントを書いてあります。

employメソッドを呼び出したあとに activateIndexWindowを呼び出して、一覧ウィンドウをアクティブにします。

onCommandCancelでは hideCommandWindowでコマンドボタンを非表示にして、一覧ウィンドウをアクティブにします。

ウィンドウの定義

ウィンドウの定義は一覧ウィンドウはあとでいろいろつけたしていきますが、とりあえずクラスの定義とinitializeメソッドの中で refreshメソッドの呼び出しをするようにしています。

refreshメソッドは、ウィンドウの内容を再描画するメソッドです。

コマンドウィンドウの定義では、雇うコマンドをemployというシンボルで追加しています。

実行してみると、ウィンドウが表示されます。
Window_Selectableで項目を選択可能なウィンドウを作る プラグインコマンド

Window_Selectableで項目を選択可能なウィンドウを作る ウィンドウの表示

一覧ウィンドウにはまだ内容が表示されませんが、決定ボタンを押すと雇うボタンが表示されます。
(employメソッドの処理をまだ書いていないので、ボタンを押してもなにも起こりません)

雇うボタンが出た状態でキャンセルボタンを押すと雇うボタンが消え、カーソルが一覧ウィンドウに戻ります。

その状態で再度キャンセルボタンを押すと、ウィンドウが閉じます。

一覧ウィンドウに項目を表示する

アクターの一覧を取得する

一覧ウィンドウに表示する内容は、Window_EmployActorIndexの配列に入れておきます。

表示したいのはアクターの一覧なので、アクターオブジェクトの入った配列を作ります。

サンプルコード2-1

長くなるのでWindow_EmployActorIndexのところだけ抜粋しています。

追加した部分は黄色でハイライトしています。

refreshメソッドの中でウィンドウの内容の消去、アクター一覧の作成、項目を書きだす処理を呼び出しています。

アクター一覧の作成は makeActorListというメソッドを作りました。

ウィンドウの内容の消去( createContents)、項目を書きだす処理( drawAllItems)はWindow_Selectableが持っているメソッドをそのまま使います。

データベースで定義されたアクターは、グローバル変数 $dataActors で取得できます。

Javascriptではふつう、配列のインデックス0番からデータが入っていることが多いのですが、$dataActors のインデックス0番はnullという特殊な値が入っているため、インデックス1番からループしています。

アクターごとにEASalaryというノートタグがあるか、パーティに入っているかを判定し、「EASalaryというタグがあり、パーティに入っていないアクター」を配列に追加しています。

タグがあるかと、パーティに入っているかはそれぞれ hasTagisJoinedPartyという個別の関数を作って判定しています。

パーティに入っているキャラクターは $gameParty._actors で取得できます。

$gameParty._actorsはアクターIDが入った配列なので、 $dataActorsのアクターIDと比較し、一致すればパーティに入っているとみなします。

一覧ウィンドウにデータを表示する

アクターの配列ができたら、つぎはウィンドウに表示する処理を作ります。

refreshメソッドの中でWindow_Selectableの drawAllItemsメソッドを呼び出しています。

このメソッドは、インデックス番号を渡して drawItemメソッドを呼び出します。

Window_EmployActorIndexに drawItemメソッドを定義しておけば、それが呼び出されるので作っていきます。

サンプルコード2-2

ウィンドウの列数を設定する

Windows_Selectableでは、1行に複数の項目を並べて表示できます。

1行の項目数(列数)は maxColsプロパティで指定できます。

デフォルトは3ですが、このプラグインでは1行に1人ずつ表示したいため、maxColsを1としています。

アイテム数(項目数)を設定する

その下の maxItemsは一覧に表示する項目の数です。

Window_Selectableの drawAllItemsでは、インデックスがmaxItemsより小さい場合に drawItemを呼び出します。

maxItemsを定義していない場合は0になるので、データを配列に入れていても、maxItemsを定義しないかぎりdrawItemメソッドが呼び出されません。

ウィンドウには配列の内容をぜんぶ表示したいので、 maxItemsは配列の要素数になります。

そこで、 return this._list ? this._list.length : 0; としています。

単純に return this._list.length としないのは、makeActorListメソッドが呼び出されるまではthis._listがundefinedという値になっているので、lengthプロパティを取得しようとするとエラーになるからです。

条件式 ? 1: 2 というのは三項演算子という書き方で、条件式がtrueならば値1、falseならば値2になります。

配列のデータを一覧ウィンドウに表示する

実際にデータをウィンドウに書きだすのは drawItemメソッドです。

drawAllItemsメソッドからインデックス番号が渡されるので、配列のindex番めの値を取得します。

配列の中身はアクターオブジェクトなので、 アクターオブジェクト.meta[タグ名] でノートタグの内容も取得できます。

賃金は通貨単位とあわせて表示するので、数値に変換はせず、文字列のまま扱っています。

通貨単位は TextManager.currencyUnit で取得します。

テキストを表示するのは drawTextメソッドです。
drawText(表示する文字, X座標, Y座標, 行幅, 配置);

配置は右揃えとか中央揃えとかです。(省略可)

指定する場合は、’right’や’center’とか英語で指定します。

X座標とY座標は、 itemRect(index) で項目の領域が取得できるので、そのまま使っています。

ここらへんは他の人のコードを参考に作っているので、よくわかってなかったり。

賃金はアクター名より右側に表示したいので、X座標を+130しています。

また、右揃えにすることで賃金の桁数が違っても通貨単位の位置が揃うようにしています。

データベースのアクターのメモ欄に、<EASalary:>を設定してから呼び出してみます。

テレーゼに<EASalary:100> 、マーシャに<EASalary:200>、ルキウスに<EASalary:150>を設定してみました。
Window_Selectableで項目を選択可能なウィンドウを作る テスト用データ作成

テストプレイすると、こんな感じで表示されます。
Window_Selectableで項目を選択可能なウィンドウを作る 項目をウィンドウに表示

行の有効・無効を切り替える

アクターの一覧を表示するところまではできましたが、所持金が0Gなのにアクター名が白色で表示されています。

しかも、決定ボタンを押すと雇うボタンも押せます。

所持金が足りない場合と、パーティ人数がいっぱいの時は決定ボタンを押しても選択できないようにします。

一覧ウィンドウから所持金を取得できるようにする

所持金の額は、Window_Goldのvalueから取得できます。

しかし、Window_GoldはScene_EmployActorで生成しているため、Window_EmployActorIndexからはWindow_Goldのvalueが取得できません。

そこでScene_EmployActorからWindow_EmployActorIndexに所持金額を渡せるように、メソッドを追加します。

サンプルコード3-1

Window_EmployActorIndexに setMoneyという所持金を設定するメソッドを追加しました。

Scene_EmployActorの activateIndexWindowメソッドの中でsetMoneyを呼び出し、所持金を渡しています。

パーティの持っている所持金は $gameParty._gold でも取得できるので回りくどい気がしますが、ショップで買う時の内部処理(Window_ShopBuy)がこういう処理をしていたので、いちおう合わせました。

パーティの最大人数を定義する

パーティ人数がいっぱいの時を判定できるように、パーティの最大人数を定義します。

パーティの最大人数はデフォルトだと4人ですが、プラグインでパーティの最大人数を増やしている人もいるのでパラメータで設定できるようにします。

ついでにほかのプラグインの説明も書いておきます。

サンプルコード3-2

お金が足りない時とパーティがいっぱいの時は選択できないようにする

これで所持金とパーティの最大人数が取得できるようになったので、行の有効・無効を判定できます。

行の有効・無効を切り替えるには、 isCurrentItemEnabledメソッドを使います。

サンプルコード3-3

isCurrentItemEnabledがtrueの時には決定ボタンで選択可能になります。

falseの時は決定ボタンを押すとブブーッという効果音が鳴り、決定ボタンを押した時の処理が呼ばれなくなります。

お金が足りるかとパーティの最大人数未満かを判定する isEnabledメソッドを作り、戻り値をisCurrentItemEnabledで使っています。

選択中のアクターはこれから雇うコマンドを作る時にも取得したいので、 selectedItemメソッドを作って取得できるようにしました。

項目を選択できない時に文字をグレーアウトする

isCurrentItemEnabledは項目を押せなくなるだけで、文字色までは変わりません。

文字をグレーアウトするには changePaintOpacityメソッドを使います。

trueの時には通常の白い文字、falseの時には文字の不透明度が下がりグレーになります。

ついでに、 meta['EASalary'] と書いているところが多いので、ノートタグ名を変数にしておきます。

ノートタグの名前を変えたくなった時に、1か所なおすだけですみます。

サンプルコード3-4

コード中略(省略部分は変更なし)

文字色がグレーになって押せなくなりました。
Window_Selectableで項目を選択可能なウィンドウを作る 押せない項目をグレーアウト

お金が手に入るイベントを別につくり、ゴールドを増やしてから開くとキチンと選択できるようになります。

あとは雇うコマンドの内容を作っていきます。

コマンドボタンを押した時の処理を作る

最初にScene_EmployActorを定義したときにemployメソッドも名前だけ定義して // あとで書く とコメントを書いておいたので、そこに処理を書いています。

一覧で選択したアイテムはWindow_EmployActorIndexの selectedItemから取得できるようにしたので、選択されたアクターを取得します。

ノートタグから賃金を取得し、 $gameParty.loseGold でお金を減らして $gameParty.addActor でアクターをパーティに追加するだけです。

デバッグと細かい修正

プラグインの挙動に問題がないか、チェックします。

ゴールドを増やすイベントを設置し、ウィンドウを開いてみます。

ちゃんと選択できますね。
Window_Selectableで項目を選択可能なウィンドウを作る お金があるとボタンを押せることを確認

雇うと雇った人はリストから消え、金額の足りなくなった人はグレーアウトされます。
Window_Selectableで項目を選択可能なウィンドウを作る 雇うコマンド実行後

データが変わってもウィンドウをrefreshしないとウィンドウの表示は更新されないので、Scene_EmployActorの activateIndexWindowメソッドの中でWindow_EmployActorIndexをrefreshし、employメソッドの最後で呼び出すことでカーソルを一覧に戻しつつ、データを更新しているところがポイントです。

おおむねいい感じですが、項目の最後の人を選択すると空白行が残ってしまいました。
Window_Selectableで項目を選択可能なウィンドウを作る 最後の人を雇うとカーソルが空白行に残ってしまう

最後にカーソルをあわせた位置は、 lastIndexプロパティに入っています。

しかしlastIndexの値はウィンドウをrefreshして項目が減った場合でも変わらないため、データがない行が選択されてしまいます。

refreshメソッドの処理を追加して、カーソル位置を調整します。

一覧のn番めの人を選択する(カーソルをうつす)には selectメソッドを使います。

指定したインデックス番号の項目にカーソルが移動します。

インデックス番号は0から始まります。

ウィンドウ描画時にlastIndexをの値がアクターの配列の要素数-1より大きかったら、lastIndexに配列の要素数-1を代入します。

lastIndexが3で一覧に表示されるアクターが2人だったらインデックス1番(リストの2番めの人)にカーソルが移ります。

Window_Selectableを使ったサンプルコード(最終版)

今回はWindow_Selectableの使い方を紹介するのが目的なので、機能は必要最低限にしています。

実際にゲームに使う場合は、画面の空いているところに選択しているアクターのステータスを表示させたり、雇うたびに好感度があがっていって賃金が安くなるみたいなシステムを組み込んでもよいかと思います。

COMMENT

メールアドレスが公開されることはありません。

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください