🚀

RPG MAKER UNITEとChatGPTを連携させて簡単な脱出ゲームを解かせるテスト

2023/07/11に公開

はじめに

こんにちは。今回は、RPG MAKER UNITEとChatGPTを連携させて、簡単な脱出ゲームを解かせるテストをしてみたいと思います。部屋内のオブジェクトを調べることで手がかりを得て、出口のカギを見つけ出すことが目的です。

ゲームの概要

ゲームは以下の流れで進行します。

  1. ゲーム起動および初期イベントの表示
  2. 直前に発生したイベントのテキストとマップ内のタイル名をAPIに送信
  3. ChatGPTを用いて、どのオブジェクトを調べるかを判断
  4. UNITEがオブジェクトのマップ内座標を受け取り、キャラクターの発話と移動を行う
  5. ステップ2からステップ4までを繰り返す

ゲームの動作を確認するための動画も用意しました。
https://www.youtube.com/watch?v=qCAL0urPMyQ

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