RPG ツクール MV の戦闘の実装

この記事は「[RPG ツクール MV Advent Calendar](http://qiita.com/advent-calendar/2015/rmmv)」 13 日目の記事**兼**「[第 2 のドワンゴ Advent Calendar](http://qiita.com/advent-calendar/2015/dwango2)」 13 日目の記事です。 Qiita の人に怒られたら兼用をやめます。

# はじめに

この記事は RPG ツクール MV における戦闘シーンの実装についての各論的なまとめです。自分が戦闘プラグインを作るために欲しかった情報をまとめます。RPG ツクール MV のソースコードは読めばだいたい分かるようにできていますが、さすがに戦闘まわりはかなり複雑であり、クラス関係や状態遷移を把握するのが大変です。戦闘プラグインを作るとき、または大々的に自作戦闘を作るときの資料としてどうぞ。

前提知識として、 JavaScript を読めること、「アクター」などのツクール MV 用語を知っていること、ツクール MV のターン制な戦闘がどういったものかを知っていることを仮定します。

用語などは基本的に英語版ベースです。筆者が日本語版を持っていないためです。適宜読み替えてください。

この記事のライセンスは原則 CC0、スクリプト部分はスクリプトのライセンスに従うものとします。

## クイズ

突然ですがクイズです。

* 戦闘が終了する条件は何か。
* 敵の行動はどのタイミングで決定するか。
* スキルのダメージとエフェクトで両方 HP が減るような設定を行った場合、何が起きるか。
* 魔法の反射は誰に跳ね返るか。
* アクターが素手で攻撃した場合、属性はどうなるか。
* 複数属性を持った攻撃の場合、属性によるダメージ変動の計算はどうなるか。

この記事を読むと、このような質問に答えられるようになります。

# クラス

戦闘に関係する主なクラスを説明します。

大雑把な依存関係を図示すると次のようになります。 Scene や View などのパッケージ的なものは筆者が便宜的につけたもので、実際にコード上に現れるものではありません。また依存関係の矢印は正確なものではなく、省略しているところもあります (特に View から Object への依存関係は全て省略しています)。 

![battle_classes.png](https://qiita-image-store.s3.amazonaws.com/0/1911/992af16c-4c72-43dd-7ee6-7331f5f766c6.png)


<dl>
<dt><code>Scene_Battle</code> (rpg_scene.js)</dt>
<dd>戦闘シーンクラス。戦闘の進行状態やビューの状態を更新する。状態は持たない (≒状態を表すフィールドがない)。大雑把に言うと、 RPG ツクール MV においては Scene クラス (<code>Scene_*</code> という名前のクラス) のオブジェクトの <code>update</code> を毎フレーム呼ぶことでゲームが進行する。 <code>Scene_Battle</code> は戦闘シーンにおける Scene クラスである。
</dd>

<dt><code>BattleManager</code> (rpg_managers.js)</dt>
<dd>戦闘シーンの状態を管理するクラス。シングルトン。ビューを更新する。 <code>Scene_Battle</code> との大きな違いは、 <strong><code>Scene_Battle</code> は状態を持たないのに対し、 <code>BattleManager</code> は状態を持つ点である</strong>。 また、<code>Scene_Battle</code> の <code>update</code> は毎フレーム呼ばれるのに対し、 <code>BattleManager</code> の <code>update</code> はウィンドウがアニメーションしていない状態においてのみ呼ばれ (厳密にはもう少し細かい条件がある)、さらに <code>update</code> 内部ではスプライトやウィンドウのどれがビジー状態の時には何もしない。すなわち論理的な状態の変更可能性がある時にのみ更新を行うメソッドである。 <code>Scene_Battle</code> も <code>BattleManager</code> もどちらもビュー (ウィンドウの類) を更新する。
</dd>

<dt><code>Game_BattlerBase</code> (rpg_objects.js)</dt>
<dd><code>Game_Actor</code> と <code>Game_Enemy</code> の祖先クラス。戦闘における登場人物。</dd>

<dt><code>Game_Battler</code> (rpg_objects.js)</dt>
<dd><code>Game_Actor</code> と <code>Game_Enemy</code>の親クラスで、 <code>Game_BattlerBase</code> の子クラス。 <code>Game_BattlerBase</code> にアクション (攻撃など) やアニメーション状態を加えたもの。</dd>

<dt><code>Game_Actor</code> (rpg_objects.js)</dt>
<dd>アクターの状態を表すクラス。</dd>

<dt><code>Game_Enemy</code> (rpg_objects.js)</dt>
<dd>エネミーの状態を表すクラス。</dd>

<dt><code>Game_Action</code> (rpg_objects.js)</dt>
<dd>バトラーの行動を表すクラス。ダメージの処理などはこのクラスで行われる。</dd>

<dt><code>Game_ActionResult</code> (rpg_objects.js)</dt>
<dd>バトラーの行動結果を表すクラス。主に <code>Window_BattleLog</code> で参照される。</dd>

<dt><code>Game_Unit</code> (rpg_objects.js)</dt>
<dd><code>Game_Party</code> と <code>Game_Troop</code> の親クラス。</dd>

<dt><code>Game_Party</code> (rpg_objects.js)</dt>
<dd>パーティー (アクターの集まり) の状態を表すクラス。</dd>

<dt><code>Game_Troop</code> (rpg_objects.js)</dt>
<dd>トループ (エネミーの集まり) の状態を表すクラス。</dd>

<dt><code>Spriteset_Battle</code> (rpg_sprites.js)</dt>
<dd>戦闘シーンにおけるスプライトの集合。</dd>

<dt><code>Window_BattleLog</code> (rpg_window.js)</dt>
<dd>戦闘中のメッセージウィンドウ。実はサイドビューバトルにおけるダメージ表示などもこのクラスを通じて行う。</dd>

<dt><code>Window_StatusLog</code> (rpg_window.js)</dt>
<dd>戦闘中のステータスウィンドウ。</dd>

</dl>

その他多数の Window クラスがありますが、省略します。

# フェーズ

`BattleManager._phase` の値で、戦闘の進行状態を表す文字列値です。戦闘の大まかな状態を表します。

![battle_phases.png](https://qiita-image-store.s3.amazonaws.com/0/1911/3ab4bf57-05cc-fb55-eae5-3a3e6f652789.png)


<dl>
<dt>init</dt>
<dd>戦闘開始前の初期状態。 <code>startBattle</code> で start フェーズに遷移する。</dd>
<dt>start</dt>
<dd>ゲーム開始状態。戦闘開始直後のいわゆる「敵が現れた!」と表示されているところの状態。ウィンドウが閉じてすぐに input フェーズに遷移する。</dd>
<dt>input</dt>
<dd>パーティーコマンド (戦う or 逃げる) およびアクターごとのコマンド入力を行うフェーズ。パーティーコマンドを入力している最中は <code>BattleManager.actor()</code> が <code>null</code>、アクターコマンドを入力している最中は <code>BattleManager.actor()</code> が入力中の <code>Game_Actor</code> を返す。パーティーコマンドで「Fight」を選択して、全入力が終了すると turn フェーズに遷移する。パーティーコマンドで「Escape」を選択すると <code>BattleManager.processEspcae</code> が実行される。逃走成功時に <code>BattleManager.processAbort</code> が呼ばれ、 battleEnd フェーズに遷移する。逃走失敗時には turn フェーズに遷移する。</dd>
<dt>turn</dt>
<dd>ターン数のインクリメント、バトラーの行動順の決定、行動の処理を行うフェーズ。誰かの行動が開始すると action フェーズに遷移する。全員の行動が終了すると turnEnd フェーズに遷移する。</dd>
<dt>action</dt>
<dd>バトラーの行動の処理を行うフェーズ。行動中のバトラーは <code>BattleManager._subject</code> である。行動が終了すると turn フェーズに遷移する。</dd>
<dt>turnEnd</dt>
<dd>ターン終了時のステート処理など、細かい処理を行うフェーズ。すぐに input フェーズに遷移する。</dd>
<dt>battleEnd</dt>
<dd>戦闘続行不可能になった場合のフェーズ。どのフェーズの時にでも、戦闘が続行できない場合にこのフェーズに遷移する。アクターが全員死亡、エネミーが全員死亡、パーティー逃走成功の他に、タイマーが時間切れした (aborting フェーズ)、イベントによって戦闘が中断した (aborting フェーズ)、アクターが誰もいなくなった場合である。状況によって元のシーンに戻るか、 <code>Scene_GameOver</code> に遷移する。 <code>BattleManager._phase</code> は <code>null</code> になる。</dd>
<dt>aborting</dt>
<dd>タイマーの時間切れ、またはイベントコマンドにより戦闘が中断するときのフェーズ。 <code>BattleManager.processAbort</code> を実行し、 battleEnd フェーズへ遷移する。 <code>processAbort</code> というメソッド名は aborting フェーズとは関係ありそうで、実はない (input フェーズの逃走成功時にも呼ばれる)。</dd>
</dl>

## コマンド入力についての補足

```js:rpg_managers.js
BattleManager.startInput = function() {
    this._phase = 'input';
    $gameParty.makeActions();
    $gameTroop.makeActions();
    this.clearActor();
    if (this._surprise || !$gameParty.canInput()) {
        this.startTurn();
    }
};
```

turn フェーズから input フェーズに遷移するときに `Game_Unit` の `makeActions` が呼ばれ、結果的に `Game_Battler` の `makeActions` が呼ばれますが、これは一体何をしているのでしょうか。 `makeActions` はアクターとエネミーで若干異なります。 `Game_Actor` の `makeActions` は `_actions` に `Game_Action` を新しく作って設定していますが、これは入力への準備に必要な作業です。一方 `Game_Enemy` の `makeActions` はもうその場でアクションが決定しています。裏方では「ユーザーの入力前に敵の行動は既に決定している」という面白いことになっているというわけです。

さて input フェーズでは `Game_Actor` の `_actions` それぞれに対して入力を順番に回していきます。このとき `_actions` 配列が空だと順番が飛ばされます。実際に `Game_Actor` の `canMove` が `false` の状態で `makeActions` を呼ぶと `_actions` は空配列になり、コマンド入力時に順番が飛ばされます。 `makeActions` という名前は少しわかりにくいですが、要は「入力のためのアクションのスロットの初期化作業」にあたります。

# バトラーのアクションの処理

ここでいうアクションとは、バトラー一人の攻撃、防御、アイテム使用、スキル使用などの行動です。大雑把な流れは次の通りです。

1. アクション準備 (`BattleManager.startAction` が呼ばれる)
2. アクション開始 (`BattleManager.invokeAction` が呼ばれる)
3. (必要ならば) カウンター、魔法反射の処理を行う
4. アクション実行 (`Game_Action` の `apply` が呼ばれる)
6. アクション結果の保存 (`Game_Battler` の `_result` (`Game_ActionResult`) が変化)
7. 結果の表示 (`Window_BattleLog` の `displayActionResult` で、バトラーに設定された `Game_ActionResult` オブジェクトを元にメッセージなどを表示する)

順番に見ていきましょう。

## アクション準備 (`BattleManager.startAction`)

```js:rpg_managers.js
BattleManager.startAction = function() {
    var subject = this._subject;
    var action = subject.currentAction();                                                             
    var targets = action.makeTargets();
    this._phase = 'action';
    this._action = action;
    this._targets = targets;
    subject.useItem(action.item());
    this._action.applyGlobal();
    this.refreshStatus();
    this._logWindow.startAction(subject, action, targets);
};
```

この関数呼び出し時点では実はまだ action フェーズではなく turn フェーズです。ここでの重要なポイントは `this._action` に `Game_Action` オブジェクトをセットしているところです。 `this._action` はこれから実行するアクションを表します。

`this._logWindow.startAction(...)` でメッセージの表示やサイドビューの場合はアクターのアニメーションの変化などを処理しています。

## アクション開始 (`BattleManager.invokeAction`)

```js:rpg_managers.js
BattleManager.invokeAction = function(subject, target) {                                                                                                                                                    
    this._logWindow.push('pushBaseLine');                                                                                                                                                                   
    if (Math.random() < this._action.itemCnt(target)) {                                                                                                                                                     
        this.invokeCounterAttack(subject, target);                                                                                                                                                          
    } else if (Math.random() < this._action.itemMrf(target)) {                                                                                                                                              
        this.invokeMagicReflection(subject, target);                                                                                                                                                        
    } else {
        this.invokeNormalAction(subject, target);                                                                                                                                                           
    }
    subject.setLastTarget(target);                                                                                                                                                                          
    this._logWindow.push('popBaseLine');                                                                                                                                                                    
    this.refreshStatus();                                                                                                                                                                                   
};
```

`_action` は `Game_Action` オブジェクトで、使用するアイテムやスキルの情報です。 `itemCnt` や `itemMrf` というアイテムに関わりそうなメソッドが出てきましたが、実はこれはアイテムだけではなくスキルも関係します。**スクリプト内部ではアイテム、武器、防具以外に、スキルも `Game_Item` で表現されています。**スキルの使用もアイテムの使用も、 `Game_Item` を使用するという形で表現されるわけです。通常攻撃はスキル 1 番を使用するのと同じなので、**バトラーのあらゆるアクションは結局 `Game_Item` の使用という形で表現されます**。スクリプト中に出てくる `item` はいわゆるアイテムだけではなくスキルを指すことも多いのです。 `itemCnt()` はカウンター率を、 `itemMrf()` は魔法反射確率を表します。

アイテムまたはスキルによってカウンター、魔法反射、通常の処理で割り振っているだけで、基本的には `invoke*` メソッドが呼ばれ、それぞれの中で `Game_Item` の `apply` が呼ばれます。 `invoke*` メソッドで実際のアクション処理が行われます。

`_logWindow` (`Window_BattleLog`) に関しては後述します。

最後の `refreshStatus` は `Window_BattleStatus` を更新します。  

### 通常

```js:rpg_managers.js
BattleManager.invokeNormalAction = function(subject, target) {
    var realTarget = this.applySubstitute(target);
    this._action.apply(realTarget);
    this._logWindow.displayActionResults(subject, realTarget);
};
```

ターゲットがいない時の処理などがありますが、基本的に単に現在の行動 `this._action` (`Game_Action`) の `apply` を呼んでいるだけです。

### カウンター

```js:rpg_managers.js
BattleManager.invokeCounterAttack = function(subject, target) {
    var action = new Game_Action(target);
    action.setAttack();
    action.apply(subject);
    this._logWindow.displayCounter(target);
    this._logWindow.displayActionResults(subject, subject);
};
```

本来のアクション (`this._action`) を**無視**しています。新たな通常攻撃アクションを作り、それの `apply` を呼んでいます。

### 魔法反射

```js:rpg_managers.js
BattleManager.invokeMagicReflection = function(subject, target) {
    this._logWindow.displayReflection(target);
    this._action.apply(subject);
    this._logWindow.displayActionResults(subject, subject);
};
```

`Game_Action.prototype.apply` の引数を `target` ではなく `subject` にしているだけです。ツクール MV においては、**魔法の反射はかならず詠唱者に跳ね返る**という実装になっています。

## アクション実行 (`Game_Action` の `apply`)

```js:rpg_objects.js
Game_Action.prototype.apply = function(target) {
    var result = target.result();
    this.subject().clearResult();
    result.clear();
    result.used = this.testApply(target);
    result.missed = (result.used && Math.random() >= this.itemHit(target));
    result.evaded = (!result.missed && Math.random() < this.itemEva(target));
    result.physical = this.isPhysical();
    result.drain = this.isDrain();
    if (result.isHit()) {
        if (this.item().damage.type > 0) {
            result.critical = (Math.random() < this.itemCri(target));
            var value = this.makeDamageValue(target, result.critical);
            this.executeDamage(target, value);
        }
        this.item().effects.forEach(function(effect) {
            this.applyItemEffect(target, effect);
        }, this);
        this.applyItemUserEffect(target);
    }
};
```

見ると分かる通り、以下の順で処理が行われます。

1. アクション結果の初期設定
2. ヒットなどの判定 (`isHit`)
3. (ヒットした場合) ダメージの計算 (`executeDamage`)
4. (ヒットした場合) エフェクトの計算 (`applyItemEffect`)
5. (ヒットした場合) 使用者の TP の増加処理 (`applyItemUserEffect`)

ここで「ダメージ」はエディタでいうと右上の計算式などを書く欄、「エフェクト」はその下の特徴 (Traits) と似たような UI を持つ欄です (下図参照)。

<img width="449" alt="damage_and_effects.png" src="https://qiita-image-store.s3.amazonaws.com/0/1911/42cd1755-9778-9de1-0745-f5b0c2b40c10.png">

最終的にアクションによって変化する HP などは `GameBattler` の `gainHp` などのメソッドが呼ばれ、 `GameBattler` が持つ `_result` (`Game_ActionResult` オブジェクト) に結果がセットされます。この `_result` はアクションの結果表示に使われます。

### ダメージとエフェクトで矛盾する場合

ダメージもエフェクトも両方 HP、 MP などの増減を指定できます。ここで、ダメージとエフェクト両方で HP を減らすようなものを書いた場合、何が起きるでしょうか。実装からいうと「ダメージの表示は後者になるが、実際の HP 増減は 2つを合わせたものになる」です。例えば HP のダメージや回復は `GameBattler` の `gainHp` メソッドが呼ばれて処理されるのですが、このメソッドは 1 回のアクションで 2 度呼ばれることを想定していません。このような実装のため、同じパラメータをダメージとエフェクトで変化させるのはやめたほうがよいでしょう。

個人的にはダメージとエフェクトを統合してエフェクトだけにすればすっきりするのではないかと思うのですが、どういう意図でこう分かれているのかはよくわかりません。

### ダメージの計算 (`Game_Action` の `makeDamageValue`)

```js:rpg_objects.js
Game_Action.prototype.makeDamageValue = function(target, critical) {
    var item = this.item();
    var baseValue = this.evalDamageFormula(target);
    var value = baseValue * this.calcElementRate(target);
    if (this.isPhysical()) {
        value *= target.pdr;
    }
    if (this.isMagical()) {
        value *= target.mdr;
    }
    if (baseValue < 0) {
        value *= target.rec;
    }
    if (critical) {
        value = this.applyCritical(value);
    }
    value = this.applyVariance(value, item.damage.variance);
    value = this.applyGuard(value, target);
    value = Math.round(value);
    return value;
};
```

スキルやアイテムに設定されている戦闘計算式から、属性の影響 (`calcElementRate`)、ヒットタイプが物理攻撃や魔法攻撃だった場合の変動、~~蘇生~~回復だった場合の回復率、クリティカル (`applyCritical`)、分散 (`applyVariance`)、防御 (`applyGuard`) を考慮して最終的なダメージを算出します。`evalDamageFormula` は HP Recover または MP Recover の場合に 0 以下の値を、それ以外の場合に 0 以上の値を返します。


### 属性としての物理とヒットタイプとしての物理

<img width="416" alt="invocation.png" src="https://qiita-image-store.s3.amazonaws.com/0/1911/0472335a-cd40-7011-a1c7-0fd79b71befa.png">

上図のようにスキルやアイテムにはヒットタイプ (Hit Type) という概念があり、「Certain Hit」、「Physical Attack」、「Magic Attack」の 3 種類があります。一方で属性 (Element) の方にも Physical があります。属性 (Element) としての物理 (Physical) とヒットタイプ (Hit Type) としての物理 (Physical) は、名前は同じでも全く別物です。

属性としての物理は、属性によるダメージ変動にのみ関係があります。

ヒットタイプには前述のとおり 3 種類ありますが、それぞれどの命中率や回避率が適用されるのか (もしくはされないのか)、カウンター攻撃の対象になるのか、どうアニメーションするかなどに影響があります。 `Game_Action` の `isPhysical` はヒットタイプが物理かどうかを返します。属性は関係ありません。

ところで、デフォルトで入っている武器やエネミーの攻撃には物理属性がつくように設定されていますが、スキルの 1 番には物理属性はついていません。アクターが素手で攻撃をした場合、物理属性はつくのでしょうか。実は、アクターが素手で攻撃した場合に物理属性が自動的につくようになっています (参考: `Game_Actor.prototype.attackElements`)。

### 属性によるダメージの変動

```js:rpg_objects.js
Game_Action.prototype.calcElementRate = function(target) {
    if (this.item().damage.elementId < 0) {
        return this.elementsMaxRate(target, this.subject().attackElements());
    } else {
        return target.elementRate(this.item().damage.elementId);
    }
};

Game_Action.prototype.elementsMaxRate = function(target, elements) {
    if (elements.length > 0) {
        return Math.max.apply(null, elements.map(function(elementId) {
            return target.elementRate(elementId);
        }, this));
    } else {
        return 1;
    }
};
```

攻撃属性集合のそれぞれの属性に対し、対象者のその属性の耐性を掛け算し、それらの値の中で最大の値が採用されます。例えば攻撃属性が「火」と「雷」、対象者の特性が「火 50%」、「火 150%」、「雷 100%」だとすると、火の耐性が 50% × 150% で 75%、雷の耐性が 100% なので、そのうちの大きい方である 100% が採用されます。

通常攻撃 (Normal Attack) の場合は、攻撃者の属性特性がすべて適用されるため、複数属性の攻撃になりえます。通常攻撃ではない場合、スキルやアイテムの属性 1 つだけが使われます。

## アクション結果の保存 (`Game_ActionResult`)

バトラーのアクションの結果は、 HP などのパラメータやステートの変更があったバトラー (`Game_Battler`) の `_result` (`Game_Action` オブジェクト) に格納されます。 HP やステートなどの純粋な現在の状態は `Game_Battler` の各フィールドに入るのですが、「最後のアクションの結果」は `_result` に入っているわけです。

## 結果の表示 (`Window_BattleLog` の `displayActionResults`)

```js:rpg_windows.js
Window_BattleLog.prototype.displayActionResults = function(subject, target) {
    if (target.result().used) {
        this.push('pushBaseLine');
        this.displayCritical(target);
        this.push('popupDamage', target);
        this.push('popupDamage', subject);
        this.displayDamage(target);
        this.displayAffectedStatus(target);
        this.displayFailure(target);
        this.push('waitForNewLine');
        this.push('popBaseLine');
    }
};
```

`subject` や `target` は Game_Battler オブジェクトですが、それらの `_result` (`Game_Action`) を参照して適切にアニメーションを表示します。呼び出し時点では `push` によってキュー (`_methods`) に何を実行するかが貯められ、後で順番に実行されます。

`Window_BattleLog` は単なるウィンドウではなく、サイドビューだった場合のアクターのアニメーションや、バトラーのダメージポップアップなどの処理も兼ねています。 `Window_BattleLog` については次節で軽く解説します。

# `Window_BattleLog`

`Window_BattleLog` はウィンドウクラスのなかでも面白いクラスで、命令を一旦ためて後で実行するということをしています。

```js:rpg_windows.js
Window_BattleLog.prototype.push = function(methodName) {
    var methodArgs = Array.prototype.slice.call(arguments, 1);
    this._methods.push({ name: methodName, params: methodArgs });
};
```

`push` メソッドで一旦メソッド名と引数を `_methods` にプッシュします。 `_methods` はスタックではなく FIFO なキューで、これを先頭から取り出して順番に実行していきます。

```js:rpg_windows.js
Window_BattleLog.prototype.callNextMethod = function() {
    if (this._methods.length > 0) {
        var method = this._methods.shift();
        if (method.name && this[method.name]) {
            this[method.name].apply(this, method.params);
        } else {
            throw new Error('Method not found: ' + method.name);
        }
    }
};
```

`callNextMethod` で `shift` (先頭から dequeue) して、そこに入っていた文字列名をメソッド名としてメソッド呼び出ししています。このように、命令列をあとからインタプリタ的に実行する形になっています。

```js:rpg_windows.js
Window_BattleLog.prototype.displayActionResults = function(subject, target) {
    if (target.result().used) {
        this.push('pushBaseLine');
        this.displayCritical(target);
        this.push('popupDamage', target);
        this.push('popupDamage', subject);
        this.displayDamage(target);
        this.displayAffectedStatus(target);
        this.displayFailure(target);
        this.push('waitForNewLine');
        this.push('popBaseLine');
    }
};
```

`displayActionResults` を再掲します。これは `subject` および `target` の `Game_ActionResult` オブジェクトを見て、 `push` で命令列を突っ込んでいる処理になります。

`pushBaseLine` と `popBaseLine` は現在の行を記憶する / 戻すという操作に対応するのですが、これが効いてくるのはアクター一人で二度攻撃する場合などだけだと思われます。ここらへん理解しきれていないので説明は割愛します。

`popupDamage` はアクションによって変化した HP などをポップアップで表示します。実はこれは `Game_Battler` の `startDamagePopup` に処理を委譲しているだけです。 **`Game_Battler` は純粋なモデルを表すのではなく、ダメージのポップアップ状態やアニメ状態も管理しています。** ビューであるところの `Window_BattleLog` からモデルであるところの `Game_Battler` を操作していて、最初見た時にギョッとしてしまったのですが、 `Game_Battler` は実はモデルではなくモデルとビューを兼ね備えたものだと思えばよいです。

他の処理はダメージやステートの変化をウィンドウに表示したり `Game_Battler` にアニメの指示をしたりしているだけです。

# 私見

`Scene_Battle` と `BattleManager` は責務がだいぶ被っている点が気になります。リファクタリングしてもうちょっと綺麗に分けられるのではないかと考えています。またモデルとビューが兼用になってしまっているクラスなどがあり (`Game_Battler`)、これらもちゃんと分けたほうがよいのではないかと思いました。

とはいうものの、全体として素直で大変読みやすいコードであり、解析にはさほど困りませんでした。

本当は逃走の処理、イベントの処理、ビューを解説していきたかったのですが時間切れです。それらはまた気が向いたら別の機会にやろうと思います。

発見したことを整理せず各論的に書いたため、まとまりのない記事になってしまいましたが、最後までご覧頂きありがとうございました。