メインコンテンツまでスキップ

バトル AI

MCE はバトル AI に差し替え可能なストラテジーパターンを使います。すべての AI は BattleAI ScriptableObject で、組み込みのものは連結できるよう設計されています。各戦略は自分の担当を行い、それができないときはFallback AI に判断を委ねます。

バトルのステートマシン

AI は決してバトルを動かしません。答えるのは「このトレーナーは今何をするか」という 1 つの問いだけで、 いつ尋ねるかはバトルループが決めます。この分離のおかげで、ターンの流れに触れることなく、 バトルごとに別の戦略を使えます。

アーキテクチャ​

BattleAI(名前空間 OpenMon.MCE.Battle.AI)が答えるべきことは 2 つあります。

  1. RequestPerformAction -- バトラーのターン。AI は BattleAction でコールバックします。これは何をするかを表す小さな構造体で、バトラー(BattlerType と Index)、行動の Type(Move、Switch、Item、Run)、メガフォームを発動するか(TriggerMegaForm)、数値の Parameters(どの技とどの対象、どのアイテム、どのモンスター)を持ちます。
  2. RequestNewMonster -- ひんしの後に、ロースターのどのモンスターを繰り出すか。

また、2 つの任意のフック OnBattlerFainted と OnBattleEnded もあります(ML AI が報酬のために使います)。

連鎖は、アセットがアセットを指しているだけです。

MegaOrGigaIfCan  ──Fallback──▶  SwitchToEffectiveMonster  ──Fallback──▶  PerformEffectiveMove  ──Fallback──▶  PerformRandomMove  ──Fallback──▶  RandomBattleAI

各リンクは状況を見て、条件を満たせば自分で答え、そうでなければ Fallback に尋ねます。RandomBattleAI はすべての連鎖の終点で、Fallback を持ちません。

組み込みの AI 戦略​

すべて Assets > Create > MCE > Battle > AI > ... から作成します。

アセット動作設定
RandomBattleAIランダムな技と、ランダムなモンスターへの交代のどちらかをランダムに選ぶ。最終的なフォールバックとして使う。--
PerformRandomMoveランダムな技を実行する。使える技がなければフォールバックする。Fallback
PerformEffectiveMove持っている中で最も威力の高い、効果的なダメージ技を実行する。しきい値を超えるものはすべて効果的とみなされ、効果的な技の中では複数対象のものを優先し、次に威力の高いものを選ぶ。効果的な技がない、または確率判定に失敗したときはフォールバックする。EffectivenessThreshold(デフォルト 1)、Chance(0-1)、Fallback
SwitchToEffectiveMonster効果的な技を持つパーティメンバーに、ある程度のランダム性を持って交代する。ひんしの後に繰り出すモンスターも選ぶ。EffectivenessThreshold、SwitchingChance(0-1)、Fallback
UseBattleItems特定の条件でバトルアイテムを使う(HP のしきい値を下回ったときの回復アイテム、列挙されたアイテム)。それ以外ではフォールバックする。UseIfAvailable、UseOnOwnIfAvailable、HPThreshold、HPHealItems、Fallback
MegaOrGigaIfCanフォールバックに行動を求め、バトラーが可能であれば、それをメガまたはギガフォームへの変化としてフラグを立てる。Fallback
IfWildWithRunChanceRunモンスターが野生で、その種に逃げる確率があれば、判定が成功したときに逃げる。そうでなければ次へ渡す。Fallback
MLBattleAI訓練済みの ML-Agents の頭脳に判断させる(後述)。AgentPrefab、Fallback

バトルの AI を選ぶ​

バトルの各ロースターは、1 つの BattleAI で制御されます。

  • 通常のエンカウント -- CommandGraph ノードの SingleWildFight、DoubleWildFight、SingleTrainerFight が開始する野生バトルとトレーナーバトル -- では、BattleLauncher アセットの Default AI フィールドが使われます。使いたい連鎖の先頭を指定してください。
  • バトルに独自の戦略を与えるには、BattleTemplate(Create > MCE > Battle > Template)を使います。その AIs 配列は、ロースター、キャラクター、バッグ、その他のバトルのパラメーターと並んで、ロースターごとに 1 つの BattleAI を保持します。FightFromTemplate ノードがそれを開始します。
  • コードからは、BattleLauncher.LaunchBattle(...) が AI の配列を直接受け取ります。

連鎖の例(BattleLauncher やテンプレートに割り当てる AI は、先頭に挙げたものです):

イージー(1 番道路)​

PerformRandomMove → RandomBattleAI

ミディアム(ジムのパズル)​

MegaOrGigaIfCan → PerformEffectiveMove → PerformRandomMove → RandomBattleAI

ハード(チャンピオン)​

MegaOrGigaIfCan → UseBattleItems (HP below 25%) → SwitchToEffectiveMonster → PerformEffectiveMove → PerformRandomMove → RandomBattleAI

独自の AI を書く(Source・Studio エディション)​

BattleAI をサブクラス化し、2 つの抽象メソッドを実装して、クラスに [CreateAssetMenu] を付けます。

using System;
using System.Collections;
using System.Collections.Generic;
using OpenMon.MCE.Battle;
using OpenMon.MCE.Battle.AI;
using OpenMon.MCE.Configuration;
using UnityEngine;

[CreateAssetMenu(menuName = "MyGame/AI/Always Struggle", fileName = "AlwaysStruggle")]
public class AlwaysStruggle : BattleAI
{
[SerializeField] private BattleAI Fallback;

public override IEnumerator RequestPerformAction(MCESettings settings, BattleManager battleManager,
BattlerType type, int inBattleIndex,
Action<BattleAction> callback)
{
// Ask the next link of the chain, then adjust what it answered.
BattleAction action = default;
yield return Fallback.RequestPerformAction(settings, battleManager, type, inBattleIndex,
answer => action = answer);
callback(action);
}

public override int RequestNewMonster(MCESettings settings, BattleManager battleManager,
BattlerType type, int inBattleIndex, List<Battler> forbiddenBattlers) =>
Fallback.RequestNewMonster(settings, battleManager, type, inBattleIndex, forbiddenBattlers);
}

protected ヘルパー GenerateActionForMove(...) は、選んだ Move に対する BattleAction(技スロットと有効な対象)を構築し、静的な GetEnemies(battleManager, type) は戦っている敵側のバトラーを返します。AI を所有するモジュールについては、BattleManager API を参照してください。

ML-Agents との統合​

MCE には、ML-Agents ベースの実験的な AI が含まれています。

MLBattleAI​

Unity ML-Agents を使い、訓練済みのニューラルネットワークで判断します。

  • 難易度:可変(訓練次第)
  • 用途:終盤のトレーナー、競技向け AI、研究
  • セットアップ:com.unity.ml-agents パッケージとスクリプティング define の MCE_ML_AGENTS が必要。ML のコードは専用のアセンブリ(OpenMon.MCE.ML)にあります

AI はバトラーごとに、Agent Prefab から MCEAgent を生成し、観測のベクトルを書き込み(コードには 630 個の整数が記載されています:シナリオ、両陣営の状態、4 体の場のバトラー、残りのロースター。各バトラーは、種、フォーム、レベル、個体値/努力値、特性、HP、状態、技と PP、持ち物、能力ランク、揮発性の状態で記述されます)、頭脳に離散的な判断を求め、それを BattleAction に変換します。報酬はモンスターがひんしになったときに与えられます(自分のモンスターがひんしになると -10 の一部、相手がひんしになると +100 の一部)。ひんしの後にどのモンスターを繰り出すかは学習されず、Fallback に任されます。

AI の訓練​

訓練は Unity の外で、標準の ML-Agents ツールチェーンを使って行います。MCE が提供するのはエージェント、観測、 報酬です。訓練済みモデルはご自身で作成します。

  1. 仮想環境に Python 側をインストールします:pip install mlagents
  2. エージェントのプレハブが宣言する動作(behaviour)の設定を、 ML-Agents の設定リファレンスに従って書きます
  3. mlagents-learn <設定ファイル>.yaml --run-id=<名前> を実行し、待機中と表示されたら Unity で Play を押します
  4. tensorboard --logdir results で監視します
  5. 訓練済みモデル(.onnx ファイル)をエクスポートします
  6. モデルをエージェントのプレハブに割り当てます

エンジン本体のリポジトリには、これらの手順のラッパー(MLAgentsInstall.ps1、RunMLTraining.ps1、 ViewMLResults.ps1、MLAgentsConfig/)がルートフォルダーに置かれています。これらはメンテナー用のツールであり、 どのパッケージにも含まれていません。お手元のものには入っていないため、上記の手順に従ってください。

ML-Agents への依存

ML-Agents は、独自の Python 依存関係を持つ別のパッケージです。MCE の中核となるバトルシステムはそれなしで動作します。ニューラルネットワークベースの AI を使う予定がある場合にのみ、ML-Agents をインストールしてください。

AI の難易度の目安​

難易度AI の連鎖使う場面
とても簡単RandomBattleAI のみ野生エンカウント
簡単PerformRandomMove序盤のルート、たんぱんこぞう
普通PerformEffectiveMove(タイプを考慮)ジムトレーナー、ライバル
難しいメガ + アイテム + 交代 + 効果的な技ジムリーダー、四天王
ニューラル訓練済みモデルを使う MLBattleAI競技、チャレンジモード

ベストプラクティス​

  1. AI を物語の文脈に合わせる。ありふれたむしとり少年が、チャンピオンのように戦ってはいけません。
  2. 同程度のレベルのプレイヤーのチームに対して AI をテストする。バランスの悪い AI は不公平に感じられます。
  3. 小さな戦略から連鎖を組み立てる。1 つの巨大な AI より保守しやすくなります。
  4. 連鎖は必ず RandomBattleAI で終える(または、それに裏付けられた PerformRandomMove)。そうすれば、AI が答えを出せなくなることがありません。
  5. 序盤のトレーナーの AI を過剰に最適化しない。プレイヤーは、賢い相手と対峙する前にシステムを学ぶ必要があります。