みかづきブログ・カスタム

基本的にはちょちょいのほいです。

Networking.UnityWebRequestを使って、CubeがクリックされたときにローカルサーバからJSONをGETする 🎁

  1. Cubeがクリックされたことを検知
  2. HTTPリクエスト(GET)でJSONの取得 👈 今回はここ
  3. HTTPリクエスト(POST)でJSONの送信
  4. WebSocketによる通信

前回の続きです。
今回はCubeがクリックされた際に、HTTPリクエスト(GET)でJSONを取得します。
Unityアプリに加え、今回はNode.jsでサーバも作ります。

開発環境

  • Unity 2022.3.36f1
  • Node.js v22.4.0

Unityの修正

スクリプトの差し替え

Assets/Scripts/GetClient.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class GetClient : MonoBehaviour
{
    [SerializeField] private string url = "http://localhost:8000/message";

    private class Response
    {
        public string message;
    }

    public void OnClick()
    {
        StartCoroutine(GetRequest(url));
    }

    IEnumerator GetRequest(string url) {
        using (UnityWebRequest webRequest = UnityWebRequest.Get(url))
        {
            yield return webRequest.SendWebRequest();

            if (webRequest.result == UnityWebRequest.Result.Success)
            {
                var response = JsonUtility.FromJson<Response>(webRequest.downloadHandler.text);

                Debug.Log(response.message);
            }
            else
            {
                Debug.Log(webRequest.error);
            }
        }
    }
}

スクリプトを作成し、Cubeにドラッグ&ドロップします。

前回、PointerClickには「ClickTarget > OnClick()」を設定していましたが、「GetClient > OnClick()」に差し替えます。

httpの許可

今回は自分で作ったローカルサーバと通信する前提なので、HTTPリクエストを許可してしまい、HTTPでサーバを立てます。

Edit > Project Settings... > Player > Other Settings > Allow downloads over HTTP* を「Always allowed」にすればOKです。

URLがhttp://localhost:3000でよければ、ここの設定は不必要なのですが、のちに同一ネットワークの別PCからIPアドレスを指定して叩くことを考慮し、今のうちに設定しておきましょう。

サーバの作成

package.json

{
  "name": "unity-network",
  "version": "1.0.0",
  "main": "app.mjs",
  "scripts": {
    "start": "node app.mjs"
  },
  "dependencies": {
    "express": "^4.19.2"
  }
}

app.mjs

import express from 'express';
import { createServer } from 'node:http';

const __dirname = import.meta.dirname; // 後述
const app = express();
const http = createServer(app);

app.use(express.json());

app.get('/message', (req, res) => {
  res.send({
    message: 'Ya-Ha-!'
  });
});

http.listen(8000);

Expressを使って、localhost:8000/messageにアクセスがあった際に、

{
  message: 'Ya-Ha-!'
}

を返すだけのサーバを作り、

npm start

で起動します。



これで準備OKです。

挙動確認

Unityを実行し、Cubeをクリックするとログに「Ya-Ha-!」と表示されることが確認できます。

解説

__dirnameの取得

今回は、__dirnameを、

const __dirname = import.meta.dirname;

と取得するために、Node.js v22.4.0を使いました。
執筆時のLTSはv20.15.1なのですが、v20.15.1だとこの記法は使えません。
どうやら、v21.2.0から使えるようになったようです。

nodejs.org

v21.1.0以前で__dirnameを取得する場合は、

import path from 'node:path';
import url from 'node:url';

const __dirname = path.dirname(url.fileURLToPath(import.meta.url));

これでOKです。
もしくは、.mjsをやめて、.jsにしてしまうのが手取り早いかもしれません。

JSONのパース

Assets/Scripts/ClickTarget.cs(抜粋)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class GetClient : MonoBehaviour
{
    private class Response // JSONをクラス化しておく
    {
        public string message;
    }

    IEnumerator GetRequest(string url) {
        using (UnityWebRequest webRequest = UnityWebRequest.Get(url))
        {
            yield return webRequest.SendWebRequest();

            if (webRequest.result == UnityWebRequest.Result.Success)
            {
                var response = JsonUtility.FromJson<Response>(webRequest.downloadHandler.text); // JsonUtilityを使ってJSONをパース

                Debug.Log(response.message);
            }
            else
            {
                Debug.Log(webRequest.error);
            }
        }
    }
}

昔は、MiniJSONを使っていた気がするんですが、JsonUtilityというクラスを発見したので、使ってみました。

docs.unity3d.com


今回は以上です。
次回はCubeをクリックした際に、HTTPリクエストでJSONをPOSTします。