【ウディタ講座】SRPGをつくろう! AIづくりの下準備

いよいよAIづくりの第一歩です。

あなたはSRPGというジャンルを目指すからには歯ごたえあるゲームが好きなはずですし、賢いAIでプレイヤーに高度な頭脳戦を仕掛けたいと思われているかもしれません。

コモンイベントなどを整えながら、実際にどんなAIが作れそうか考えていきましょう。

MEMO
データベース(CDB)構成のときと同様、ここも多種多様なやり方があるでしょう。ここでは「なんちゃってAI」ぐらいのシンプルなものを目指したいと思います。

AIの仕様をざっくり決める

先達の開発日記に学ぶ

「ウディタでSRPGをつくろう!」シリーズではその名の通りウディタでSRPGを作ろうとしていますが、すでにその偉業を成し遂げられた方々が数多くいらっしゃいます。

【まとめ】ウディタ製SRPG8選+α

こちらの記事で筆者が参考にさせていただいた作品をまとめておりますが、フリーゲームとしてご作品を発表し、なおかつ詳細な開発日記をつけられている方も少なくありません。

これらを拝見するだけでも、かなりのものが見えてきそうです。

『フェアリーズエメラルド』のとちさん

参考 敵のAIゲーム製作記録

これ、攻撃範囲内ならHPが一番高い奴を狙うっていう設定なんです。
つまり、敵軍は大雑把に言うと手加減してた(!?)んですね。

また、移動時に山や壁にはさまれるのは、
1ターンで動ける移動力によって一番近寄れるマスへ移動という設定をしてました。
直線距離で一番近い位置へ移動していたが為、動けなくなっていたんですね。
それを数ターン分の移動力で判断するようにしました。
(その分、ちょいとお時間を戴くコトになっちゃうんですが、)

例えば、機動力が低いはずの海賊の移動力計算がフリーズと勘違いするほど長く掛かるとか、

他のユニットは海の上まで計算しないのですが、
海賊は海の上も計算するんで時間かかるんですね。
あ、いまはちゃんと対策してますんで大丈夫です。

参考 まだまだ思考ルーチンゲーム製作記録

こちらにはAI関係のコモンイベントのスクショ。コメント(メモ)がびっしりです。

 

『グラン内戦記』のロビンさん

参考 グラン内戦記のあとがき2グラン王国第二歴史研究所

覚えている限りかかった時間は・・・
①SRPGの基礎   2ヶ月
②移動範囲表示  2ヶ月
③AI         1年

開始から半年くらいでなんとか【動く】ようにできました。
しかしこのときのAIは1ユニットあたり計算だけで0.3秒かかってました。数が少ないうちは気になりませんが、30ユニットを越えたあたりからはストレスを感じるようになります。(中略)
ちなみにこのAIを作り始めた当初は頭のいいAIを作ろうとしてました。プレイヤーの【釣り】を見破ったり、次のプレイヤーの行動を見越した位置に移動したり、壁を作ったり・・・
あっ、もちろん無理でしたのでグランのAIはこんなに賢くないです。

 

先達の開発日記を拝見してわかること

  • 賢いAIづくりには限界がある
  • 数ターンぶんの移動力で計算すると、AIの賢さがあがる
  • 移動力が高い/特殊な地形も踏破できるユニットは処理負荷が高い
  • AIが賢くなるほど計算の待ち時間が増え、プレイヤーのストレスになる

 

コンシューマーのSRPGに学ぶ

本記事のSRPGはFE(ファイアーエムブレム)ライクを目指しています。

FEは3DSの『覚醒』からライト層にもやさしいカジュアルさを強めて大成功したそうで、自軍ユニットをオート操作できる機能も追加されています。どんなものがあるのでしょうか。

「おまかせ」機能

  • 護衛!(リーダーの周囲で戦う)
  • 突撃!(手近な敵に突っ込んでいく)
  • 追従!(リーダーの近くで、なるべく敵の射程に入らないように移動)

 

また、『覚醒』『if』に続く3本目の3DS作品である『エコーズ』にも類似の機能がありますが、こちらはリメイク前の『FE外伝』からすでにあった「号令」システムのリファインです。

「号令」機能

  • 全力(手近な敵に突っ込んでいく)
  • 遊撃(合理的に行動を決定。未詳)
  • 後退(敵から離れる)
  • 集合(リーダー付近に集まる)

 

実際に使ってみると期待するほど賢くはないのですが、マップが単純な場合なんかは過不足なく動いてくれるように感じます。

種類もしぼられていて各方針も明瞭ですから、さきほどのフリゲSRPG開発日記からの知見も踏まえると、これぐらいのことはなんとか「なんちゃってAI」として仕立てられるのではないか? と思えてきます(作ろうとしているのは敵の思考ですが)。

なんちゃってAIの仕様まとめ

というわけで、こんなイメージでやっていこうと思います。

なんとか実現できそうなAIの挙動

  • 特定の地点やユニット(リーダーなど)を目的地とする(動かない=初期位置が目的地)
  • 攻撃可能範囲内では倒しやすそうな方を優先して攻撃
  • 移動時は2~3ターン(回)分の移動力で考える

 

AIコモンを受け入れられるようにデータを整える

ユニットを増やして、各種コモンを対応させる

自軍と敵軍をそれぞれ2体ずつにしてみましょう。

また、主人公は透明にしてしまい、すべてのユニットをマップイベントで扱うことにしました。

マップイベントをさらに配置し、例の初期配置用処理の内容も4体分に対応させます。せっかくなので両軍の2体目はどちらも夕一(移動タイプが飛行のクラス)で射程2とします。HPにも差をつけておくといいですね。

 

以前掲載した「ユニット番号と知りたい項目を入力すると、結果を返してくれるユニットデータ取得用のコモン」も整えて、ユニット操作や移動力計算では実際にCDBから値を拾ってくるようにしておいてください(今は移動力、射程、HPぐらいでOK)。

 

また、移動や待機からの復帰で命令を出すべきイベントIDの取得は、ユニットのCDB格納座標にいるイベントのIDを「変数+」で調べればいけるはず。

「┃┣指定マスにあるEvID取得」コモン

■イベントの挿入[名]: CSelf10[所属] = [“┃┣ユニットの所属を取得”] <コモンEv 31> / \cself[0] ■イベントの挿入[名]: CSelf11[番号] = [“┃┣ユニットの番号を取得”] <コモンEv 32> / CSelf0[ユニット番号] ■変数操作: CSelf10[所属] += 1 + 0
■DB読込(可変): CSelf12[X] = 可変DB[ CSelf10[所属] : CSelf11[番号] : 存在X ] (- : – : ? )
■DB読込(可変): CSelf13[Y] = 可変DB[ CSelf10[所属] : CSelf11[番号] : 存在Y ] (- : – : ? )
■変数操作+: CSelf4[結果] = X:CSelf12[X] Y:CSelf13[Y]のイベントID

このコモンにユニット番号を入力すると、対応するマップイベントのIDが返ってきます。そのマップイベントIDに対してキャラ動作やキャラエフェクトをかければOK。

マップイベント同士が重なっていると「変数+」では小さい方のIDを優先するので、なるべくイベント同士がおなじマスに重なって存在する状況は避けましょう。

 

ざっくり書き飛ばしていた「指定の勢力のユニットの待機状態と暗化を解除する処理」も次のようになります。途中までは生存者カウントと同じ仕組みですね。

「┃┣待機解除」コモン

■DB読込(可変): CSelf10[データ数] = 可変DB[タイプCSelf0[対象](-)のデータ数] ■変数操作: CSelf11[読み位置] = -1 + 0
■回数付きループ [ CSelf10[データ数] ]回
|■変数操作: CSelf11[読み位置] += 1 + 0
|■DB読込(可変): CSelf12[HP] = 可変DB[ CSelf0[対象] : CSelf11[読み位置] : HP ] (- : – : ? )
|■DB読込(可変): CSelf13[出撃フラグ] = 可変DB[ CSelf0[対象] : CSelf11[読み位置] : 出撃フラグ ] (- : – : ? )
|■条件分岐(変数): 【1】 CSelf12[HP] が 1 以上
|-◇分岐: 【1】 [ CSelf12[HP] が 1 以上 ]の場合↓
| |■条件分岐(変数): 【1】 CSelf13[出撃フラグ] が 1 と同じ
| |-◇分岐: 【1】 [ CSelf13[出撃フラグ] が 1 と同じ ]の場合↓
| | |▼ ↑ここまで生存者カウントとおなじ
| | |▼
| | |■可変DB書込:DB[ CSelf0[対象] : CSelf11[読み位置] : 行動フラグ ] (- : – : ? ) = 0
| | |■変数操作: CSelf14[ユニット番号] = CSelf0[対象] – 1
| | |■変数操作: CSelf14[ユニット番号] *= 100 + 0
| | |■変数操作: CSelf14[ユニット番号] += CSelf11[読み位置] + 0
| | |■イベントの挿入[名]: CSelf15[EvID] = [“┃┣指定マスにあるEvID取得”] <コモンEv 16> / CSelf14[ユニット番号] | | |■キャラエフェクト:キャラ[CSelf15[EvID]][点滅B(自動フラッシュ)] R0/G0/B0 (0)フレーム
| | |■
| |◇分岐終了◇
| |■
|◇分岐終了◇
|■
◇ループここまで◇◇

 

UDB「AI」の項目を整える

上記の通りにイメージした内容に合わせて、必要そうな判断フラグを適当に増やしてみました。

まだ実際には使いませんので、下書きぐらいのつもりでざくざくと。

おなじ「攻撃する」設定でも、目的地(優先して移動する場所)を変えるだけで「ボスのように陣地をじっと守る」、「自軍のリーダーに付き従う」、「とにかく手近な敵を狙っていく」などと見え方が変わってくることがわかります。

単純なフラグの組み合わせでバリエーションを作ることができそうです。

手動で敵を動かしてみる(AIコモンのさわりをつくる)

「■AI処理」というコモンがおおもととします。

このコモンに入力された番号のユニット1体1体が、なんやかんや考えて「動作内容のリスト(文字列変数)」を決めることになるのでしょう。

仮に、「┗指示リストの実行」というコモンがその「動作内容リスト」を解読して、実際にユニットの行動(移動や攻撃)を実行すると考えてみましょう。

 

動作内容リストの書き方は、次のようになりそうです。

  • 移動先X座標(移動しない場合は、元居た座標を指定)
  • 移動先Y座標(同上)
  • 待機外の行動内容と対象(攻撃など。待機は最後に必ず行うので指示不要)
  • 3行目の行動の対象となるユニット番号

1ターンめの敵フェイズでこんなふうに動いてもらうとします。

  • 201の赤スライムは上に1マス移動
  • 202の赤い夕一(ニワトリ)は右3マス移動し、101の青い人(ウルファール)に攻撃

ということは、ユニット201と202に出す指示内容はこうなります。

  • 201(元座標6,7)への命令=「6/6/」(3行め以降無し)
  • 202(元座標9,9)への命令=「12/9/攻撃/101」

※ここでは仮に「/」で改行を表示。

「┗指示リストの実行」コモンの中身がこんな感じ。

(便宜上、「┣■移動力計算」コモンをここで呼び出していますが、本来は「■AI処理」コモンのなかで先に呼び出しておくとよいでしょう)

それでは、敵軍ターンが来たら201と202に上の指示文をそれぞれ送って動かすようにしてみましょう。

リストで指定した通りに動いてくれましたね。

ということは、あと必要なのは「UDBからAIの動作フラグを読み取って、動作内容のリストを自分で考えるコモン」です。

 

それでも賢いAIを作りたい! という方に

こちらがオススメです。

ビデオゲーム(テレビゲーム)発展の歴史とともに、どのようなAIが求められ、派生・発展していったのかがまとまっています。面白。

 

また、JavaScriptのコードがわかる方向けになりますが、こちらは実際にSRPGで豊富な作例がある作者さんによるソースコードの開陳です。

TinySRPG アルゴリズムブック JavaScriptのコードで学ぶ シミュレーションRPGの処理(DLsiteへ)

 

 

 

【ウディタ講座】SRPGをつくろう! まとめ

コメントはお気軽にどうぞ!