
【ChatGPT×SceneXplain】大乱闘AIバトルシミュレータを作成して遊んだ!【画像からファイターを自動作成してAIバトル】
◆最終的に出来るゲームの概要
先にゲームの内容を知りたい人向け。
基本の流れ
・ユーザがボタンを押下、画像をアップロード。
・画像からAIが自動的にキャラを創作。
ステータスや特殊能力、必殺技までAIが作る。
・2体以上揃ったらバトル可能。
・AIがキャラ情報から白熱のバトル内容を作成。
・勝者が一人決まる。
◆初期画面

画像を基にGPTがプロファイルを作成
◆生成されるキャラデータのサンプル

ステータス・必殺技もクールに決まるぞ
◆2~4人揃えてバトルロワイヤル!!

全くもって纏まりのない4人の戦いの行方は・・・
↓
◆戦闘結果表示画面

◆ゲーム作成のきっかけ
ある日、以下のリンクがツイッターに流れているのを目撃した。
このゲームをプレイした事が、今回のゲーム作成のきっかけだった。
◼︎AIバトラー
ChatGPTのAIジャッジで戦う異能力バトルゲーム
ドハマりした。
内容は文章で説明するよりキャラ作成ページを見せたほうが早い。
つまりこういうことだ!↓

各々が"自分の好きなキャラクター"を実現するために能力値や紹介文を直接入力し、ChatGPTへ送信。
それらファイターの戦闘結果をChatGPTが生み出すバトルシミュレーターだ。
ある人は「最高にかっこいい/かわいい」キャラを作り、ある人は「この能力あったら最強じゃね?」とインチキキャラを作り、ある人は「能力記述欄でChatGPTをハック」して強制勝利していた。(反則)
ChatGPTを土台にすることで成立した「攻略の方法を自然言語で無尽蔵に生み出せるシステム」は、とっかかりのハードルが低く、遊び方は奥深い。
コロナで寝込みながら一人でずっと対戦してた。
攻略が盛り上がっているDiscordもあり、割と盛況しているぞ!
友達に紹介したら、「小学生に戻るな」と一蹴され、一緒にやってくれませんでした。
!!!もっとこういうゲーム欲しい!!!!
ということで、自分なりにAIバトラーにはない面白さを持った、スーパーAIバトルゲームを考え、勉強がてら個人で遊ぶ用に作成してみることにした。
!!!!GO!!!!
1.自分なりのAIバトルシステムを考える
1.1.画像を使いたい!

まず、思ったのが「AIバトルに画像を使いたい」ということ。
文字だけのバトルよりは、ファイターのビジュアルが欲しくなる。
自作の絵、好きなキャラの画像、写真・・・
戦わせたいものはたくさんある。
文字情報から画像生成AIに絵を作らせるという方向を考えたものの、それで理想のファイターが出来るか?というと、そうは思えない。
生成AIのモデルに画風が左右されすぎてしまうし、どこか奇妙なものが出てくるに違いない。
なので、好きな画像や絵を使って戦わせる方向をまずは模索した。
・
・
・
すぐに答えが見つかった。
以下のChatGPTの受け答えは、試しに自作のイラスト(恥)をChatGPT*SceneXplainプラグインに解説してもらった時の画像である・・・

2の回答を見て欲しい。背景に無い森を読み取っている。
自作のイラスト↓

>少女の名前はリリア。彼女はかつて、遠くの森で一人で暮らしていた。その森は魔法で溢れており、リリアもまたその魔法を感じ取ることができる数少ない人々の一人だった。
上記の画像1枚から、ファンタジーな世界観を持つキャラ設定を導けている。
着目したいのが、画像では木が一本も生えていないのに「森に棲んでいる」と推測している所。
耳の長い金髪=エルフ=森の住人であるという知識があるのだ。
知識や観察力が必要な部分までAIはプロファイリング出来る。
これだけで、AIバトラーとはまた違ったゲームが作れると確信できた。
AIの"画像分析能力"を生かしたバトルシミュレーターを作るという方向性は決まった。
1.2.バトルロワイヤルしたい
AIバトラーにおける対戦はあくまで1vs1だった。
だが、AIならキャラが揃っていればごく自然にバトルロワイヤルが出来るのでは?と思う。
人の意思から生まれる戦略とはまた違った戦闘風景が見れるのではないか。

戦略的に立ち回る人のように、まずリンチして敵の数を減らしに行くのか、公平にみんなで殴り合うのか、情報が錯綜して訳分からんことになるのか。AIの表現する乱闘が楽しみだ。
サムスのようなファイターが生み出されたら、遠くからチャージショットを打ち続けて欲しい。(文字で表現出来るのか知らないが)
これ以上考える前に作りたくなってしまったので、次の章から早速ゲーム作りの内容に移っていく。
素人の開発過程なんて興味ねえ!という方は、3章「AI大乱闘ゲームを遊ぶ」まで飛ばして良いです。
2.ゲームシステムを作る
2.1.仕様案の策定
使うのは以下のソフト・サービス。
・Unity (WebGLビルド)
・MicroSoft Azure(実行環境・ストレージ)
・SceneXplain
・ChatGPT
このゲームは、AIバトラーのようにブラウザから気軽に遊べるようにしたい。
また、ChatGPTなどのAPIを使うこともあり、オンラインのストレージは欲しい。
更にはunityのお勉強も兼ねるぞということでwebGL形式での制作に挑戦する。
webGL形式でビルドしたunityゲームはAzureにデプロイして動かす事を目標とする。

ということで製作開始。
以下、主に壁にぶち当たった時の開発過程を紹介していこうと思う。
2.2.Unity分からん。Azure分からん。どうする?
いきなりだが、コーディング能力が全然ない。
Unityが分からない。Azureも知らん。(ゴミ)
ということでGPT-4先生に聞いてみた。


全部教えてくれるし作ってくれる!!!
ということで、開発はChatGPT先生と組んで進めました。
また、開発していく中でこのような記事も発見↓
コード内のプロンプトも励まし仕様にしました。
これのせいでトークンが増えてAPI料金が上がる・・・
GPTは抜け目のないヤツだ

2.3.画面の設計(ステータスパネル)
ひとまず、キャラクター同士の対戦ということで、対戦に必要な要素を考えて「ステータスパネル」を仮組で作成してみる。

イメージはス○ブラっぽく・・・
1つのパネルには1キャラ分のデータが入る。
各項目の詳細は以下の通り。
1.容姿についての分析
アップロードされた画像について、AIが分析して文字に起こした文章。
「青い兜を被った戦士が槍を持ち~…」といった容姿の分析が入る。
2.生い立ち
1.にて分析された容姿の情報を基に、AIがそのキャラクターの生い立ちを創作した結果。
例「彼は国を代表するドラゴンナイトであり、倒した魔物の数は数えきれない~…」といった説明が入る。
3.ステータス項目
HP,攻撃力,防御力,魔力,魔法防御力,素早さの項目を設けた。
2.の情報を基に、HPは1~9999、他は1~999の値域でAIが数値を決定。
各項目の解説は割愛するが、AIがバトルの勝敗を決定する材料として使用されるようにする。
4.特殊能力・必殺技
2,3の情報を基に、AIが特殊能力と必殺技を設定してくれる。
勝敗や戦闘の内容に大きく影響を及ぼす部分となる。はず。。
上記の通り、キャラクターのステータスや画像を表示する箱は作成できたので、次はゲームの起点となる「画像のアップロード」機能を実装していく。
2.4.Azureに画像をアップロードする機能の作成
◆UnityのWebGLビルドにおけるファイル選択ダイアログの実装
いきなりハマった落とし穴。
Unityエディタ上でアップロードする画像ファイルを選択するダイアログを出す処理は、UnityのライブラリのOpenFilePanel機能を使っていれば簡単。
開発中盤程度までそのまま進めていたのだが、途中である問題に気が付く。
WebGLビルドではOpenFilePanelがWindowsビルド向けのため使えない!
当然なんだろうが、自分にとっては大きな壁だった。
幸い、以下のブログを見つけることが出来、一命をとりとめた。
ありがとうございます。。。
ビルド環境に依存せず、ファイル選択ダイアログを実装できるというのは今後必要となる場面が多そうなので覚えておきたい。
◆Azure Blob Strageに画像をアップロードする
画像をプログラム内に取り込む手段は出来たので、Azureにアップロードするための処理を実装する。
NuGet for UnityをUnityプロジェクトへインストールし、Azure Blob Strage というSDKを使用して画像のアップロードを行えばOK。SDKあれば簡単!
以下のブログを参考にしたおかげで簡単にAzureへのアップロードコードが書けました。
https://blog.jbs.co.jp/entry/2022/08/08/125541s
Unity プロジェクト (C#) から Azure Blob Storage へファイルをアップロードするには、Microsoft が提供する Azure Blob Storage SDK for .NET を使用します。この SDK は NuGet のパッケージとして公開されています。今回は Unity プロジェクトで NuGet パッケージを管理するために、NuGetForUnity を使用します。NuGetForUnity は Unity Editor で使用できる NuGet パッケージ管理システムです。

2.5.AIに画像を渡してプロファイルの作成をしてもらう
Azureにアップロードした画像は、URLでSceneXplainAPIに送信することで、その外見の分析結果について解説文を得ることができる。
Azureへの画像アップロードが完了次第、そのURLをSceneXplainAPIに飛ばして応答となる画像解析文章を待つだけ。
UnityにおけるAPI通信のやり方はChatGPTさんが丁寧に答えてくれます。
2.1に載せたカスの設計図にもあった通り、応答を貰った後はChatGPTに解析文章を送り、それを基に生い立ちや能力を考えてもらうというシステムになっている。
2.6.GPTのfunction_call機能を用いたキャラデータの作成
容姿の分析結果を受け取ったら、次はその内容に基づいて「キャラの名前・能力・必殺技」をChatGPTに決めてもらう。
しかし、GPTの返す結果が「たまにHP項目が欠損している」とか「たまに必殺技を奥義と書いている」など、あいまいな状態だと非常に困る。
そこで、キャラクタープロファイルの作成にはChatGPTに新しく実装された機能である「function_call」機能を使用した。
以下のブログを参考にさせて頂き、作成しました。
プロンプトを送る[messages]項目とは別に存在する[functions]項目には、ChatGPTによる応答を"必ず"、指定された「ラベル名:内容」のペアでJSONファイル出力できる活用方法があるらしい。
これを活用して、2.5でSceneXplainが作成した「キャラクターの容姿分析結果」を入力情報とし、期待する応答として「キャラクターのパラメータ名:内容」のJSONフォーマットが返ってくるようなfunctionsを以下の通り作成した。
functions = new object[]
{
new
{
name = "character_profile",
description = "キャラクターのプロファイリングデータです。日本語で書かれています。",
parameters = new {
type = "object",
properties = new {
FighterID = new {
type = "string",
description = "このキャラクターのIDです。\""+fighterID+"\"です。",
},
character_name = new {
type = "string",
description = "このキャラクターの名前です。15文字以内となっています。",
},
character_background = new {
type = "string",
description = "このキャラクターの生まれ育った生い立ちや現在の状態について、日本語で300字程度の小説形式で改行を入れつつ出力してください。想像力を働かせて、物語を描いてください。キャラクターの名前はcharacter_nameと同じです。",
},
character_skill = new {
type = "string",
description = "このキャラクターの特殊能力について日本語で100字程度で書かれています。想像力を働かせて、character_backgroundの内容も踏まえて作成してください。出力する文章については、「特殊能力:特殊能力名」を冒頭にまず提示し、改行してから解説してください。",
},
character_special = new {
type = "string",
description = "このキャラクターの必殺技について日本語で100字程度で書かれています。想像力を働かせて、character_backgroundの内容も踏まえて作成してください。出力する文章については、「必殺技:必殺技名」を冒頭にまず提示し、改行してから解説してください。",
},
character_HP = new {
type = "string",
description = "このキャラクターの体力の数値です。一般的な素手の成人男性の数値は300です。character_backgroundやcharacter_skillの内容も踏まえて、1桁単位の数値で正確に能力値を見積もり、1~9999までの値で決定してください。",
},
character_ATK = new {
type = "string",
description = "このキャラクターの攻撃力の数値です。一般的な素手の成人男性の数値は100です。character_backgroundやcharacter_skillの内容も踏まえて、1桁単位の数値で正確に能力値を見積もり、1~999までの値で決定してください。",
},
character_DEF = new {
type = "string",
description = "このキャラクターの防御力の数値です。一般的な素手の成人男性の数値は100です。character_backgroundやcharacter_skillの内容も踏まえて、1桁単位の数値で正確に能力値を見積もり、1~999までの値で決定してください。",
},
character_MATK = new {
type = "string",
description = "このキャラクターの魔力の数値です。一般的な素手の成人男性の数値は100です。character_backgroundやcharacter_skillの内容も踏まえて、1桁単位の数値で正確に能力値を見積もり、1~999までの値で決定してください。",
},
character_MDEF = new {
type = "string",
description = "このキャラクターの魔法防御力の数値です。一般的な素手の成人男性の数値は100です。character_backgroundやcharacter_skillの内容も踏まえて、1桁単位の数値で正確に能力値を見積もり、1~999までの値で決定してください。",
},
character_SPD = new {
type = "string",
description = "このキャラクターの素早さの数値です。一般的な素手の成人男性の数値は100です。character_backgroundやcharacter_skillの内容も踏まえて、1桁単位の数値で正確に能力値を見積もり、1~999までの値で決定してください。",
}
},
required = new object[] {"FighterID","character_name", "character_background", "character_skill","character_special","character_HP","character_ATK","character_DEF","character_MATK","character_MDEF","character_SPD" },
}
}
}
GPTより出力されるJSON文字列の例:
{
"FighterID": "1",
"character_name": "アザレア",
"character_background": "アザレアの頬にふいた風は、鮮やかな花畑の香りを運んできました。彼女は遠い森の中で生まれ育った、一変の妖精としての特性をもつ少女です。青空のような透明な青い瞳、金髪の長い髪にはいつも一輪の蒼い花が優雅に飾られています。\n\nどこからともなくやってきた彼女の存在は、いつの間にか村の人々にとって欠かせない存在となりました。彼女の魅力は、単に外見だけではなく、内面の力も含んでいました。子供たちは彼女の優しい物語に夢中になり、大人たちは彼女の賢明な助言に感謝していました。そして、そのひとつひとつがアザレアの魅力を引き立てていました。",
"character_skill": "特殊能力:母なる大地の感覚\n\nアザレアには、自然と一体となる特殊能力があります。彼女はこれらの力を駆使することで、周囲の動植物からの微細な信号を感じ取り、それに応じて行動することができます。花が咲く時期、草が枯れる瞬間を知り、風の流れを感じ取り、雨が降る前にはそれを予知することができます。この力のおかげで、彼女は常に最適のタイミングで行動し、予期せぬ事態を未然に防ぐことができます。",
"character_special": "必殺技:花吹雪舞\n\n「花吹雪舞」はアザレアの必殺技で、彼女が自然の力を最大限に引き出し、美しくも力強い攻撃を放つ技です。彼女の周りには花びらが舞い上がり、それは強力な花の爆発に変わります。この攻撃は見た目の美しさとは裏腹に、強大な破壊力を秘めています。一度この技が発動すると、敵は息の根を止められるばかりか、深い眠りに落ちます。",
"character_HP": "750",
"character_ATK": "300",
"character_DEF": "350",
"character_MATK": "500",
"character_MDEF": "400",
"character_SPD": "450"
}
この機能は"モデル名"-0613以降のバージョンで使用できるようだ。
入力トークン数が大きすぎるとか、ひとまず考えないことにする・・・
これにより、画面上のボタンから画像を送るだけで"AIがファイター用ステータスデータを自動作成する"内部のシステムは完成した。
ここからは、受信したJSONファイルを分解して、2.3で作成したステータスパネルにデータを展開していくことになる。
ChatGPTには、集まったキャラ達で"大乱闘"を起こすために後でもう一度活躍してもらうことになる。
◆自動作成されたキャラクターを試しに見てみる。
以下は、まだ受信したJSONファイルをステータスパネルに展開できていない開発中の画像だが、いらすとやの赤い竜を見て「炎龍焦熱爆発」なる必殺技を生み出してくれてテンションが上がった。そういうノリも行けるんだ。

ほとんどの敵は逃げ出すしかない。
2.7.JSONデータを基にステータスパネルを完成させる
GPTより受信したJSONデータを分解して、ファイターのパラメータを管理するインスタンスに値を入れ込んでいく。
先程見せたように、GPTからの応答データはJSON形式で成型されているため、NewtonSoft.JSONライブラリのデシリアライズ用の関数を用いて、ファイター用のパラメータクラスインスタンスに簡単に格納できる。
function_callで生み出されたJSONだけを取り出すコードは以下の通り。
public string ExtractContent(string jsonText)
{
var jObject = JObject.Parse(jsonText);
var arguments = jObject["choices"][0]["message"]["function_call"]["arguments"].ToString();
Debug.Log(arguments);
return arguments;
}
「ラベル名:値」となっているJSONデータに対して、ラベル名と同じ名前・データ型のメンバ変数を持つクラスとなっていればOKだ。

作ったので・・・
1つのFighterクラスインスタンスに1パネルが対応する形となるため、最終的に以下の画像の通り、各フォームの値が埋まることになる。

ステータスも技も魔法タイプといった感じで良い!
2.8.バトルシミュレーター機能の実装
キャラクターのステータスが決まれば、後はそれらの情報をChatGPTに渡して戦闘の内容を創作してもらうだけとなる。
ChatGPTに戦闘内容を描画してもらうプロンプトは「AIバトラー」で学習済だ。
以下のようなプロンプトで実行した。
"以上の各キャラクターが戦闘を行います。生い立ち・特殊能力・必殺技・能力値を踏まえた上で勝敗を決定し、その戦闘過程の描写を[邂逅]、[会話劇]、[戦闘開始]、[戦闘終盤]、[決着]、[その後]の6章構成の創造性溢れる小説形式にて、2400字程度の日本語で出力してください。\n"
本当は戦闘に参加する各キャラのステータス文章を展開する下りなど、プロンプト全文は長いのだが、for文で人数分出力してるだけなので割愛。
上記の通り、入力は通常のプロンプトだが、戦闘描写の出力については2.6で説明したfunction call機能を用いて形式を指定し、章ごとに分解した形で受信することにした。
必ず以下のような流れでストーリーが進行することになる。
[邂逅]→[会話劇]→[戦闘開始]→[戦闘中盤]→[決着]→[その後]
3.AI大乱闘ゲームを遊ぶ
3.1.タイマンでテストプレイ
本来、テストプレイは2章に入れるべきかと思うが、もうほぼ遊んでるようなものなので章を分けた。
まだ、戦闘の結果を出力ログの形でコンソールからコピペするくらいしか出来ないが、ゲーム画面上に表示されているか否かの違いしかない。
戦闘描写の内容を確かめるためにも早速テストを開始!
3.1.1.タイマンバトル(テストデータ 同キャラ戦)
GPTとのAPI通信や、戦闘プロンプトが上手く動くかも分からないので、キャラ作成の手間とコストを省いたテストデータ同士でタイマン。

上記2キャラのデータをGPTに送信し、戦闘結果を得る
AIバトルシミュレータの初シミュレーションの結果は如何に・・・
↓
↓
↓
[邂逅]
ある日、森の奥深くにひときわ美しい花が咲いていました。その花を愛でるように立ち止まり、微笑むリリエン。しかし、彼女はその美しさに魅せられているうちに、自分が森に迷い込んでしまったことに気づきます。彼女があたりを見回すと、不思議な姿をしたもうひとりのリリエンがそこにいました。
[会話劇]
リリエン1: 「あなたもこの美しい花に魅了されたのですか?」
リリエン2: 「はい、私もです。自然が与えてくれる癒しを感じつつ、立ちすくんでしまいました。」
リリエン1: 「私も同じです。あなたも宮廷魔法使いなんですか?」
リリエン2: 「はい、そうです。花と魔法を愛し、自然と共に生きる魔法使いです。名前はリリエンです。」
リリエン1: 「あなたと同じ名前ですか、不思議ですね。」
リリエン2: 「確かに不思議ですね。私たちの出会いには、何か意味があるのかもしれません。」
[戦闘開始]
突然、森の中で異変が起こります。闇のエネルギーが現れ、二人を包み込みました。
リリエン1: 「どうやら、魔物が私たちに襲いかかってきたようです。」
リリエン2: 「みんなを守るために戦いましょう!」
[戦闘終盤]
リリエンたちは魔物を倒し、森を守りました。しかし、二人は力尽きて倒れてしまいます。
[決着]
倒れていたリリエンたちは、力を合わせて再び立ち上がりました。彼女たちの力はお互いに伝わり、さらに強く輝きを放ちます。そして、二人の魔法がひとつに結びつき、壮大な光が広がりました。
[その後]
魔物の撃退に成功したリリエンたちは、森の中に響き渡る拍手の音を聞きました。彼女たちの勇気ある戦いに感銘を受けた森の生き物たちの応援でした。
リリエン1: 「私たちの力が合わさったおかげで、森を守ることができましたね。」
リリエン2: 「はい、でも私たちだけではなく、森の生き物たちの力もあったと思います。」
リリエン1: 「そうですね。自然の力と共に戦うことで、より強い力を引き出すことができたのかもしれません。」
リリエン2: 「これからも、自然と共にいつでも戦えるように、力を尽くしましょう。」
彼女たちは再び手を取り合い、自然の魔法使いとして、さまざまな冒険に身を投じるのでした。"
何でこうなった。
予想外なことに、キャラ同士の戦闘が発生することはなかった。
しかしまあ、こういう揺らぎが発生することはAIに任せることの面白さの一つだとも思う。
「AとBが戦闘する」という命令に対して、
「AとBが(力を合わせて無から発生した闇エネルギーと)戦闘する」
という答えを返してきたということだ。
肝心の会話劇は正直面白くなかったが、全く同じキャラのタイマンというテストデータのため、仕方ない気がする。
それよりも、テストとしては同キャラであることを不思議なことと捉えて会話劇を展開した上、名前も「リリエン1」と自動でナンバリングして個体を識別することで、物語を読みやすくしていることに着目したい。
このまま色々な組み合わせを試して良いと思える出来だった。
強いて問題点を挙げるならば、
1.文字数が極端に少ない章がある
2.まともに戦闘が発生しない可能性がある。
3.必殺技や特殊能力を使わなかった
くらいだろうか。
1,3は、function call機能で章ごとに最低文字数を設定する他、戦闘の章で必殺技・特殊能力を活用するようにプロンプトを調整すれば良い。
2は、他の組み合わせを見ていくことではっきりするだろう。
3.1.2.タイマン2(エルフ少女 vs いらすとやドラゴン)
テストデータはひとまず卒業し、ちゃんとキャラ生成からバトルまで通しでやってみる。
今回は新しくいらすとやのドラゴンを加え、タイマンだ。
ドラゴンはファンシーな見た目に反して、非常に強い能力で生成された。

HP3500。魔力もカンストしそうだ

赤き炎竜の設定が強すぎるが・・・
バトルの結果は如何に・・・
↓
↓
↓
[邂逅]
遥かな空から、炎のように赤くまぶしい何かがアザレアの森に落ちる。轟音と共に炎を吹き上げる大穴ができ、煙の中からあらわれたのは、赤き炎竜だった。
一方、深い森の中では、アザレアが剣を手にその存在に気付いていた。生まれながらに自然と一体となり、風の囁きや草木の息づかいさえ感じ取る特殊能力を持つ彼女には、赤き炎竜の到着は予感されていたのだ。
[会話劇]
赤き炎竜の魂の炎を背に、アザレアは彼と向き合った。「なぜ、この生命に溢れた森に降り立ったの?」と問う。自然を愛し、守ることを使命とする彼女には、脅威たる彼の存在が許せず、竜の存在は彼女の心を蝕み始めていた。
「私は戦うために生まれた存在。力を試す場を求めて遍く世界を飛び回る。」と、竜は鳴動する声で答えた。
[戦闘開始]
互いが踏み出し、壮絶な戦いが始まった。風がうなり、草木が震える。一人の少女と一匹の竜の、全てを賭けた闘いが。
赤き炎竜は巨体をねじり、その口からは炎の吐息が沸きあがった。しかしアザレアは自然と一体となる力で先を見通し、剣を片手に巧みに攻撃をかわす。木々の間を駆け巡りながら、赤き炎竜の隙を伺う。
[戦闘終盤]
戦いが長時間にわたり続く中、互いの力の差は歴然として居た。赤き炎竜の火力は圧倒的で、アザレアの魔法防御力を試す。しかし、自然と一体となる彼女は、微細な信号を感じ、赤き炎竜の攻撃を避け続けていた。
必殺技、「花吹雪舞」。静寂と緊張が深まる森に、一輪の蒼い花しずかに舞い立つ。その花が美しい爆発と共に敵の息の根を止め、深い眠りへと誘う。この技が発動した時、森は幻想的な景色に包まれるだろう。
[決着]
しかし、赤き炎竜はその花が舞う瞬間、怒りと闘志を燃えさせた炎で花を焼く。「爆炎の咆哮」、全てを焼き尽くす巨大な炎がアザレアに迫る。しかし、自然と一体となる彼女は既に移動していた。「花吹雪舞」再び。深い眠りへと誘う一撃が、為す術なく赤き炎竜を包み込んだ。
[その後]
その後、アザレアは再び森に静けさを取り戻す。静かに花々を咲かせ、竜が産み落とした傷を癒す。その存在が力と敬意を同時に湛えていることを、森の住人たちは感じ取った。そして、彼女の戦った証を永遠に語り継ぐこととなった。
そして、赤き炎竜は力を試す戦いの中で自己を見つめ直し、もはや戦うだけではなく、それぞれの世界を理解する冒険者となり、世界を飛び回ることを決意した。そう、物語はまだ終わっていない。未来は未知の冒険と神秘に満ちているのだから
エルフの少女の勝利。ステータスは飾りか?
しかし、読み物としてはなかなかエキサイティングだったと思う。
クソほど強そうな赤き炎竜の必殺技「爆炎の咆哮」が「既に移動していた」でなかったことにされたのは悲しい。自然と一体になれば最強なんだろう。
3.1.1のテストタイマンとは打って変わり、必死の戦いを両者が繰り広げ、特殊能力を駆使し、必殺技も派手に打ち合ってくれた。
最後の改心展開も含め、赤き炎竜はアザレアに完膚なきまでにボコボコにされている。
プロンプト等の作りこみが浅い中で、ここまでの戦闘描写が出来るとは思っていなかったので、個人的には満足している。
しかし、ステータスの数値ですべてが決まらないのもいいかもしれないが、何回もステータス最強の赤き炎竜が負け続けるのだとしたら悲しい…
パラメータによる有利不利の重み付けはどこまで命令に組み込んでいいのか、判断が難しい所だ。
何回もトライしたいのだが、2体のキャラ作成→戦闘の一連の流れを実行した結果、0.4ドル消えてた。(?)

↓

0.4円ではなく、ドル。1$150円換算で約60円だ。ゲーセンか。
ChatGPTをコスト度外視で利用すると、こうなるらしい。。
下手にトライしまくると、お財布がイッてしまうので、ちょっとずつプレイしながらの改良が必要だ。
ちなみに、AIバトラー界隈では「ChatGPTによるバトルシミュレーションは倫理的に正しいほうが勝ちやすい」という説が囁かれているとか、ないとか。
画像を上げてGPTからバトル結果の返答をもらうという基本の流れは、満足のいくレベルになっているので、UIを整えてちゃんとしたゲームの形に仕上げていく。
直した結果は以下の通り。
◆画面一覧
・キャラ一覧画面

帯をクリックすると試合が始まる。
・戦闘待機画面

燃える炎を背に両者睨みあう(?)
・戦闘結果表示

・勝敗表示

色々と完成してきたので、どんどん遊んでいく。
3.2.三つ巴戦(ミノタウロス vs いらすとやクノイチ vs 俺)
3.1でタイマンは問題なくこなせることが分かったので、次は三つ巴戦をプレイしていく。
今回はメンバーをガラッと変えていこうと思う。
このゲームを作るにあたって、一つ考えていたのは「画像をアップロードする」というのがトリガーなら、それはそこら辺で撮った写真でも構わないということだ。
話題のネタ作りとして、友人を撮ってドラゴンと戦わせてみる。そういう遊び方も出来るはず。これは文字情報を入力するだけのバトルシミュレータでは出来ない芸当だろう。
ということで・・・

記事に載せたり勝手に戦わせる事に関して、何一つ問題がない実写の人間
=俺。
強くなれ・・・と念を込めて握った拳、その思いはAIに届くのだろうか。
その他の参戦者は以下の通りだ。
◆ミノタウロス(https://commons.nicovideo.jp/works/nc318362)

◆くのいち

↓
↓
↓

ホーク・ブラヴァード
HP:9850 ATK:920 DEF:650
生い立ち(抜粋)
>しかし、その強さとは裏腹に、女性のような一面もあると伝えられている。彼がどのようにしてこの力を手に入れ、そしてなぜ女性の形象が彼に存在するのか、真実は未だ謎に包まれている。
色々と強すぎるホーク・ブラヴァード vs 普通過ぎる女ユキカ vs 魔法大国レジスタニア()の革命家レヴァンの異色マッチ。
ホークに蹂躙されつくしてしまうのか。勝負の結果や如何に。
革命の炎、ファイアリー・レヴォルシオンの発動に期待したい。

[邂逅]
荒廃した街並みの中、分厚い闘士の影が浮かび上がる。それはかつて漫画のキャラクターであった筋骨隆々の男、ホーク・ブラヴァードだ。逆に漫画界から現実世界に足を踏み入れた彼は、巨大なハンマーを乱し、闘いを求め続けていた。その姿は絶えず揺れる筋肉と獰猛な角で語られていた。時折、女性らしい一面を覗かせる彼の姿が不思議と見える。そんな中、黒い衣装を身につけるユキカと、革命家レヴァンが彼の前に現れた。
[会話劇]
「ホーク・ブラヴァード、戦いは楽しみだけど、私たちには重たい使命があるの。それは他人を助け、励ますことよ。」とユキカは微笑みながら言った。「それを実現するためには力が必要だ。悲しみや苦しみから人々を救い出すために。それが私、革命家レヴァンの意志だ」と、レヴァンは深い眼差しで語った。ホークもそれに頷き「力こそ全てだが、その意志も力の一部だとは認めよう」と、互いに理解し合った。
[戦闘開始]
三者三様の存在感が交錯し、戦いは始まる。先陣を切ったのはホークの一撃-それは怒号とともに現れるレイジング・ハンマー。ユキカとレヴァンがその力の前に震えるも、ユキカのオーラとレヴァンの革命の炎が立ちはだかった。レヴァンの炎はユキカのオーラと混ざり、ユキカは「スーパーモチベーションブースト」で炎に力を更に与えていった。
[戦闘中盤]
そうした戦況の中盤、ホークは自身のリアリティ・シフトを発動し、一時的に戦場から姿を消した。ユキカはその隙を見逃さず、レヴァンにオーラを授ける。その力によって回復したレヴァンは、革命の炎を最高にまで上げ、必殺技「ファイアリー・レヴォルシオン」を発動。その光景はまるで夜空を照らす焚き火のようだった。
[決着]
そして、ホークが再び現れた時、眼前の光景に驚愕した。力を共有し、連携を深めたユキカとレヴァンの前では、ハンマーの一撃も効力を発揮できず、彼の怒りは振るう対象を見失っていた。最終的に、レヴァンの「ファイアリー・レヴォルシオン」とユキカの「スーパーモチベーションブースト」の組み合わせによる一撃が、ホークを倒す決定打となった。
[その後]
戦いが終わった後、ホークはその強さと女性らしさを理解し、新たな思索へと自身を突き動かすことになった。一方、ユキカとレヴァンは互いの信念と力を確認し、共に新たな戦いへと進んでゆく。そして一つの結論に達した。「力」は破壊だけではなく、「救済」のためにも使うことができるのだと。
ちょいちょい挟まれるホークの性転換願望が光る深い作品となっていたが、ユキカとレヴァンが完全にグルで肝心の勝者がよく分からない。
結果表示で見てみると・・・


勝者が一人に決まらないことがあるらしい・・・
しかし、強すぎるミノタウロスが二人の協力プレイにより倒されるという展開は面白かった。
ChatGPTは乱戦もちゃんと処理できる創作力があるようだ。
勝者が一人に決まらない点についてはプロンプトを修正し、必ず一人に決まるよう調整することにする。
3.3.バトルロワイヤル(エルフ vs いらすとや竜 vs 俺 vs ク○ウド)
3.2の内容から、実写の画像を入れたとしても、三つ巴の戦いだとしてもバトルシミュレーションは上手く行くことが分かった。
よって、ついに4人参加でのバトルロワイヤルをする時が来た。
果たしてまともに勝負がつくのだろうか。
ここで更に、新しいメンバーを加えたい。
4人対戦の大乱闘とくればあのキャラが必要だろう・・・!

ク○ウドだ!!!!!!
許して欲しい、一人で遊ぶ用のゲームだから・・・
カッコいいキャラが欲しくなったし、実際ク○ウドがどのようにAIに解釈され、戦闘するのか物凄い気になってしまった。
騎士でもなければ筋骨隆々の男でもない、謎のバカでかい剣を持っているクールなこのキャラは、一体どのようなプロファイルをされるのだろうか。
↓
↓
↓

一応3回はやり直しました。が、クラウド・ストライフ、クラウド・ストライフ、クラウドという結果に。
SceneXplain(容姿分析)では、ファイナルファンタジーという固有名詞は出るものの、クラウドであると明言していない。
それにもかかわらず、ChatGPTは絶対クラウドだと確信しているのが色々と凄い部分だ。
特殊能力:マテリアマスタリ 必殺技:オムニスラッシュ(超究武神覇斬の英訳)というのも、原作準拠な作りこみだ。
おまけ程度に載せると、以下が容姿解析の全文である。長いので飛ばした方が良いかも。
この絵は、ファイナルファンタジーの世界から飛び出したような、目がサファイアのように輝く金髪の戦士を鮮やかに描き出しています。彼の身体はしっかりとした筋肉が際立ち、力強さと機敏さを兼ね備えた存在感を放っています。それは彼のようなヒーローにとって最も重要な特徴です。彼の視線には、どんな危険が待ち受けていようとも立ち向かっていく、揺るぎない決意が感じられます。
この戦士の衣装は、ファイナルファンタジーが持つ独特のファンタジーと未来的要素の融合を証明しています。彼の鎧の複雑なデザインは、磨き上げられたメタルの装飾で引き立てられ、洗練された戦闘態勢を感じさせます。彼のブーツは頑丈で黒く、実用的なジッパーが付いており、彼が遭遇するかもしれない様々な地形を移動する準備ができています。
様々な戦闘状況に備えて、彼は強力な剣を振るっています。これは彼が引き受けるクエストへの彼の献身を象徴しています。見逃してはならないのは、彼の背中に添えられた銃です。これは彼が待ち受ける多くの挑戦に備えていることを示しています。また、興味深い点は、彼の服からぶら下がっているウルフのエンブレムのキーチェーンです。これは忠誠心や獰猛さを示唆し、彼を彼が住む世界の深い神話に結びつけています。
全体的な印象としては、ファイナルファンタジーシリーズの壮大な物語と広大な世界造りの中心にいる主人公のようです。彼の態度は、数々の試練を乗り越えてきたという感じを与え、それでいて希望の象徴としての魅力を保っています。彼の世界を定義する魔法と科学の融合を体現しています。彼の姿はただのヒーローを描いているだけでなく、驚異と謎に満ちた世界を通じた冒険に参加するように誘っています。
なぜか銃を持っているとされているが、これでも絶対クラウドらしい。
こう断言されると、クラウドは本当に銃を持っていたんじゃないか、俺の記憶違いではないかと不安になる。

最強の元ソルジャー(?)を加えたところで、いざ戦闘へ。
他のメンバーは自作エルフ、いらすとや竜、実写の俺に決めた。

絵面の混沌具合が良い。やはり赤竜はステータス上最強だ。
GPTも自作絵エルフのキャラ生成は慣れた物なのか、春心(はるこころ)と奇妙なセンスを発揮してきている。
実写の俺は怒りがテーマのようだ。レイジというのは怒りと日本男性名のダブルミーニング感があって、少し洒落ている。憎い
一体この謎の集まりで形成されたバトルロワイヤルはどうなるのだろうか。
↓
↓
↓

[邂逅]
春のそよ風が、花弁を優しく揺らす。その風を通り抜けて現れたのは、春心と名の付く美しい乙女。彼女の手には青い花が握られており、その姿からは、春の息吹を感じさせる。しかし、その平穏な風景を引き裂くように、天地を揺るがす轟音が広がる。空を覆っていたのは、赤く燃えさかる火の翼を持つ赤竜だ。その巨大な身体が試合場の空間を満たす。試合場に現れた次のファイターは、筋肉隆々としたその身体が怒りを象徴するような男、レイジ。そして最後に登場したのは、冷静な表情で剣を抱え、狼の装飾を身につけた男、クラウド。彼ら四人が揃い、試合が始まる。
[会話劇]
「頼む、戦う前に話を聞いて。私たちは自然を守る者として闘うべきだと思うの。」青い瞳で春心が望む。しかし、「たわごとを言うな!」と、赤竜が怒りをぶちまける。「ここは闘いの場だ!」続けてレイジが力強く語った。「それに、結局は最後に勝つのは我だ!」と、自信満々にクラウドが言い放つ。春心はうつむき、静かに口を開いた。「だとしても、私は自分の信じる道を進む。」
[戦闘開始]
彼女が言い終えると同時に、試合が開始された。瞬時に春心は、広範囲の植物とコミュニケーションをとり、広範囲にかけて幻想的な花畑を咲かせた。しかし、赤竜はそれに動じずに火炎を召喚、「火炎噴射」で花畑を焼き尽くした。レイジは赤竜に向かって突進し、「反抗の力」で強烈な一撃を放つ。同時に、クラウドがレイジの背後から攻撃を仕掛け、彼自身の強力な剣術で攻撃した。
[戦闘中盤]
赤竜とレイジの争いは続くも、赤竜の厚い皮膚はレイジの拳を受け止める。一方、クラウドは裏をかくように「マテリアマスタリ」を発動。そこへ春心が青い花を振り上げ、一気に「ブルームハリケーン」を放つ。治癒の風が四人に吹き抜け、それぞれの傷が癒えた。
[決着]
しかし、春心の治癒は、体力が圧倒的にあった赤竜に更なる力を与えてしまう。赤竜は再び火炎を召喚し、レイジとクラウドを焼いた。「火炎噴射」の炎は避けることができず、二人は倒れ込む。春心は赤竜に向かって花を振るが、赤竜の前には春心の力は無力だった。最後の力で再度「火炎噴射」を放つ赤竜。春心は熱波に飲まれ、勝者は赤竜となった。
[その後]
赤竜が試合場を去ると、その場には焦げた大地と倒れたファイターたちが残された。春心は体力を回復し、レイジとクラウドに駆け寄り、自身の力で治療を試みた。赤竜の勝利は認められざるを得なかったが、春心はこの後も治療を続け、春を待つ環境をつくることを誓った。

主人公ツラして色々語っていた春心(はるこころ)さん
まさかの全員回復で大戦犯に。
新参戦のクラウドも全くいいところがなかった。
「それに、結局最後に勝つのは我だ!」と言い放ちキャラ崩壊した上、オムニスラッシュを撃てずに散っていった・・・
三人の見せ場がなく、赤竜に処理されるというなかなか塩辛い勝負ではあったが、春心(はるこころ)のドジというイベントがあり、まずまずの面白さはあったのではないか。
ステータスを考慮すると、何らおかしくない結果ではある。
とはいえ、この勝負については少し物足りないイメージはある。人数に応じて制限文字数を増やすべきだろうか。
何かモヤモヤするので、同じメンツでもう一戦。

[邂逅]
春の訪れを告げるような場所、美しい花々が咲き乱れる森の中で春心は自身と自然との調和を享楽していた。そんな彼女の元に突如、赤竜が舞い降りた。その迫力に森は一瞬で静まり返り、刹那、焔は木々を焼き尽くす。遠くから、レイジとクラウドがその様子を見つめていた。
[会話劇]
「あなたたちは何者?ここは私と自然の楽園・・」自身の楽園が荒れ果てる様を見て春心は泣き叫んだ。赤竜は「力こそ全て。弱き者が消えるのは当然だ」と高笑いする。その場に乱入したレイジ。「お前は人間の生活を無視する。だからこそお前は間違っている」と怒りをあらわにし、言葉少なくクラウドも同意を示す。
[戦闘開始]
そして、四者四様のバトルロイヤルが始まった。個々の力と特性を最大限に活かすため、まず皆それぞれ距離をとり、頭脳戦を開始する。赤竜は体力と攻撃力で圧倒的なリードを得るため攻撃的に行動し、春心は自身の防御力乖離を補うため植物を使って防御壁を築く。レイジは素早く赤竜に接近しながら重い一撃を狙う。クラウドはマテリアマスタリを持ち出し、透明なバリアで自身を護る。
[戦闘中盤]
戦闘が進む中、赤竜はレイジの接近をふくび(?)と火炎で距離をとる。その局面を見守る春心とクラウド。次に春心がブルームハリケーンを纏い、クラウドがマテリアマスタリを用いて颯爽と赤竜に赴く。そのふたつの攻撃は赤竜の防御を突破し、大ダメージを与えるも直ぐに勝負がつくほどでもない。一方、レイジは距離を再調整し、必殺の拳の怒りを繰り出すよう準備する。
[決着]
しかし赤竜の反撃は凄惨だった。「ここで終わらせる」と火炎噴射を発動。レイジはそれに対して拳の怒りを放つがその火炎は強固で拳の怒りは通用せず、レイジはダウン。そこへ春心が青い花の旋風で赤竜の火炎を抑え、クラウドがその隙に赤竜の体に突っ込む。そして、「貴様を倒す!」と声をあげ、オムニスラッシュを決めた。一気に赤竜の体力が切れ、勝者はクラウドに決定した。
[その後]
戦いが終わると、春心は自然の力を利用し、荒れ果てた森を再生させた。赤竜は「力以外の何かによって敗北したとは…」と理解しつつ、彼らの前から姿を消した。クラウドは春心とレイジに向けて「助けてくれて、ありがとう」と頷き、旅を続けるためにそこを後にした。それぞれの生活に戻る四者だったが、この戦いによって何かが変わったことを彼らは知っていた。

クラウドとレイジは二人組で旅をしているかのような設定で乱入してくるし、赤竜が完全なヒール役を引き受けたせいで戦闘が赤竜 vs 三人組となっている等、ツッコミ所が多い試合だったが全員が活躍するアツいバトルだったと思う。
何より、春心(はるこころ)とレイジのサポートを受け、炎のブレスを突破したクラウドが超究武神覇斬で赤竜にトドメを刺すという展開は、先程の塩試合を経た今、期待通りだった。
ステータスで勝る赤竜が敗れるパターンとしては、先程のミノタウロス同様納得性が高いものであった。
ステータス差が開いていると結託するのだろうか?単純に人類3人と魔物の組み合わせだからだろうか。まだまだ遊ぶ余地はありそうだ。
このゲームで遊べるパターンはこれで一通り終了。
開発中にこっそり友人と以下のような遊びもやったりした。
左から、俺・友人の好きなキャラ・友人の飼い猫1・友人の飼い猫2

無憂以外の三者が削りあう中、必殺技「キャットスリープ」で寝続けていた事が勝因
十分、当初の目的である「画像を上げるだけのAIバトルシミュレータ」は完成したと個人的に思う。
予想できない試合展開は面白かった。一人遊びの道具としてはなかなかの完成度となった。

この後は感想や改善点・問題点の考察なので、蛇足みたいなものです。
長々とここまで読み進めて頂き、ありがとうございました。
よろしければ、いいねとフォローの程、お願いいたします。
4.制作を終えての感想・改善案
◆オンライン対戦したい
やっぱり、色々な人が作ったファイターと戦いたい。
しかし、記事の中でも言及した通り、APIに掛かるコストが尋常でない上、ユーザーが上げる画像によっては著作権や肖像権やら色々なリスクが発生することになるだろう・・・
遠い夢である
◆人力で介入出来る要素を増やしたい
AIがすべてを決めるのも楽しいっちゃ楽しいが、ゲームとしては人力の介入要素も欲しい。
例えば、キャラに対して「戦略カード」を選択して専用のプロンプトを与えることで、戦闘の立ち回りに少しでも影響を与えられるようにするとか。
いっそ、パ〇プロのサクセスのようにキャラを育成してパラメータを鍛えるとか。。。
特能スキルはプロンプトに追加され、有利に働くとか。
ここまでストーリーを作れるGPTなら、ランダムイベントもたくさん作れるだろう。
鍛え上げたキャラをオンラインバトルロワイヤルに送り出してみたい所だ。
AIを利用したゲームの追求は今後も考え続けていきたいところ。。。
◆コストがヤバい
コストがヤバい(2回目)
1キャラ作成文の入出力トークン数について以下にレポートを乗せる
ちなみに、開発中は全くコストのことは考えていない。
モデルは"gpt4-0613"
トークン数については、GPTAPIからのResponse内に情報が含まれているので、それを参考にする。
結果
Appearance Response: { *容姿分析の情報
"usage": {
"prompt_tokens": 401,
"completion_tokens": 686,
"total_tokens": 1087
}
}
Background Response: { *生い立ち+ステータス情報
"usage": {
"prompt_tokens": 1449,
"completion_tokens": 643,
"total_tokens": 2092
}
}
合計:3179トークン
一回実行すると、キャラ一体につき約0.09$(14円くらい?)消えていたので、詳しい計算は分からんが高すぎることは分かる。
4人作ったら60円も消える。キャラを作るだけで・・・
戦闘描画の方は全キャラ分のプロファイルデータを入力として、戦闘結果の長文を出力する都合上もっと高い。
しかし、これはすべて"日本語"でやってるが故、英語にするとトークン数は減るという。
というわけで、入力プロンプトをすべて英語にして、同じようなキャラを作成してみた結果がこちら
Appearance Response: {
"usage": {
"prompt_tokens": 345,
"completion_tokens": 761,
"total_tokens": 1106
}
}
Background Response: {
"usage": {
"prompt_tokens": 997,
"completion_tokens": 496,
"total_tokens": 1493
}
}
2596トークン
入力について、約500トークンの削減に成功した。
GPT-4のトークンの料金は以下の通り。約0.015ドルの削減となった。
入力トークンは$0.03 / 1Kトークン、出力トークンは$0.06 / 1Kトークン
料金表によると、出力も英語にすれば更なる効果が期待できる。
しかし、そこにはいくつか問題点がある。
翻訳を挟むことにより、出力されてくる文章のニュアンスが大きく変わってしまうのだ。
物語を重視するゲーム性が故に、翻訳された文章は堅苦しい上にヘンテコな物になる確率が高い。
定量的なところで言えば、文字数指定が非常に難しくなる点が挙げられる。英文の出力を行う際に、日本語に翻訳した時の文字数を指定する方法はあるのだろうか。
プロンプトのトークン量の削減は、LLMをサービスに組み込む事を考える際、重要な課題になると考えている。
単に日本語を英語にする、など小手先でどうにかする課題ではなく、専用の勉強が必要になる領域として見るべきだと感じた。
今回取り扱ったfunction_call機能など、プロンプトの技法については注意深く観察していきたい。
◆WebGLビルドを本番環境で動かした結果
ローカルのテスト環境ではちゃんと動くし、後はWebGLビルドのUnityプロジェクトをAzureにリリースするだけ。
そう思っていた・・・
以下のブログの方法を参考にしながら、CORS設定に苦戦しつつもデプロイは成功した。
◆結果

ローカルで出来ていたことが本番環境で出来ないタイプのバグが、雪崩の如く襲い掛かる。
無念、Windows64bit向けにビルドし、本当に個人用のアプリとなりました。
元々セキュリティも何も考えずに作っていた物なので、公開する気はありませんでしたが、悔いの残る形に。
タブレットで持ち運んで遊びます。
もっとWebGLを勉強してリベンジしたい。
多分すぐ出来るだろう、起動までは出来ているのだから・・・(死亡フラグ)
◆おわり
以上、画像認識力の向上・創作能力などヤバい勢いで進化するAIの力を今回のゲーム作りで実感した。
マネタイズなど大人の問題を乗り越え、一人遊び用のおもちゃではないサービスがAIで作れるようになる日を夢見つつ。。
アドバイスなどあれば、コメントお願いします!!

この記事を楽しめて頂けたら、いいね、フォローの程よろしくお願い致します。