ルールベースAI
■概要
ルールベースAIとはルール毎に挙動を変更するAIのことで、
ルールはプログラム上では条件分岐により表現されます。
このAIはシンプルなゲームのAIに適しており、
複雑な仕様のAIを実現したい場合には不向きとされています。
●ルールの構成
全てのルールは「条件」と「挙動」の二つで構成されており、
この二つがあって初めて「ルール」として扱えます。
●サンプル
ルールベースのサンプルコードを用意しています。
・リンク
サンプル
・言語
C++
・環境
VisualStudio2015
・内容
RuleBaseAI
単純なRuleBaseAIの実装
RuleBaseAI02
ルール選択処理実装
■ルールベースの例
ルールベースを適応したAIは同じ種類のルールが同時に条件を満たすことがあります。
その場合、同時にルールを実行できないので、ルールの変更やルールの選択が求められます。
このような複数のルールが同時に条件を満たした状態のことを「競合」と呼びます。
※種類とは「移動方法」や「攻撃方法」などの挙動の内容を指します。
●競合がないケース
・シューティングの敵AIその1
・HP70%以上
一定間隔で弾タイプ1を出す
・HPが30%以上
一定間隔で弾タイプ2と3を出す
・HP30%未満
・特定部位にしかダメージが入らない
・一定間隔で弾タイプ4と5を出す
・シューティングの敵AIその2
・一定間隔で弾を撃つ
・下に移動しながら左右移動を繰り返す
(ジグザグに移動する)
上記の2つの例は特に問題がありません。
その1はHPがルール実行の条件となっており、同時に条件を満たすことがありません。
その2では同時に条件を満たすことがあるかもしれませんが、
「攻撃方法」と「移動方法」に分かれているのでに挙動に不都合は生じません。
※攻撃時は停止しないといけないという仕様があるのならば
「攻撃方法 + 移動方法」となるので同時に条件を満たした場合問題になります。
●競合があるケース
・その1(アクションゲームの敵AI)
・一定間隔で待機 => 右移動 => 待機 => 左移動を繰り返す
・プレイヤーが索敵範囲に来たら向かっていく
・その2(RPGの敵AI)
・プレイヤーの平均レベルが○○以下の場合、物理攻撃しか使わない
・HPが30%未満になった場合、10%の確率で特殊魔法を使用する
上の例は二つともルール的に同時に生じる可能性があり、
どちらも同じ種類の挙動なので、同時には実行できません。
・各例の同時発生条件
その1.
移動中にプレイヤーが索敵範囲に入ってくる
その2.
指定レベル以下で10%の特殊魔法選択が選ばれる
・問題点
その1.
左右移動と追跡が同時にできない
その2.
物理攻撃しかしてはいけないのに魔法攻撃を使う
このような同じ種類の挙動に対して同時に条件を満たした場合は
ルール自体を変更して同時に発生しないようにしたり、
実行するルールを選択して同時発生した挙動をコントロールしたりします。
■ルールの選択
「■ルールベースの例」でルールに競合が発生した場合の解決策として紹介した
ルールの選択の内容をもう少し詳しく説明します。
ルールの選択は「静的優先順位」「動的優先順位」「ランダム」「交互設定」があります。
●静的優先順位
静的優先順位は最初に優先順位を設定し、競合が発生した場合は
優先順位の高いルールの挙動を実行します。
・サンプル例
RuleBaseAI02では「ActionID~」でルール挙動の宣言をしており、
この値が大きいほうを優先して実行するようにしています。
・例
// 優先順位選択
#elif RULE_SELECT == PRIORITY_SEELCT
if (ActionIdSearchFood > ActionIdGoShop)
{
fire_rule = ActionIdSearchFood;
} else {
fire_rule = ActionIdGoShop;
}
●動的優先順位
動的優先順位は状況に応じて、優先順位を計算して順位が
高いルールの挙動を実行します。
・サンプル例
お店の距離と食べ物の距離が近いほうを優先して
実行するようにしています。
// 評価選択
#elif RULE_SELECT == EVALUTION_SELECT
if (m_FoodManager->GetNearestDistance(this) <
m_ShopManager->GetNearestDistance(this))
{
fire_rule = ActionIdSearchFood;
} else {
fire_rule = ActionIdGoShop;
}
●ランダム
競合した場合、ランダムで挙動を決定します。
・サンプル例
サンプルではお店と食べ物の選択をランダムに行っています。
// ランダム選択
#if RULE_SELECT == RANDOM_SELECT
int random = rand() % 2;
int base_shift = 1;
fire_rule = 1 << (random + base_shift);
●交互設定
競合した場合、交互に動作を実行します。
・サンプル例
サンプルではお店の挙動と食べ物の挙動の終了時に
値を保存するようにして、次回の挙動で同じ内容の
動作をしないようにしています。
// 交互選択
#elif RULE_SELECT == ALTERNATE_SELECT
if (m_BeforeSelectAction == ActionIdSearchFood)
{
fire_rule = ActionIdGoShop;
} else {
fire_rule = ActionIdSearchFood;
}