Utility Based AI
Game AI Proを読んだので、いくつかの手法を実際に実装してみたくなり、
まず utility based AIを試してみる。
これは意思決定のための方法で、
いろんな場面に適用できる。
シムズみたいなゲームであれば、
AIエージェントが次になにをするかの判断、
コマンド選択式のRPGであればエネミーのアクションの選択に、
といった具合。
Game AI Pro では
www.gameaipro.com
Section 2
9. An Introduction to Utility Theory
に詳しく書かれている。
ゲーム世界から情報を統計・取得し、
0~1に正規化されたユーティリティ値にする。
それらを変換、組み合わせを行い選択肢となるアクションのスコアを決め、
一番高いものを選択する。
(もしくはウェイトにした行動を抽選したり、同種のアクションをバケツにいれて、とか。詳しくはGame AI proに)
階段 or エスカレータ どっちで行く?エージェント
Unity上で簡単な例を作ってみた。
カプセル型のAIエージェントが階段に向かって歩いていき、
階段に近づいたときに、階段でいくか、エスカレータに乗るかの判断を行う。
階段、エスカレータそれぞれでエリア判定用のコリジョンを設定しており、
エリア内にすでにどれだけのエージェントが居るのかが判断のためのファクターとなる。
階段、エスカレータともにキャパシティの値を持っており、
現在のエージェント数をキャパシティで除算したのもが混雑度となり、
ユーティリティ値となる。
選択肢は階段かエスカレータどちらかということになるわけだが、
スコアとしては混雑していないほうがよいので
1 - [混雑度]
という変換をする。
正規化された値なのでこういう変換が簡単。
あと、このままだとリニア曲線になるので、値を二乗して二次関数になるように。
こんな感じ。
float crowdedness = (float)statictics.escalaterArea.NumberOfAgents / (float)statictics.escalaterCapacity; float score = 1.0f - Mathf.Min(crowdedness, 1.0f); return score * score;
まずはこれで階段、エスカレータでスコアを出し、
比較して意思決定を行う。
これだけだと単純すぎるので、別のユーティリティを加味するようにしてみる。
階段は長くなるほど、上るのは疲れてしんどいもの。
なので、階段の長さをファクターとし、
階段をアクションとする場合のスコアに掛け合わせる。
float crowdedness = (float)statictics.stairsArea.NumberOfAgents / (float)statictics.stairsCapacity; float hardships = Mathf.Min(1.0f, statictics.stairsLength / statictics.stairsLengthMax ); float score = 1.0f - Mathf.Min(crowdedness, 1.0f); return ((score * score) + (1.0f - hardships)) * 0.5f;
階段の最大長として想定している値で、階段の長さを除算し、
ネガティブな値に変換(1から引く)、
もともとのスコアと、平均を取るようにする。
これで、階段が長いほどスコアが下がるようになります。
階段が長いと判定されるような値に設定しておくと次のようになる。
ほとんどのケースで、エージェントがエスカレータを選ぶようになる。
実際には、階段の長さに応じて判定のための値を設定するようにし、
エージェントに疲労パラメータを追加してもよさそう。
こんなふうにパラメータを後から足せるのが非常に良い。
Game AI Proにも記述があるが、
ユーティリティ計算のためにはエディタを作るとよいようで、
実際、すべて正規化された値なので、計算方法の組み合わせで表現ができ
データドリブンに出来るので良さそうである。
プロジェクトを進めるにあたって、
ある程度Utility basedに基づいてAIを構築していくのであれば、
ノードエディタもセットで作ると良さそう。
今回試したプロジェクト
GitHub - kuriharaan/UtilityBasedAI: Experimental project for utility based AI