続・バトル周りを調べてみた

いわゆるチャームですね

今度は戦闘アクションを調べるよ

 さて、前回のバトル周りを調べてみたでは、戦闘シーンの処理の流れを追っていきました。
 しかし、肝心の戦闘アクションの処理をどうやってるんだか追いきれませんでした。
 今回はその戦闘の解決周りを追っていきたいと思います。

 あ、ところでこの記事もこれまでの記事も、静的メソッドもインスタンスメソッドもごっちゃに書いてます。
 ClassName.method() って書くと普通は静的メソッドですけど、ClassName のメソッド、という意味で書いてます。
 ClassName.prototype.method() とか書くと長いし、かといって method() だけだと、どのオブジェクトのメソッドかわからないし。
 その程度のいい加減な記事だと思って、気楽に流していただけると幸いです。基本備忘録なので。
 とはいえ、あきらかな間違いの指摘など、やっていただけると嬉しいです。読みましたよ、程度でも嬉しいです。

 ではまず、戦闘の解決に必要なオブジェクトをざっと並べてみます。

JSONデータ

 基本的にRPGのデータって戦闘用のものなんで、マップ関連以外のほとんどが含まれる感じです。
 なんでまともに並べたらクラスツリーをそのまま書くことになっちゃうので、戦闘に特に深く関わる部分を抜粋。
 要は、味方(Actor)と敵(Enemy)です。敵の方は群のデータ(Troop)もあります。

 アイテム・武器・防具・スキル・ステートといった部分だけでも結構な量になるので、今回はスルーします。
 バトルイベント関連も今回は見るのやめておきましょう。
 まずは、とにかく攻撃を繰り返す殴り合い部分の理解をしたい。

オブジェクト

 JSONデータを読み込んで、JavaScriptオブジェクトとして生成したやつです。
 基本はこれらを使って行くといいと思うんですが、尋常じゃなくメソッドの量が多くて圧倒されます。
 Game_BattlerBase - Game_Battler と継承が繋がっていることでも、ボリュームのほどが伺えます。

 なお今後、バトラーとか Game_Battler とか書いたら Game_ActorGame_Enemy のどっちかの事を書いてると思ってください。
 いちいち、Game_ActorGame_Enemy って書くの分かりにくいですし。
 あと、行動するバトラーを行動主体、その行動を受ける側を行動対象と表記します。
 行動は攻撃だけではないので、攻撃側・防御側と書けないので。
 ちなみに、コード上では行動主体は subject、行動対象は target という表現が使われてます。

 さらに敵味方毎にまとめた以下のオブジェクトがあります。
 単体のバトラーのオブジェクトを直接扱うのではなく、この敵・味方ユニットを通して扱うことも多い感じです。

 あと、超重要なのが行動のデータや処理の中心となる Game_Action オブジェクト。
 個々のバトラーが _actions プロパティに持っています。
 そして、行動の処理結果を保持するのが Game_ActionResultです。

 前回調べた戦闘の流れを作るオブジェクトはシーン制御のためのものなんで、実際戦う場面では気にしなくていいんですが、 BattleManager は別。
 むしろ戦いになってからが本番です。

 今回は、BattleManager._phase の中で行動解決に関わる 'start' から入って 'turn' と 'action' の繰り返し部分を詳しく見て行きます。

'start'フェーズ

 まずは行動(アクション)を決定しないといけません。
 Game_Action のプロパティには行動対象の _targetIndex と行動内容の _item があります。

 行動内容が_item? ってナニって思いますよね。
 RPGツクールMVは、行動をまとめて Game_Item オブジェクトが受け持っているので、道具という意味でのアイテムではなく、ここは項目程度の意味だと思った方がいいと思います。
 なお、そのサブクラスとして各種[攻撃][防御][スキル][アイテム]の行動に対応したオブジェクトがありますが、前述の通り今回は無視。

 では、BattleManager.startBattle()から追っていきましょう。

Game_Actor側の戦闘準備

 'start'フェーズでは、$gameParty.makeActions() が呼ばれて、行動の初期化がなされます。
 この時点では特に行動は設定されていません。
 なので、[不意打ち]で 'turn'フェーズに行くと、一方的に敵から攻撃されることになります。

 プレイヤーキャラ( Game_Actor )は、'input'フェーズでプレイヤーが選択した行動(コマンド)が、 BattleManager.inputtingAction() で返される Game_Action に定義されます。
 こうして、$gameParty に含まれるバトラーごとに行動が定義されていきます。

Game_Enemy側の戦闘準備

 $gameTroop.makeActions() が呼ばれ RPG.Enemy.Action のうち条件に合う行動が抽出され、設定されます。
 ここが敵のかしこさなんかを感じさせる部分なんですが、RPGツクールMVは行動の種類(スキル)頻度(レーティング)と発生条件でそれっぽく表現しています。

 $gameTroop.makeActions() は個々の敵キャラの行動を決める Game_Enemy.makeActions() を呼び出しています。
 例えば、アクティブタイムバトルなんかを実装する際は、行動順が回って来た時点で Game_Enemy.makeActions() を呼べば、その時点での状況に合わせた適切な行動が返ってくるので、行動順に配列としてバトラーを入れてる BattleManager._actionBattlers にpushしておけばいいですね。
 ATBシステムを作ったわけではないので、多分ですが。

'turn'フェーズ

 このフェーズでは、BattleManager.makeActionOrders() で行動順を決めています。

 ただ、行動の解決に関しては特に何もやってません。
 次の行動主体となるバトラーと行動を、'action'フェーズに渡すのが役割です。

'action'フェーズ

 BattleManager.processTurn() から BattleManager.startAction() が呼ばれ、さらにGame_Battler.useItem() が呼ばれてます。
 Game_Battler.useItem() ではスキルのMP・TP あるいは アイテムの個数の消費がなされます。
 前述の通り、ここでのアイテムは複合的な要素なんで、Game_Battler.useItem() は「アイテムを使う」というより「行動に必要なものを消費」みたいな意味になります。

BattleManager

 BattleManager.updateAction() では BattleManager.invokeAction() が呼ばれて、行動の解決が行われます。
 カウンター攻撃は BattleManager.invokeCounterAttack() で、魔法反射は BattleManager.invokeMagicReflection() で解決されますが、特殊処理なのでここでは説明しません。気になったらコード読んでね。
 普通の行動はその名の通りの BattleManager.invokeNormalAction() で、ここから Game_Action に処理が渡されます。

Game_Action

 BattleManager から呼ばれるメソッドは Game_Action.apply() で、このメソッドが戦闘の解決の中心と言えます。
 このメソッドのコードを読めば、大まかな処理の感じは掴めるんじゃないでしょうか。
 まず行動の結果が行動対象の Game_ActionResult に記録され、それに従って実際のダメージなどが適用されます。

 Game_Action.apply() の中でさらに解決する要素ごとに処理が分かれています。
 まず Game_Action.makeDamageValue() でダメージ計算がされ、Game_Action.executeDamage() でダメージが適用されています。
 そこから Game_Action.executeHpDamage() が呼ばれ、さらに行動対象の Game_BattlerGame_Battler.onDamage() に処理が渡ります。

 Game_Action.applyItemEffect() で行動主体の[スキル][アイテム]の使用効果( RPG.Effect )を、行動対象に適用します。
 Game_Action.applyItemUserEffect() 行動主体が受ける効果が適用されます。と言っても標準のメソッドが行なっているのは、行動によるTP増加処理だけです。

Game_Battler

 Game_Battler.onDamage() ではダメージを受けると外れる[ステート]の解除を行い、ダメージによるTP増加処理を行なっています。

  Game_Battler には _actionState プロパティがあって、バトラーの状況を記録しています。
 状況には、‘undecided’、‘inputting’、‘waiting’、‘acting’ があります。
 ただ、BattleManager._phase のように、_actionStateによって戦闘が進行するというわけではなくて、キャラを表示する際にチェックして対応する画像を表示する、みたいな使い方のようです。

 画像関係調べてないから、わりとカンで言ってますが(笑)

まとめ

 今回は戦闘の行動解決部分を調べてみました。
 いやーややこしいですね。
 アイテム・武器・防具・スキル・ステートの部分はほぼ無視しているというのに。

 さらにウィンドウや敵画像、味方のサイドビュー画像、エフェクトアニメーション、コマンド入力処理など、戦闘に関わる部分はまだまだ沢山有ります。

 そこで結論。

RPG専用といえども、汎用性高いから要素多いな!