RPG MAKER UNITEとChatGPTを連携させて簡単な脱出ゲームを解かせるテスト
はじめに
こんにちは。今回は、RPG MAKER UNITEとChatGPTを連携させて、簡単な脱出ゲームを解かせるテストをしてみたいと思います。部屋内のオブジェクトを調べることで手がかりを得て、出口のカギを見つけ出すことが目的です。
ゲームの概要
ゲームは以下の流れで進行します。
- ゲーム起動および初期イベントの表示
- 直前に発生したイベントのテキストとマップ内のタイル名をAPIに送信
- ChatGPTを用いて、どのオブジェクトを調べるかを判断
- UNITEがオブジェクトのマップ内座標を受け取り、キャラクターの発話と移動を行う
- ステップ2からステップ4までを繰り返す
ゲームの動作を確認するための動画も用意しました。
RPG MAKER UNITEの変更点
この脱出ゲームは、RPG MAKER UNITEのファイルにいくつかの変更を加えて作成しています。以下に変更点を抜粋して紹介します。なお、Unity初心者のため、間違いがある可能性がありますのでご了承ください。
Runtime/Map/SceneMap
SceneMap
は、マップ上での動きを扱う最上位のファイルだと思われます。UpdateTimeHandler
内の処理が毎フレーム呼ばれているようです。ここに、APIの処理を追加します。
IEnumerator APIGet()
{
if (_firstRequestFlag)
{
_firstRequestFlag = false;
MapManager.ResetEventText();
}
string eventText = MapManager.GetEventText();
if (_search_object_name != "none")
{
if (eventText != "none")
{
_eventTextList.Add(_search_object_name + "を調査した結果:" + eventText.Replace("\r", "").Replace("\n", ""));
}
else
{
_eventTextList.Add(_search_object_name + "を調査した結果:" + "何も見つからなかった");
}
}
Debug.Log(eventText);
APIPostData apiPostData = new APIPostData()
{
items=MapManager.GetCurrentItems(),
objects=MapManager.GetCurrentObjects(),
text=_eventTextList,
events=MapManager.GetVisibleEvent()
};
if (apiPostData.items.Count == 0)
apiPostData.items.Add("none");
string json = APIPostData.Serialize(apiPostData);
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(json);
using UnityWebRequest request = new UnityWebRequest(_url, "POST");
request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
// エラーが起きた場合はエラー内容を表示
Debug.Log(request.error);
}
else
{
// レスポンスをテキストで表示
Debug.Log(request.downloadHandler.text);
var response = APIResponse.Deserialize(request.downloadHandler.text);
if (response.utterance != "none") MapManager.SetEventForApi(response.utterance);
_moveX = response.x;
_moveY = response.y;
_search_object_name = response.name;
_canMoveFlag = true;
}
}
APIを呼び出せる条件も追加する必要があります。
// メッセージウィンドウがアクティブかどうか
HudDistributor.Instance.NowHudHandler().IsMessageWindowActive()
// キャラが移動中かどうか
MapManager.GetMovingStatus()
Runtime/Map/MapManager
MapManager
は、マップ関連の処理がまとまっているようです。マップ情報を抽出するためのメソッドを追加します。
- キャラが移動中かを判定するメソッド
public static bool GetMovingStatus() {
return _actorOnMap.IsMoving();
}
- マップ内のタイルの一覧を取得するメソッド
public static List<ObjectDataForAPI> GetCurrentObjects() {
var objectList = new List<ObjectDataForAPI>();
for (int x = 0; x <= _mapWidth; x++)
{
for (int y = 0; y <= _mapHeight; y++)
{
var tileData = new tilesDataForAPI();
var clickTileDataDict = CurrentTileData(new Vector2(x, -y)).GetTileDataDict();
foreach (KeyValuePair<string, TileDataModel> item in clickTileDataDict) {
if (item.Value != null) {
//Debug.Log (item.Key);
//Debug.Log (item.Value.name);
if (item.Key == "A") tileData.A = item.Value.name;
if (item.Key == "B") tileData.B = item.Value.name;
if (item.Key == "C") tileData.C = item.Value.name;
if (item.Key == "D") tileData.D = item.Value.name;
}
}
var objectData = new ObjectDataForAPI()
{
x=x,
y=-y,
tiles=tileData
};
objectList.Add(objectData);
}
}
return objectList;
}
- 任意のイベントを発生させるメソッド(キャラクターの発話に使用)
public static void SetEventForApi(string text) {
MapEventExecutionController.Instance.TryToApiEvent(text);
}
- 座標指定でキャラクターを移動させるメソッド
public static void TryToMoveCharacterXY(int positionX, int positionY) {
// TryToMoveCharacterClickを参考に実装したため割愛
}
Runtime/Map/MapEventExecutionController
MapEventExecutionController
は、マップ上でのイベントの発生を管理するファイルのようです。TryToTalkToEvent
を参考に、テキストを指定してイベントを発生させるメソッドTryToApiEvent
を追加しました。
Runtime/Event/Message/MessageTextOnLineProcessor
MessageTextOnLineProcessor
は、イベントのテキストを表示させる場所です。最新のイベントのテキストをMapManager
で利用できるようにする処理と、メッセージウィンドウを4秒後に消す処理を追加しました。
おわりに
リリースされてから日も浅く、情報がほとんどないため、試行錯誤にかなり時間がかかりました…。
もっと良い方法や、アドオン化する方法があれば知りたいです。
お楽しみいただければ幸いです!
(※ ChatGPT側の処理の紹介は、今回は割愛させていただきます。)
Discussion