見出し画像

第三回ハッカソン参加! 技術部門3位になれました! Unityでゲーム開発支援ゲームを6時間で作ってみた

今日AITech社主催のAIハッカソン3回目に行ってきた!

12時10分から18時10分までの6時間の間にその場で発表されたテーマでAIツールを作るという大会だ。
当日昼まで一切の情報なし! 全員が事前準備出来ない状態で大会を競う。

結果でいうと、技術部門で3位になれた! うれしい!
doit! の入賞記念品をもらってにっこり大満足!

30チームの作品とプレゼンがあって、アイデア部門と技術部門で1位から3位まで入賞だったから、6/30でから5人に1人の入賞率だ。


今回作ったツールは、UnityでGoogleスプレッドシート(GAS)で個人のコーディング設定や言語を設定して、chatGPTのAPI連携でゲーム作成コードを返答するゲーム。

ゲームの中で、飛んだり跳ねたりできる空間で、優しい笑顔AI、ムキムキストロングAI、家族AIの3タイプを作って、近づいて質問するとそれぞれの個性に合わせたコード回答をしてくれる。
開発中の画像見るよりも、まず動かした方がわかると思う。 (APIは金かかるので一定期間後にキーは削除する予定)
 https://unityroom.com/games/gameshiengme

実装は、フリーアセットをぺたぺた張っていく(AIの指示に従う)
9割はchatGPT 4oにコード作ってもらった

3分の発表プレゼンシートも一人で作るから、まあ時間足りない!
全組の発表見てたけど、1/3は最後まで完成してなかった(そらそう)。

ひたすら楽してAI創作、企画始めてみます。おやつさんのFF5やり込み動画投稿から10年|すきづきん@レイキopenAI狂GPTs (note.com)

1年前に、FFやりこみレジェンドのおやつさんに触発されて、「ひたすら楽してAI創作」という企画を作って、コツコツ勉強してきた。

今日はその集大成として、AIに頼りきりでゲームを作るとどうなるか?
という企画の一つとして結果を出せたと思う。


今回の大会のすごかったところは、年齢層の広さ。
びっくりしたのが中学校三年生の方が参加していて、プレゼンも作品内容も素晴らしかった!
50代の方、先生、介護、プロンプトエンジニア、営業、様々な業種の方がチームを組んでテーマに沿った作品を出していった。

今回は勢いでUnityRoomで公開してしまったが(実はUnity動かしてテスト用のゲームが過去にある)、悔いはない。

後日、運営の方々からプレゼン動画と結果発表などが出てくると思うので、
またそこで詳しくnote記事にしていこうと思う。

今回一番頑張ったところ、非同期でスプレッドシートアクセスして、その情報とAIキャラ特性と質問から、chatGPT 4oにAPIアクセスする部分
APIキーをマスクして、下に貼り付けた。
AIに8割ベースを作ってもらい、AIモデル(gpt-4o-2024-08-06)や細かいコードは後から修正した。
(今のAIってホント賢くして、コピペで理想通りに動くからドン引き……)

using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using TMPro;
using UnityEngine.UI;
using System.Text.RegularExpressions;

using System.Collections;
public class GoogleSheetReader : MonoBehaviour
{
    public TMP_InputField questionInputField;  // 質問インプットフィールド
    public TMP_InputField sheetInputField;  // TextMeshProのインプットフィールド
    public TMP_InputField answerInputField; // ChatGPTの応答を表示するTextMeshProのインプットフィールド
    public Button sendButton;               // 送信ボタン
    public EnableMessageButton enableMessageButton;

    // スプレッドシートID
    private string spreadsheetId = "xxxxxxxxxxxxxxxxxxxxxxx"; // スプレッドシートID
    private string spreadSheetApiKey = "xxxxxxxxxxxxxxxxxxx"; // Google Sheets APIキー
    private string spreadSheetRange = "'シート1'!A1:D10";  // 取得したい範囲

    // ChatGPT APIの設定
    private string chatGptApiKey = "sxxxxxxxxxxxxxx";  // 
    private string apiUrl = "https://api.openai.com/v1/chat/completions";  // ChatGPTのAPIキー
    private string organizationId = "sukidukinn";  // Organization IDが必要な場合
    private string projectId = "HakkasonAI";   // Project IDが必要な場合

    private void Start()
    {
        sendButton.onClick.AddListener(async () =>
        {
            await GetGoogleSheetDataAndAskChatGPT();
        });
    }

    // Googleスプレッドシートからデータを取得し、ChatGPTに質問するメソッド
    private async Task GetGoogleSheetDataAndAskChatGPT()
    {
        // Google Sheets API のエンドポイントを作成
        string url = $"https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}/values/{spreadSheetRange}?key={spreadSheetApiKey}";

        // UnityWebRequestでスプレッドシートのデータを取得
        UnityWebRequest request = UnityWebRequest.Get(url);

        await request.SendWebRequestAsync();  // 拡張メソッドで非同期リクエスト

        if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
        {
            Debug.LogError($"Error: {request.error}");
        }
        else
        {
            // レスポンス内容をログに表示
            string csvData = request.downloadHandler.text;

            // カンマ区切りでデータを分割して処理
            string[] rows = csvData.Split('\n');
            string formattedText = "";

            foreach (string row in rows)
            {
                // 余計な文字を削除
                string cleanRow = row.Replace("[", "").Replace("]", "").Replace("\"", "").Trim();
                formattedText += cleanRow + "\n";
            }

            await Task.Yield(); // 確実にUIスレッドで実行
            sheetInputField.text = formattedText;

            // 取得したデータをChatGPTに送信
            string question = questionInputField.text +","+ formattedText;

            SendChatGPTRequest(questionInputField.text).ConfigureAwait(false);
        }
    }

    // 非同期のリクエストメソッド
    private async Task SendChatGPTRequest(string userMessage)
    {
        try
        {
            Debug.Log("AIタイプ: " + enableMessageButton.currentCloseCharacter);
            switch (enableMessageButton.currentCloseCharacter)
            {
                case "AISmile":
                    userMessage += "。優しく簡単な言葉説明して。";
                    break;
                case "AIStrong":
                    userMessage += "。力強く励ます口調で説明して。";
                    break;
                case "AIFamily":
                    userMessage += "。家族として愛を持って説明して。";
                    break;
            }
            string jsonData = $@"
            {{
                ""model"": ""gpt-4o-2024-08-06"",
                ""messages"": [
                    {{
                        ""role"": ""system"",
                        ""content"": ""You are an AI assistant that teaches Unity game development. Provide helpful and clear guidance on Unity programming and game design.""
                    }},
                    {{
                        ""role"": ""user"",
                        ""content"": ""{userMessage}""
                    }}
                ]
            }}";

            // UnityWebRequestの設定
            UnityWebRequest request = new UnityWebRequest(apiUrl, "POST");
            byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonData);
            request.uploadHandler = new UploadHandlerRaw(bodyRaw);
            request.downloadHandler = new DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Authorization", "Bearer " + chatGptApiKey); // APIキーをAuthorizationヘッダーに設定

            // 非同期でリクエストを送信
            var operation = request.SendWebRequest();
            while (!operation.isDone)
                await Task.Yield();

            if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
            {
                Debug.LogError("Error: " + request.error);
            }
            else
            {
                ProcessResponse(request.downloadHandler.text); // レスポンスを処理する
            }
        }
        catch (System.Exception e)
        {
            Debug.LogError("Exception during request: " + e.Message);
        }
    }

    // レスポンスデータを処理する関数
    void ProcessResponse(string responseData)
    {
        try
        {
            GPTResponse response = JsonUtility.FromJson<GPTResponse>(responseData);

            string message = response.choices[0].message.content;
            answerInputField.text = message;
        }
        catch (System.Exception e)
        {
            Debug.LogError("Error processing response: " + e.Message);
        }
    }

    // ChatGPTのレスポンスデータ構造を定義するクラス
    [System.Serializable]
    public class GPTResponse
    {
        public Choice[] choices;
    }

    [System.Serializable]
    public class Choice
    {
        public Message message;
    }

    [System.Serializable]
    public class Message
    {
        public string content;
    }
}


次回、ハッカソン4回目があればまた参加しようと思う。
2回目に2位! 3回目に3位! なら次は4位だー!(ダメだろ)


この記事が気に入ったらサポートをしてみませんか?