いろいろとデータを調整する
この章で学ぶこと
いろいろとデータを調整する
- シンプルに動かしてみる
- 受け取ったデータをあいさつ文テキストに反映してみる(ResponseData.title)
- 自分の名前を送っていてサーバーであいさつ文を作っていることを確認(RequestData.name)
- 受け取ったデータをポイント加算に反映してみる(ResponseData.add_point)
- 実は term1-2 chapter02 のデータを JSON でまとめたことを確認
- ゲームポイントの記録を確認(RequestData.point)
- ゲームポイントの記録が成功すると記録ポイントが返ってくるのでテキストに反映してみる(ResponseData.recordPoint)
- 初期起動時の API で記録ポイントが表示されていることを確認
- 実はサーバーが起動している間、記録ポイントは保持されていることを確認
- 初期起動時に受け取った記録ポイントを反映すれば再開できることを確認
- 再起動して記録ポイントが初期化されることも確認
Codespace の起動
GitHub にログインした状態で https://github.com/codespaces にアクセスします。
Codespaces のページです。さきほど使っていた Codespace をクリックして起動します。
サーバの起動
- ターミナルで
node term1-3-chapter02.js
をサーバ起動 - ポートタブで今回のサーバ起動を公開
- シークレットウィンドウで今回のサーバが公開されているか確認します
こちらの手順を進めます。
✅ポイント
- 今回は POST リクエストで 2 つの仕組みを作っています
/api/post/result
というパスでは、現在のポイント受信して記録。さらに今記録したものを返答。/api/post/init
というパスでは、初回ロード時にいろいろな情報をもらいます。recordPoint
という現在のポイントを記録する変数もあります。- サーバープログラム内の変数なのでメモリで動いています
- これはサーバを再起動すると初期化されますが起動している間は記録してくれています
- 受信した現在のポイントを記録にも注目
- あいさつ文の値の流れにも注目
今回の Unity シーンを起動
Project タブから Assets > Scenes を選択します。Scene-Term1-3-Chapter02 をダブルクリックして起動しましょう。
今日は、このプログラムをベースに、送る値や受け取る値を Unity に使っていきます。
✅ポイント
- ClickPart が Term1-2 Chapter02 に近い仕組みでクリックしたらポイントが加算されたり、初回ロード時にいろいろな情報をサーバの
/api/post/init
から受け取っています。 - SendButton が Term1-3 Chapter01 とほぼ同じ仕組みで ClickPart の得たポイントをサーバの
/api/post/result
に送っています。
Term1_3_Chapter02_ClickPart.cs 変更
Assets/Scripts/Term1_3_Chapter02_ClickPart.cs
をエディタで開きます。
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections; // IEnumerator のための参照
using UnityEngine.Networking; // UnityWebRequest のための参照
using System.Text; // Encoding のための参照
using System; // Serializable のための参照
public class Term1_3_Chapter02_ClickPart : MonoBehaviour, IPointerClickHandler
{
// 受信した JSON データを Unity で扱うデータにする ResponseData ベースクラス
[Serializable]
public class ResponseData
{
// result というプロパティ名で string 型で変換
public string result;
}
// 送信する Unity データを JSON データ化する RequestData ベースクラス
[Serializable]
public class RequestData
{
// 自分の名前
// name というプロパティ名で string 型で変換
public string name;
}
// アクセスする URL
// サーバー URL + /api/post/init
string urlGitHub = "ここにサーバーURLを入れる";
// ポイント加算設定
int addPoint = 1;
// 蓄積ポイント
public int currentPoint = 0;
void Start()
{
// 起動時にデータを読み込む
// HTTP リクエストを非同期処理を待つためコルーチンとして呼び出す
StartCoroutine("RequestInit");
// 蓄積ポイントのリセット
currentPoint = 0;
}
public void OnPointerClick(PointerEventData eventData)
{
// マウスクリックイベント
// Debug.Log($"オブジェクト {this.name} がクリックされたよ!");
// ポイント加算
currentPoint += addPoint;
// テキストに反映
string infomation = currentPoint + "pt";
GameObject.Find("CurrentPointMessage").GetComponent<TextMesh>().text = infomation;
}
// リクエストする本体
IEnumerator RequestInit()
{
// HTTP リクエストする(POST メソッド) UnityWebRequest を呼び出し
// アクセスする先は変数 urlGitHub で設定
UnityWebRequest request = new UnityWebRequest(urlGitHub, "POST");
// ResponseData ベースクラスを器として呼び出す
RequestData requestData = new RequestData();
// データを設定
// requestData.name = "まいねーむ"; // 自分の名前
// 送信データを JsonUtility.ToJson で JSON 文字列を作成
// pointRequestData の構造に基づいて変換してくれる
string strJSON = JsonUtility.ToJson(requestData);
Debug.Log($"strJSON : {strJSON}");
// 送信データを Encoding.UTF8.GetBytes で byte データ化
byte[] bodyRaw = Encoding.UTF8.GetBytes(strJSON);
// アップロード(Unity→サーバ)のハンドラを作成
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
// ダウンロード(サーバ→Unity)のハンドラを作成
request.downloadHandler = new DownloadHandlerBuffer();
// JSON で送ると HTTP ヘッダーで宣言する
request.SetRequestHeader("Content-Type", "application/json");
// リクエスト開始
Debug.Log("リクエスト開始");
yield return request.SendWebRequest();
// 結果によって分岐
switch (request.result)
{
case UnityWebRequest.Result.InProgress:
Debug.Log("リクエスト中");
break;
case UnityWebRequest.Result.Success:
Debug.Log("リクエスト成功");
// コンソールに表示
Debug.Log($"responseData: {request.downloadHandler.text}");
// ResponseData クラスで Unity で扱えるデータ化
ResponseData responseData = JsonUtility.FromJson<ResponseData>(request.downloadHandler.text);
// MessageText に結果テキスト割り当て
GameObject.Find("StatusMessage").GetComponent<TextMesh>().text = responseData.result;
break;
}
}
// Update is called once per frame
void Update()
{
}
}
以下を修正します。
// アクセスする URL
// サーバー URL + /api/post/init
string urlGitHub = "ここにサーバーURLを入れる";
こちらをサーバー URL に /api/post/init
というパスを加えて変更して保存します。
解説します。
今回は Term1-2 Chapter02 に近い仕組みで作られています。
// 受信した JSON データを Unity で扱うデータにする ResponseData ベースクラス
[Serializable]
public class ResponseData
{
// result というプロパティ名で string 型で変換
public string result;
}
受信した JSON データを Unity で扱うデータにする ResponseData ベースクラスを用意して、「ひとまず」result 値だけ Unity の値として扱えるようにしています。「ひとまず」としたのは、
{
"result":"OK",
"title":"こんにちは!ようこそ!", // あいさつ文
"add_point":1, // 加算ポイント
"recordPoint":0 // 記録している現在のポイント
};
他のデータも受け取れるため、あとで拡張するためです。JsonUtility はクラスで準備した以外のデータを受け取っても、無視されるので、このようなことができます。
// 送信する Unity データを JSON データ化する RequestData ベースクラス
[Serializable]
public class RequestData
{
// 自分の名前
// name というプロパティ名で string 型で変換
public string name;
}
送信する Unity データを JSON データ化する RequestData ベースクラスでは、サーバに自分の名前を name という値で送れるよう準備しています。
// ResponseData ベースクラスを器として呼び出す
RequestData requestData = new RequestData();
// データを設定
// requestData.name = "まいねーむ"; // 自分の名前
最初に動かすときは name 未設定なので {"name":""}
と空の文字列で動作します。コメントアウトすると requestData.name = "まいねーむ";
の部分が動作するので、サーバが出来る title の値が こんにちは!ようこそ!
から こんにちは!まいねーむさん、ようこそ!
と動作します。
あとは、POST リクエストを行っています。
Term1_3_Chapter02_SendButton.cs 変更
Assets/Scripts/Term1_3_Chapter02_SendButton.cs
をエディタで開きます。
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections; // IEnumerator のための参照
using UnityEngine.Networking; // UnityWebRequest のための参照
using System; // Serializable のための参照
using System.Text; // Encoding のための参照
public class Term1_3_Chapter02_SendButton : MonoBehaviour, IPointerClickHandler
{
// Term1_3_Chapter01_CubeEvent とほぼ同じ
// 受信した JSON データを Unity で扱うデータにする ResultResponseData ベースクラス
[Serializable]
public class ResultResponseData
{
// result というプロパティ名で string 型で変換
public string result;
}
// 送信する Unity データを JSON データ化する PointRequestData ベースクラス
[Serializable]
public class PointRequestData
{
// point というプロパティ名で int 型で変換
public int point;
}
// アクセスする URL
// サーバーURL + /api/post/result でアクセス
string urlGitHub = "ここにサーバーURLを入れる";
public void OnPointerClick(PointerEventData eventData)
{
// マウスクリックイベント
// Debug.Log($"オブジェクト {this.name} がクリックされたよ!");
// HTTP リクエストを非同期処理を待つためコルーチンとして呼び出す
StartCoroutine("PostPointData");
}
// POST リクエストする本体
IEnumerator PostPointData()
{
// HTTP リクエストする(POST メソッド) UnityWebRequest を呼び出し
// アクセスする先は変数 urlGitHub で設定
UnityWebRequest request = new UnityWebRequest(urlGitHub, "POST");
// PointRequestData ベースクラスを器として呼び出す
PointRequestData pointRequestData = new PointRequestData();
// データを設定
pointRequestData.point = 1000; // ダミーで 1000 pt のゲーム結果を送る
pointRequestData.point = GameObject.Find("ClickPart").GetComponent<Term1_3_Chapter02_ClickPart>().currentPoint;
// 送信データを JsonUtility.ToJson で JSON 文字列を作成
// pointRequestData の構造に基づいて変換してくれる
string strJSON = JsonUtility.ToJson(pointRequestData);
Debug.Log($"strJSON : {strJSON}");
// 送信データを Encoding.UTF8.GetBytes で byte データ化
byte[] bodyRaw = Encoding.UTF8.GetBytes(strJSON);
// アップロード(Unity→サーバ)のハンドラを作成
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
// ダウンロード(サーバ→Unity)のハンドラを作成
request.downloadHandler = new DownloadHandlerBuffer();
// JSON で送ると HTTP ヘッダーで宣言する
request.SetRequestHeader("Content-Type", "application/json");
// リクエスト開始
yield return request.SendWebRequest();
// 結果によって分岐
switch (request.result)
{
case UnityWebRequest.Result.InProgress:
Debug.Log("リクエスト中");
break;
case UnityWebRequest.Result.Success:
Debug.Log("リクエスト成功");
// コンソールに表示
Debug.Log($"responseData: {request.downloadHandler.text}");
// ResultResponseData クラスで Unity で扱えるデータ化
ResultResponseData resultResponse = JsonUtility.FromJson<ResultResponseData>(request.downloadHandler.text);
// MessageText に結果テキスト割り当て
GameObject.Find("StatusMessage").GetComponent<TextMesh>().text = resultResponse.result;
break;
}
}
}
以下を修正します。
// アクセスする URL
// サーバーURL + /api/post/result でアクセス
string urlGitHub = "ここにサーバーURLを入れる";
こちらをサーバー URL に /api/post/result
というパスを加えて変更して保存します。
解説します。
今回はTerm1_3_Chapter01_CubeEvent とほぼ同じプログラムです。SendButton をクリックすると現在のポイントを ClickPart から取得してデータ送信します。
// データを設定
pointRequestData.point = GameObject.Find("ClickPart").GetComponent<Term1_3_Chapter02_ClickPart>().currentPoint;
このように値を取得しています。あとは同じです。
シンプルに動かしてみる
まずは、サーバーへつなぐ設定ができたので動かしてみましょう。
Play ボタンをクリックします。
ClickPart の上の StatusMessage にサーバからデータを受け取って JSON データを Unity で扱えるデータにしてから result 値の OK を表示できていれば、うまくつながっています。
コンソールでもやり取りの様子が確認できます。
/api/post/init 受信
{ name: '' }
Codespace 側でもターミナルで字受信できたことが確認できます。
続いて、ClickPart を何度かクリックしたあとに、結果送信ボタンをクリックします。
/api/post/result 受信
{ point: 8 }
8 pt 記録
Codespace 側でもターミナルで字受信できたことが確認できます。
コンソールでもやり取りの様子が確認できます。またこの値は、サーバで受信した時点でサーバに recordPoint という値で記録されています。サーバーが起動している間、記録ポイントは保持されています。
また、こちらは初期起動時のデータ取得でも、記録ポイントが返ってきています。(再度つないでみた様子)
受け取ったデータをあいさつ文テキストに反映してみる(ResponseData.title)
Term1_3_Chapter02_ClickPart の対応です。
📋答え(出題中は開かないでくださいね)
// 受信した JSON データを Unity で扱うデータにする ResponseData ベースクラス
[Serializable]
public class ResponseData
{
// result というプロパティ名で string 型で変換
public string result;
// title というプロパティ名で string 型で変換
public string title;
}
ResponseData に title の読み込みを加えます。
// StatusMessage に結果テキスト割り当て
GameObject.Find("StatusMessage").GetComponent().text = responseData.title;
StatusMessage のテキスト割り当てを responseData.title に変更します。
自分の名前を送っていてサーバーであいさつ文を作っていることを確認してから反映(RequestData.name)
Term1_3_Chapter02_ClickPart の対応です。
// 初回ロード時にいろいろな情報をもらう
// /api/post/init というパスで POST リクエストでアクセスするとデータが取得できます
app.post('/api/post/init', (req, res) => {
console.log('/api/post/init 受信');
// 受信したデータ
console.log(req.body);
// あいさつ文の値
let title = "";
// 受信した name 値の有無で文言が変わる
if(req.body.name){
title = `こんにちは!${req.body.name}さん、ようこそ!`;
} else {
title = "こんにちは!ようこそ!";
}
// 送るデータを JavaScript のオブジェクトで作る
const responseData = {
"result":"OK",
"title":title, // あいさつ文
"add_point":1, // 加算ポイント
"recordPoint":recordPoint // 記録している現在のポイント
};
// res.json はオブジェクトを JSON 形式で返答します
res.json(responseData)
});
このようにサーバ側では実は name 値を待っています。では name 値を反映してみましょう。
📋答え(出題中は開かないでくださいね)
// ResponseData ベースクラスを器として呼び出す
RequestData requestData = new RequestData();
// データを設定
requestData.name = "まいねーむ"; // 自分の名前
このように新たな値を加えます。
受け取ったデータをポイント加算に反映してみる(ResponseData.add_point)
Term1_3_Chapter02_ClickPart の対応です。
📋答え(出題中は開かないでくださいね)
// 受信した JSON データを Unity で扱うデータにする ResponseData ベースクラス
[Serializable]
public class ResponseData
{
// result というプロパティ名で string 型で変換
public string result;
// title というプロパティ名で string 型で変換
public string title;
// add_point というプロパティ名で int 型で変換
public int add_point;
}
ResponseData に add_point の読み込みを加えます。
// StatusMessage に結果テキスト割り当て
GameObject.Find("StatusMessage").GetComponent().text = "~~~~~";
// ポイント加算を反映
addPoint = responseData.add_point;
読み込み後に addPoint に値を反映します。
ポイント送信時に実は記録ほやほやの値が返ってくるので、それをOK と表示されてる StatusMessage に表示してみる(ResultResponseData.recordPoint)
Term1_3_Chapter02_SendButton の対応です。
📋答え(出題中は開かないでくださいね)
// 受信した JSON データを Unity で扱うデータにする ResultResponseData ベースクラス
[Serializable]
public class ResultResponseData
{
// result というプロパティ名で string 型で変換
public string result;
// recordPoint というプロパティ名で int 型で変換
public int recordPoint;
}
PointRequestData に recordPoint の読み込みを加えます。
// MessageText に結果テキスト割り当て
GameObject.Find("StatusMessage").GetComponent().text = resultResponse.recordPoint.ToString();
StatusMessage のテキスト割り当てを responseData.recordPoint に文字列変換して変更します。
ダミーでなく加点したポイントをちゃんと送る
Term1_3_Chapter02_SendButton の対応です。
📋答え(出題中は開かないでくださいね)
pointRequestData.point = GameObject.Find("ClickPart").GetComponent().currentPoint;}
ClickPart の Term1_3_Chapter02_ClickPart から currentPoint 値を読み込みます。
再起動して記録ポイントが初期化されることも確認
現在何点獲得していますという実装をする
Term1_3_Chapter02_ClickPart の対応です。
以前記録したポイントで再開してみる
Term1_3_Chapter02_ClickPart の対応です。
JsonUtility の文献紹介
- JsonUtility をつかって Unity で JSON を取り扱う方法 - Qiita
- JsonUtilityでVector2, Vector3をシリアライズする - Qiita
- UnityのJsonUtilityの細かい10の疑問をいまさら検証した - Qiita
- JsonUtilityでオブジェクトをシリアライズしたりデシリアライズしたりする | Yucchiy's Note
今回の Codespace の終了
今回の Codespace 終了しておきましょう。