MPチェーンシステムを作ってみる

はいどーもこんばんはプログラマになりかけのニートです。
本日はMPチェーンシステムの作成、もとい責任のたらい回しについて勉強したいと思いますよ。

言語はJavaScirpt(ツクールMV)です。

MPチェーンシステムとは

MPチェーンシステムとは「パーティーでMPを統一的に扱うシステム」のこととします。
より具体的には「パーティーメンバーAがMP0になったとき、パーティメンバーBのMPを代わりに使う。これはC、Dも同様」という感じのシステムです。

「チェーン」とはどういうことでしょうか?
これはパーティメンバーAがダメならパーティメンバーBをチェックし、それもダメならパーティメンバーCをチェックする、という感じの「責任をたらい回しにする動きのこと」をチェーンと呼んでいます。
ちなみに例えばこのチェーンをパーティメンバーBから始めたとき、最後のチェックはAで終わるようにしなければなりません(再びBに入ると無限ループになるため)。

なお、今回は本格的なプラグインとして作成はしないので、あんまりバグチェックとかしてません。
実際の使用に耐えうるものではないことをあらかじめお断りしておきます(つまりちゃんとしたものを作りたい場合、もう少し丁寧にテストする必要がある)。
また、僕はそもそも戦闘系の処理をいじったことがほとんどなく、戦闘系の処理について詳しくないことも付記しておきます。
なんか間違ってたら教えてちょうだい!

サンプル動画はこんな感じです。
MPが足りなくなると、次のアクターのMPを使っているのがわかるでしょうか?

全コードは一番下に貼ってます。

さっそく作ってみる

ではさっそく作ってみましょう。
まずはChainManagerクラスの作成です。
というわけでドン。

このクラスは静的なクラスです。
まずはinitializeBattlersメソッドを見てください。
これは単に現在の戦闘メンバーの情報をChainManagerクラスにも保存しているだけです。
このメソッドを実行したとき、デバッグ用で「initializeBattlers」とコンソール画面に表示するようにしています。
初期化用のメソッドですので、実行するのは「戦闘開始直後」です。

次にtryExecuteChainMpCostメソッドを見てください。
このメソッドがチェーン状に呼ばれることになります。
これは「次に行動するはずのバトラーの情報を取得し、現在のバトラーのMPが0以下になっていたら次のバトラーに対してchainSkillMpCostを呼ぶ」メソッドです。
このメソッドが呼ばれる前にMP消費の計算がおこなわれるので、「現在のバトラーのMPが0以下になっていれば」という判定が可能となります。

getPartyMPメソッドは単にPTの合計MPを返すだけです。

getNextBattlerメソッドは、「自分の次のバトラーを取得する」メソッドです。
(index + 1)%this.battlers.length;の計算式が若干複雑ですが、要は0→1→2→3→0→1→2→3→0とループする感じの計算式です。

さて次は実際にChainManagerクラスを利用します。
まずはBattleManager.startBattleメソッドをオーバーライドしましょう。

次はGame_Actorクラスのメソッドをオーバーライドおよびメソッドの追加をします。

canPaySkillCostメソッドは、そのスキルを使用できるかどうかを確認しています。
ここは本来「そのキャラクターが、今のMP(とTP)でその技を使えるかどうか」をチェックするものです。
ですが今回はチェーン状でMPを共有していますので、ChainManager.getPartyMP()を利用してチェックしています(パーティー全体のMPとの比較)。

paySkillCostメソッドは、実際にスキルが使用されたときに呼び出されます。
このときChainManager.tryExecuteChainMpCostメソッドが呼び出されます。
引数は自分自身(Game_BattlerBaseで、つまり技を使用したアクター)です。
するとtryExecuteChainMpCost内でMPをチェーン状で使用するかどうかの処理が入り、チェーン状で使用する必要があると、次のアクターのchainSkillMpCostメソッドが呼び出されます。
これが処理のたらい回しです。
ちなみに、chainSkillMpCostはGame_BattlerBaseのメソッドです。
機能的にはpaySkillCostとほとんど変わらないのですが、paySkillCostメソッドはskillを引数に取ることを前提としているので、別に新しく作りました。
そしてこのたらい回しされたアクターも再びChainManager.tryExecuteChainMpCostメソッドを呼び出します。

この処理を見たら「MPがゼロになったとき、延々とたらい回しし続けて無限ループするのでは?」と思うかもしれませんが、実際はcanPaySkillCostのチェックではじかれて無限ループになりません。
が、あまりテストしていないので、何か複雑な使い方(ないしは僕が想定していない使い方)をすると実際のところ不具合が出るかもしれません。
実用に耐えうるものではない、というのはこういうところですねw

バトル系は処理が複雑なので、全てのパターンを想定するのが難しいのです。

おわりに

今回のプラグインはデザインパターンの一つ「Chain of Responsibility」から想起して作ったものです。
ごく簡単なチェーン状の動作だったので、しっかりきっちり「Chain of Responsibility」パターン通りは作っていませんが、考え方はこのパターンの通りなんじゃないかなと思います。
気になった人はググってみてくださいw

ゲーム的には「チェーンで繋がるのは特定のキャラ同士のみにする」という機能を入れてもおもしろいかもしれません。
例えば双子キャラとか三つ子キャラのみとかですかね。
あるいは恋愛関係になるとフラグONになり、チェーンで繋がるようにするギミックとかしょうか。

なんにせよ面白い機能が作れそうですよね。
誰か作ってください。

ほなそんな感じでまた。

↓これ全コードです。面倒な人はコピペしてください。

フォローする