見出し画像

RPGツクールプラグイン制作過程紹介 第13回

昨年から始めた本シリーズですが、いつの間にかもう2022年ですね。できれば今年度中に完結させたいと思っているので、もうしばらくの間お付き合いいただければと思います。

前回はマップ上に表示したスキルリストウィンドウにスキル一覧を表示させるところまで進めました。今回は、そのスキルがアクターやスキルタイプに応じて変更されるようにしていきたいと思います。

現状の確認

まずは前回のおさらいもかねて、現在どのような動作をするのかを確認してみましょう。

ご覧の通りスキルリストウィンドウ内の項目は何も選択できません。ただ、普通に歩き回ったりメニューを開いたりすることはできます。つまりこのウィンドウは今のところ何の動作もしない、ただの「ハリボテ」ということです。とりあえず、ものすごく「ジャマ」ではありますね……。
また前回は暫定措置としてケイシーの魔法を表示させることにしたわけですが、このままではそれ以外のスキルを表示させることもできません。

というわけで今回はこのウィンドウをきちんと機能させることを目標にしたいと思います。

コードの改良

現状ではご覧のように機能していないスキルリストウィンドウですが、そもそもこのウィンドウが使用されているScene_Skillスキル使用シーンではどのように使われていたでしょうか。

スキル使用シーン(Scene_Skill

スキルリストウィンドウの左上には、スキルを使用するアクターの情報が表示されています。右上には、スキルタイプを選択するウィンドウが表示されています。これによってスキルリストウィンドウに、それらを反映したスキル一覧が表示されるようになっています。
本プラグインには今のところそれらを表示させていませんが、代わりに暫定措置としてアクター6番とスキルタイプ1番という固定値をセットしていましたね。

setActorおよびsetStypeId関数の引数に固定値が指定されている

ですがこのように簡略化して設定しただけではうまく機能しない、ということがわかりました。それならいっそ、変に省略せずにコアスクリプトのScene_Skillを丸ごとコピーしてみてはどうでしょうか。

Scene_Skillのコピー

以前コピーした以下の関数2つですが、暫定措置として途中のコードをコメントアウトしていました。

まずはこれらのコメントアウトを解除して元に戻します。反対に、以前追記した箇所をコメントアウトします。つまりScene_Skillに定義されていた通りの状態に戻す、というわけですね。

下2行をコメントアウト
wywh定数の暫定措置をコメントアウト

ですがこの状態で起動しようとするとエラーになってしまうのでしたね。それを防ぐための暫定措置でした。
createItemWindow関数には、以下のコードがあります。

this._itemWindow.setHelpWindow(this._helpWindow);

this._itemWindowsetHelpWindowという関数をthis._helpWindowという引数で呼び出しているようですが、このthis._helpWindowというのはその名の通りヘルプウィンドウのことです。スキルやアイテムの説明文が表示される、さまざまなシーンで表示されるウィンドウとしてお馴染みだと思います。

Scene_Skillにおけるヘルプウィンドウ

このヘルプウィンドウは元々のScene_Skillでは作成されますが、今のところScene_Mapでは作成していません。ですのでこれはエラーの原因になります。

また、itemWindowRect関数には以下のコードがあります。

const wy = this._statusWindow.y + this._statusWindow.height;

このthis._statusWindowScene_Skillにおけるこのウィンドウです。

アクター情報が表示されているウィンドウ

アクターの顔グラフィックや名前、HPMPなどが表示されているウィンドウですね。こちらもScene_Skillでは作成されますが、今のところScene_Mapにはありません。

最後に、itemWindowRect関数にある以下のコードもエラー原因の一つです。

const wh = this.mainAreaHeight() - this._statusWindow.height;

wh定数に数値を代入しようとしているのですが、mainAreaHeightという関数はScene_Mapには定義されていませんのでエラーになってしまうのです。

なお余談ですが、このように開発途中のプラグインにおいて必要な関数等がまだ定義されていないためにエラーになってしまうことはよくあることです。その状態でゲームを起動する必要がある場合、いったんプラグインをオフにしましょう。

FieldActionをオフに!

ということで、現状のエラーを回避するには以下の3つを用意する必要がありそうです。

  1. _helpWindow(に代入する関数)

  2. _statusWindow(に代入する関数)

  3. mainAreaHeight関数

まずはScene_Skillにおいてこれらがどのように定義されているのかを確認します。上記のcreateItemWindow関数がScene_Skillにおいてどこで呼び出されているのかを見てみましょう。

検索結果からたどり着いたcreateItemWindow関数の呼び出し元

ご覧の通りScene_Skillcreateという関数にて呼び出されているようですが、この関数には他にもcreateHelpWindowcreateSkillTypeWindowcreateStatusWindowなどなど気になる名前をした関数が多数呼び出されています。これらの定義箇所を見てみましょう。

createSkillTypeWindow
createStatusWindow

雰囲気から察するにまさにこれらこそが、今必要としているウィンドウの作成関数に違いありません!
なおcreateHelpWindowScene_Skillを探してみても見つかりません。でしたら検索してみましょう。

createHelpWindowの検索結果

どうやらScene_MenuBaseというクラスに定義されている関数のようです。今参考にしているScene_SkillScene_ItemBaseという、アイテム類の使用に関するシーンクラスのサブクラスである、ということは以前にもご紹介しました。それではScene_ItemBaseのスーパークラスは何なのでしょうか? 確認してみましょう。

Scene_ItemBaseの定義箇所

ご覧の通りScene_ItemBaseのスーパークラスはScene_MenuBaseです。Scene_MenuBaseとは、メニュー画面にて使用されるすべてのシーンクラスのスーパークラスなのです。ヘルプウィンドウはさまざまなメニュー関連シーンに登場するので、それらの共通のスーパークラスに定義した方が都合が良いわけですね。
ただし本プラグインではマップ上にウィンドウを表示させようとしているわけですが、Scene_MapScene_MenuBaseのサブクラスではありません。

Scene_Mapの定義箇所

Scene_MapScene_Messageのサブクラスですが、Scene_MessageのスーパークラスはScene_Baseです。つまりScene_MapのクラスツリーにはScene_MenuBaseがどこにも登場しませんので、Scene_MapからはcreateHelpWindow関数を参照することができません。ですのでこの関数もコピーした上でScene_Mapに定義する必要があるでしょう。

というわけで、まずはScene_Skillcreate関数の内容であるさまざまなウィンドウの作成関数呼び出しをScene_MapcreateAllWindows関数にコピーしてみることにします。

createAllWindows関数に貼り付けた状態

この関数では以前からcreateItemWindowだけは呼び出していましたが、それ以外の関数もすべてScene_Skillcreate関数に合わせました。

ただしこれだけではそれらの関数がScene_Mapにまだ定義されていませんのでエラーになります。ということでそれらもコピーして持ってきます。

rmmz_scene.jsの1670行目から1701行目までをコピー
FieldAction.jsに貼り付けてからクラス名をScene_Mapに置換

ご覧のようにウィンドウ作成関数だけではなく、その関数内で呼び出されるxxWindowRect関数も一緒にコピーして貼り付けています。これはもちろん、それらもセットでないとエラーになってしまうからです。

上記の通りcreateHelpWindow関数もScene_MenuBaseからコピーして貼り付けます。

FieldAction.jsに貼り付けてからクラス名をScene_Mapに置換

ヘルプウィンドウにも他のウィンドウと同様、このウィンドウの座標や寸法を表す矩形(Rectangle)情報をhelpWindowRect関数にて取得しています。こちらもScene_Mapにはない関数なので、忘れずに貼り付けます。

FieldAction.jsに貼り付けてからクラス名をScene_Mapに置換

これで上記1・2のウィンドウ作成関数はそろいました。最後に3のmainAreaHeight関数を用意しましょう。この関数もScene_MenuBaseに定義されています。

Scene_MenuBasemainAreaHeightの定義箇所

注意が必要なのは、mainAreaHeight関数内でさらにhelpAreaHeightという関数が呼び出されています。また、その定義箇所の周囲に似たような名前の関数が多数定義されています。これらの関数は何のためにあるのかというと、ウィンドウの配置場所をUIボタンやヘルプウィンドウの高さなど、他の要素との兼ね合いで計算するために用意されているのです。上記スクリーンショットの関数はいずれも必要になりますので、すべてコピーします。

FieldAction.jsに貼り付けてからクラス名をScene_Mapに置換

テスト・デバッグ

これですべての準備が整ったはずです。早速テストしてみましょう…とその前に、FieldAction.jsを再びオンにするのを忘れずに!

起動すると上記エラーが表示されます。デバッグコンソールにて詳細を確認してみましょう。

createSkillTypeWindow関数内のbindという箇所でエラーになっているようです。

4〜7行目が当該箇所

このbindとは何なのかというと、プレイヤーがあるコマンドを押した際に実行される関数を紐づけるための処理です。以前にもcreateItemWindow内の似たようなコードをコメントアウトしたことがありましたね。この処理は後で組むことにするので、今はコメントアウトしておきます(createItemWindow内の当該箇所も再びコメントアウトします)。

createSkillTypeWindow
createItemWindow

それでは再度テストしてみましょう。

またエラーが出てしまいました! デバッグコンソールを確認しましょう。

createAllWindows関数内のcreateActorWindowは関数ではない」というエラー内容です。当該箇所を確認しましょう。

createAllWindows

これは、createActorWindowという関数が定義されていないために起こるエラーです。このウィンドウもScene_Skillにて作成されるウィンドウなのですが、今回あえてコピーしませんでした。というのも、このウィンドウは本プラグインでは不要であると考えているからです。ではこのウィンドウは何なのでしょうか?

《ヒールⅠ》を選択するとこのウィンドウが表示された

これは、Scene_Skillにおけるスキルの対象アクター選択ウィンドウです。ツクールでは通常、メニュー画面でスキルを選択するとその対象となるアクターの選択ウィンドウが表示されますよね。これがアクターウィンドウであるわけなのですが、ではなぜ本プラグインでは不要なのでしょうか?
それは、本プラグインにおいてマップ画面上でスキルを選択・使用する時は常にプレイヤーの目の前にいるイベントがその対象となる、という前提であるからです。ですのでこのような対象選択ウィンドウは必要ない、ということなのです。

というわけでcreateActorWindow関数の呼び出しは不要ですので削除してしまいます。

createActorWindowを削除

再びテストしてみましょう。

今度こそエラーなく起動できました! ですが以前と同様、ウィンドウ内に何も表示されていません。その原因も以前と同様「アクターが指定されていないから」なのです。
ではScene_Skillではもともと、どのようにしてアクターを取得しているのでしょうか? Scene_Skillの近辺をactorで検索してみましょう。

1662行目は先程削除したcreateActorWindowなので無視して、1667行目に注目してみましょう。このrefreshActorという関数は何やら重要そうな気配がするので、その定義箇所を詳しくみてみます。

refreshActor

以前定義していたsetAcor関数が3つも並んでいます。スキルタイプウィンドウ、ステータスウインドウ、アイテムウィンドウにそれぞれアクターをセットしているようです。ではそのアクターはどこから取得しているのかというと、最初にactorという定数にthis.actor()の戻り値を代入して取得しているようです。このthis.actor()とはScene_Skillに定義されているactorという関数を呼び出しているということなのですが、探してもこの関数は見つかりません。このような場合、上記のcreateHelpWindowのときと同様スーパークラスに定義されていることが多いです。ですのでScene_MenuBase内を探してみます。

rmmz_scenes.jsの1131行目に、Scene_MenuBaseの関数としてactorが定義されています。これがサブクラスであるScene_Skillにも継承されていて、refreshActor関数にて呼び出されていた、ということのようです。
ですのでこちらもrefreshActorともどもコピーしてしまいましょう。その際、その下にあるupdateActorも後々使うことになりそうな気配が漂っているのでついでにコピーしてしまいます。

FieldAction.jsに貼り付けてからクラス名をScene_Mapに置換

この状態ではまだrefreshActorを定義しただけで実際に呼び出してはいませんので、その呼び出し箇所もScene_Skillに準じて設定しましょう。Scene_Skillでは、以下の箇所にてrefreshActorを呼び出しています。

start関数

startというのはScene_Baseに定義されている関数であり、その名の通りシーン開始時に実行される処理です。つまりScene_Skillでは、シーン開始時にrefreshActorを呼び出し、各種ウィンドウにアクターをセットしている、ということのようですね。この処理をScene_Mapにも流用してしまいましょう。というわけでこの関数もコピーします。

FieldAction.jsに貼り付けてからクラス名をScene_Mapに置換

これだけで良さそうに思えますが、実はこのコードには一つ問題があります。それは以下の箇所です。

Scene_ItemBase.prototype.start.call(this);

これは以前にもご紹介したことのある、call関数ですね。Scene_ItemBasestart関数を呼び出しているようですが、つまりScene_Skillのスーパークラスの同名関数を呼び出している、ということなのです。スーパークラスと同様の処理を行なった上でrefreshActorを呼び出す、という処理の順番になっています。そうでないとスーパークラスのstartに定義されている重要な処理が実行されなくなってしまうからですね。
ここでポイントなのは、Scene_ItemBasestartを呼び出しているのはScene_Skillの直接の親クラスがScene_ItemBaseだから、ということです。Scene_Mapの場合、親クラスが違いますのでそのまま使うことはできません。では以下のようにしてはどうでしょうか。

Scene_ItemBaseScene_Messageに変更

Scene_Mapの直接の親クラスはScene_Messageです。ですのでこれで問題なく動作するでしょう。
…と言いたいところですが、実はまだ少し問題があります。start関数はもともとScene_Baseに定義されている関数であると言いましたが、このクラスは全てのシーンクラスのスーパークラスです。もちろんScene_Mapの祖先クラスでもあります。ということは、Scene_Mapにももともとstart関数が定義されている、ということなのです。
このようにもともと定義されている関数に処理を追加したい場合、以前にもご紹介した通り元の関数を定数に逃した上で、その定数を呼び出す、という処理にした方が好ましいのです。
つまり以下のようにします。

_Scene_Map_prototype_startという定数に代入

これは以前にもご紹介した、他プラグインとの競合を避けるためのテクニックですね(以下公式講座の「既存メソッドの再定義」参照)。

これでこの関数は完成です…と言いたいところですが、まだ一つやることがあります。先程Scene_SkillにおけるScene_ItemBaseの箇所をScene_Messageに置き換えたわけですが、実はこの箇所はもはや丸ごと不要なのです。というのも、この処理は元々のScene_Mapstart関数に含まれているからなのです。つまり_Scene_Map_prototype_start.callの箇所にて実行されているわけなので、同じ処理が2回実行されてしまいます。それでは困るので、Scene_Message.prototype.start.call(this)は削除してしまいます。

Scene_Message.prototype.start.call(this)を削除

これでようやく完成です。早速テストしてみましょう。

またエラーですね……。デバッグコンソールを確認しましょう!

startrefershActorsetActorにて、selectLastという関数を未定義のプロパティに対して実行しようとしてエラーが出たようです。
先程actor関数をScene_MenuBaseからコピーしましたが、この関数は以下のようになっています。

つまりthis._actorというプロパティを戻り値とする、という非常にシンプルな処理です。ただしこのthis._actorというプロパティにはまだ初期値を設定していませんので、具体的なアクターが代入されておらず無効な値(undefined)になってしまっているのです。これではエラーが出てもおかしくないですね。
ですのでこのプロパティに実際のアクターを代入したいと思うのですが、その処理には先程「ついでに」コピーしておいたupdateActor関数が鍵を握っています。

updateActorの定義

これは上記のthis._actorプロパティに具体的なアクターを代入するための処理をしています。具体的なアクターとは$gameParty.menuActor()ですが、これは「メニュー画面で今選択されているアクター」を表します。
というわけでこのupdateActor関数はとても重要な処理をしていることがわかりましたが、ではどこで呼び出されているのでしょうか。検索してみましょう。

rmmz_scenes.js

Scene_MenuBasecreate関数内で呼び出しているようです。このcreateとはその名の通りシーン上のさまざまな要素を作成するための関数であり、Scene_Baseに定義されています。ということは、もちろんそれを継承するScene_Mapにも定義されている、ということです。
では先ほどのように既存関数の再定義によってScene_MapcreateupdateActor関数を追加してみましょう。

_Scene_Map_prototype_create定数に既存関数を代入

それではテストしてみましょう!

Scene_Skillと同様のウィンドウがきちんと表示されましたね! また、メニューを開いてアクターを選択するとそのアクターに表示が切り替わるようになっています!

まとめ

今回はスキルウィンドウの内容をきちんと表示するために、Scene_Skillの内容をコピーしてみました。お疲れ様でした。
ですがこのままではまだウィンドウ内の項目を選択することができず、まだ完全に機能しているとはいいがたいです。
次回はその辺りを改良していこうと思います。

それではまたお会いしましょう!

GitHub


この記事が気に入ったらサポートをしてみませんか?