ページ 1 / 2
【解決】作成途中のアクター選択を省略するプラグイン 内エラーに対応、リファクタリング
Posted: 2024年7月22日(月) 18:44
by ムノクラ
下記のリクエストに応えようと、プラグインを作成しました。
アクター選択を省略するプラグイン
viewtopic.php?f=116&t=13996
一応、動作はさせられたのですが、一部のフック処理がどうしても動作してくれていないようです。
範囲が味方全体の回復スキルを使用すると、下記のエラーが出てしまいます。
コアのバージョンは1.8.0です。
Scene_Skill.prototype.itemTargetActors をフックせずに上書きするとエラーが出ずに動作します。
コード: 全て選択
rmmz_managers.js:2036 ReferenceError: _Scene_Skill_itemTargetActors is not defined
at Scene_Skill.itemTargetActors (MNKR_SkipSkillScopeMZ.js:40)
at Scene_Skill.Scene_ItemBase.isItemEffectsValid (rmmz_scenes.js:1628)
at Scene_Skill.Scene_ItemBase.canUse (rmmz_scenes.js:1622)
at Scene_Skill.Scene_ItemBase.onActorOk (rmmz_scenes.js:1569)
at Window_MenuActor.Window_Selectable.callHandler (rmmz_windows.js:1037)
at Window_MenuActor.Window_Selectable.callOkHandler (rmmz_windows.js:1278)
at Window_MenuActor.processOk (rmmz_windows.js:2063)
at Window_MenuActor.Window_Selectable.processHandling (rmmz_windows.js:1150)
at Window_MenuActor.Window_Selectable.update (rmmz_windows.js:1115)
at WindowLayer.update (rmmz_core.js:4287)
自分が何を勘違いしているのか知りたく思います。
エラーが出る状態の簡単な動作サンプルを添付します。
コメントアウト部を見れば、フック処理したい箇所は分かるようにしたつもりです。
新規プロジェクトに上書きしていただければ、すぐに動作確認できると思います。
ご助言いただきたく、よろしくお願いいたします。
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月22日(月) 18:52
by ムノクラ
もしかして、自己解決した…かも?
コード: 全て選択
_Scene_Skill_itemTargetActors.call(this);
を
コード: 全て選択
return _Scene_Skill_itemTargetActors.call(this);
に変更したら、エラーが出なくなりました…
これで合っているでしょうか?
コード: 全て選択
(() => {
"use strict";
//-----------------------------------------------------------------------------
// Scene_Skill
const _Scene_Skill_itemTargetActors = Scene_Skill.prototype.itemTargetActors; //問題のフック
Scene_Skill.prototype.itemTargetActors = function () {
const action = new Game_Action(this.user());
action.setItemObject(this.item());
if (action.isForUser()) {
return [this.actor()];
} else {
return _Scene_Skill_itemTargetActors.call(this); //問題のフック
}
};
const _Scene_Skill_determineItem = Scene_Skill.prototype.determineItem;
Scene_Skill.prototype.determineItem = function () {
const action = new Game_Action(this.user());
const item = this.item();
action.setItemObject(item);
if (action.isForUser()) {
this.useItem();
this._itemWindow.refresh();
this._itemWindow.activate();
} else {
_Scene_Skill_determineItem.call(this);
}
};
})();
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月22日(月) 20:51
by basu
こんにちは。
私の環境で確認しましたところ異なるエラーが発生しました。
コード: 全て選択
rmmz_managers.js:2036 TypeError: Cannot read property 'some' of undefined
at Scene_Skill.Scene_ItemBase.isItemEffectsValid (rmmz_scenes.js:1628)
at Scene_Skill.Scene_ItemBase.canUse (rmmz_scenes.js:1622)
at Scene_Skill.Scene_ItemBase.onActorOk (rmmz_scenes.js:1569)
at Window_MenuActor.Window_Selectable.callHandler (rmmz_windows.js:1037)
at Window_MenuActor.Window_Selectable.callOkHandler (rmmz_windows.js:1278)
at Window_MenuActor.processOk (rmmz_windows.js:2063)
at Window_MenuActor.Window_Selectable.onTouchOk (rmmz_windows.js:1208)
at Window_MenuActor.Window_Selectable.processTouch (rmmz_windows.js:1172)
at Window_MenuActor.Window_Selectable.update (rmmz_windows.js:1116)
at WindowLayer.update (rmmz_core.js:4287)
ムノクラさんが発生した「is not defined」のエラーはその変数または関数が未定義のまま呼び出そうとした際に発生するエラーなので今回とは別のタイミングで発生したエラーだと思います。
また、同様に「_Scene_Skill_itemTargetActors.call」をreturnするよう修正したら私の環境でもエラーが発生しなくなりました。
私の環境でのエラーの原因は、元の「Scene_Skill.prototype.itemTargetActors」関数でreturnを行っているので、呼び出し元でもreturnをしてあげないと「Scene_Skill.prototype.itemTargetActors」関数の戻り値を返すことができなくなり「Scene_Skill.prototype.itemTargetActors」関数の戻り値がundefinedとなってしまうためでした。
(return this.itemTargetActors().some(target => action.testApply(target));)
ただ、エラーの内容が「is not defined」の場合は違う原因の可能性があります。
よろしくお願いします。
※エラーの原因が一部誤っていたので修正しました。
誤:nullが返る
正:戻り値がundefinedとなる
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月22日(月) 21:21
by ムノクラ
basu さんが書きました:こんにちは。
私の環境で確認しましたところ異なるエラーが発生しました。
コード: 全て選択
rmmz_managers.js:2036 TypeError: Cannot read property 'some' of undefined
at Scene_Skill.Scene_ItemBase.isItemEffectsValid (rmmz_scenes.js:1628)
at Scene_Skill.Scene_ItemBase.canUse (rmmz_scenes.js:1622)
at Scene_Skill.Scene_ItemBase.onActorOk (rmmz_scenes.js:1569)
at Window_MenuActor.Window_Selectable.callHandler (rmmz_windows.js:1037)
at Window_MenuActor.Window_Selectable.callOkHandler (rmmz_windows.js:1278)
at Window_MenuActor.processOk (rmmz_windows.js:2063)
at Window_MenuActor.Window_Selectable.onTouchOk (rmmz_windows.js:1208)
at Window_MenuActor.Window_Selectable.processTouch (rmmz_windows.js:1172)
at Window_MenuActor.Window_Selectable.update (rmmz_windows.js:1116)
at WindowLayer.update (rmmz_core.js:4287)
ムノクラさんが発生した「is not defined」のエラーはその変数または関数が未定義のまま呼び出そうとした際に発生するエラーなので今回とは別のタイミングで発生したエラーだと思います。
また、同様に「_Scene_Skill_itemTargetActors.call」をreturnするよう修正したら私の環境でもエラーが発生しなくなりました。
私の環境でのエラーの原因は、元の「Scene_Skill.prototype.itemTargetActors」関数でreturnを行っているので、呼び出し元でもreturnをしてあげないと「Scene_Skill.prototype.itemTargetActors」関数の戻り値を返すことができなくなりnullが返ってしまうためでした。
ただ、エラーの内容が「is not defined」の場合は違う原因の可能性があります。
よろしくお願いします。
ご返信いただき、ありがとうございます。
もしかして、エラーを出したときのコードと、提出したサンプルが微妙に違う可能性がある気がしてきました…。
ただ、修正後はbasu様の環境でも問題なさそうとのことで、これで大丈夫なんじゃないかなーという気がしています。
この程度のスキルでプラグインを公開するのは、みっともないと自認していますが、このような相談や不具合報告から勉強になり、ありがたく思っております。
引き続き、数日は他の方の回答をお待ちしてから正式公開しようかと思います。
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月22日(月) 22:42
by Plasma Dark
エラーの原因については、エラー発生時のコードとサンプルが異なっているとすれば特定のしようがないので置いておきます。
直接エラーとは関係ないんですが、書き換え対象を Scene_Skill に限定している(スキルのみ対象選択をスキップし、アイテムは特に何もしない)のは何か意図があってのことでしょうか。
元々、 itemTargetActors は Scene_ItemBase に定義された関数で、それを Scene_Skill の場合に限って上書きしてしまうと、思わぬ競合を招くことがあります。
他に Scene_ItemBase.prototype.itemTargetActors をフックするようなプラグインがいた場合、プラグインの順序関係次第では意図通りに動かなくなる恐れがあります。
スキルのみ対象選択をスキップしたい場合であっても、 Scene_ItemBase.prototype.itemTargetActors をフックするほうが、利用者にとっては混乱を招きにくいように思います。
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月23日(火) 06:38
by ムノクラ
Plasma Dark さんが書きました:エラーの原因については、エラー発生時のコードとサンプルが異なっているとすれば特定のしようがないので置いておきます。
直接エラーとは関係ないんですが、書き換え対象を Scene_Skill に限定している(スキルのみ対象選択をスキップし、アイテムは特に何もしない)のは何か意図があってのことでしょうか。
元々、 itemTargetActors は Scene_ItemBase に定義された関数で、それを Scene_Skill の場合に限って上書きしてしまうと、思わぬ競合を招くことがあります。
他に Scene_ItemBase.prototype.itemTargetActors をフックするようなプラグインがいた場合、プラグインの順序関係次第では意図通りに動かなくなる恐れがあります。
スキルのみ対象選択をスキップしたい場合であっても、 Scene_ItemBase.prototype.itemTargetActors をフックするほうが、利用者にとっては混乱を招きにくいように思います。
ご返信いただき、ありがとうございます。
書き換え対象を Scene_Skill に限定しているのは意図があります。
元リクエストである
アクター選択を省略するプラグイン
viewtopic.php?f=116&t=13996
は「マップ上でスキル(範囲が使用者)を使用した場合に、使用対象を選択する画面を経由するのを変更したい」旨のリクエストと解釈しています。
アイテムの場合、マップ上ではパーティの誰が使用しているのか不明なため、スキルのみこの対象になると考えました。
最初は、Scene_ItemBaseで作り始めたのですが、使用したのがスキルであるかの判定を考えているうちに「Scene_Skillに継承したのを利用すれば、そこは要らなくならないか?」という発想で切り替えました。
この考えから、Scene_Skillに限定しようと考えました。
Scene_ItemBase を使用したほうが競合対策になりやすいのであれば、そちらで作り直してみようと思います。
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月23日(火) 08:22
by ムノクラ
作り直してみました。
.skills()メソッドが使えそうもないので、スマートでない手法になってしまいました。
コード: 全て選択
const isSkill = action._item._dataClass === 'skill';
こちらの方がベターな作りになるでしょうか?
また、よりスマート(ムノクラに理解できるレベルで…)な書き方を教えていただければ幸いです。
※クラス構文?とか分からないので…
コード: 全て選択
(() => {
"use strict";
//-----------------------------------------------------------------------------
// Scene_ItemBase
const _Scene_ItemBase_itemTargetActors = Scene_ItemBase.prototype.itemTargetActors;
Scene_ItemBase.prototype.itemTargetActors = function () {
const action = new Game_Action(this.user());
action.setItemObject(this.item());
const isSkill = action._item._dataClass === 'skill';
if (isSkill && action.isForUser()) {
return [this.actor()];
} else {
return _Scene_ItemBase_itemTargetActors.call(this);
}
};
const _Scene_ItemBase_determineItem = Scene_ItemBase.prototype.determineItem;
Scene_ItemBase.prototype.determineItem = function () {
const action = new Game_Action(this.user());
const item = this.item();
action.setItemObject(item);
const isSkill = action._item._dataClass === 'skill';
if (isSkill && action.isForUser()) {
this.useItem();
this._itemWindow.refresh();
this._itemWindow.activate();
} else {
_Scene_ItemBase_determineItem.call(this);
}
};
})();
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月24日(水) 02:21
by Plasma Dark
ああ、なるほど。確かにスキルは使用者が直感的にも明らかで、アイテムはそうではないという違いがありますね。
一応、 Scene_Skill を使う手もなくはないんですが、丁寧に競合を避けようとすると、競合回避専用のプラグインを独立させるみたいな迂遠なことをしなければならないので、私としては Scene_ItemBase のほうで分岐を書くことをオススメします。
isSkill の条件式はもっとシンプルに書けますが、方針としてはご提示頂いた書き方で良さそうです。
使う対象がアイテムであるかどうかを見分ける条件式は、直前に Game_Action インスタンスを作っているので
action.isSkill()
が最も簡単な書き方かなと思います。
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月24日(水) 03:43
by ムノクラ
Plasma Dark さんが書きました:ああ、なるほど。確かにスキルは使用者が直感的にも明らかで、アイテムはそうではないという違いがありますね。
一応、 Scene_Skill を使う手もなくはないんですが、丁寧に競合を避けようとすると、競合回避専用のプラグインを独立させるみたいな迂遠なことをしなければならないので、私としては Scene_ItemBase のほうで分岐を書くことをオススメします。
isSkill の条件式はもっとシンプルに書けますが、方針としてはご提示頂いた書き方で良さそうです。
使う対象がアイテムであるかどうかを見分ける条件式は、直前に Game_Action インスタンスを作っているので
action.isSkill()
が最も簡単な書き方かなと思います。
返信いただき、ありがとうございます。
コードもスッキリしました。
質問が逸れるようで恐縮ですが、
action.isSkill()
のような、状況によって使用できるメソッド(?)の探し方が分かりません。
以前から疑問に感じていましたが、これらを探し出すコツみたいなものはありますか?
一応、公式やtonbi氏の非公式リファレンスを検索したりはしているのですが…
Re: 作ったプラグイン内でフック処理するとエラーが出てしまう
Posted: 2024年7月24日(水) 07:37
by Plasma Dark
ある程度コアスクリプトのインターフェースを頭に入れているからさっと出てくるみたいなところはあり、最終的に効率よく探すんだったら経験が物を言うとしか言えないですね……。
今回の例で言うと、行動(Game_Action)について、それがスキルであるかアイテムであるかを判別したいというところから始まるので、その時点で isSkill の名前が思い浮かびます。
後は、 rmmz_objects.js 内をテキスト検索して、 isSkill が実際に存在するか、使えるかを確認するという流れで回答に至っています。
対象について、どんな情報がほしいか、どんな操作を行いたいかからなんとなくそれっぽい英語を作って、コアスクリプト(あるいはスクリプトリファレンス)を検索する感じですね。
コアスクリプトを読んだ経験が多ければ多いほど、それっぽい英語を作るところの精度が上がります。
それっぽい英語が作れない場合は、対象 (今回の場合は Game_Action) についてコードを眺めて探すのもアリですが、これはちょっと時間がかかるので常にできるわけじゃないですね。