GoogleスプレッドシートとUnityWebRequestを使って簡単なランキング機能を作ってみる
完全無料で、なおかつデータが消えず、シンプルで柔軟性に優れるランキングシステムはGoogleスプレッドシートとApps Scriptなのよ。
目次
仕組み
Google Apps Scriptを用いて、Googleスプレッドシートの記録をJSON出力する。また、UnityサイドでHTTP-GET通信を行ってJSON取得できるよう、UnityWebRequestを用いる。
UnityサイドでUnityWebRequestを使い、HTTP-POST通信を行う。そして、Googleスプレッドシートにスコアなどの情報を記録できるよう、Apps Scriptを用いる。
Googleスプレッドシート側の実装
Googleスプレッドシートの作成
Googleスプレッドシートを作成しなければ何も始まりませんので、Googleスプレッドシートのサイトに移動します。(Googleアカウントが必要です)
https://docs.google.com/spreadsheets
そしたら、トップに表示されている「新しいスプレッドシートを作成」から「空白」をクリックして、新しいスプレッドシートを作成します。
スプレッドシートを作成したら、1行目に必要なパラメータを英字で記入します。今回はプレイヤー名「name」とスコア「score」を用意したいと思います。
また、システム用に、スコア更新の際にプレイヤーのデバイス情報を格納する「address」と、記録が作成された日時を格納する「created」ならびに、記録が更新された日時を格納する「updated」合計5つのパラメータを用意しました。
そして、左下のシート名を「Main」に変更します。ついでにスプレッドシートの名前も「SampleRanking」に変更します。
一応、パラメータ情報を格納する1行目は特別に着色しました。
これにてスプレッドシートの準備は完了です。
スプレッドシートIDの取得
ブラウザのリンク欄に「https://docs.google.com/spreadsheets/d/xxxxxxxxxx/edit」が表示されていると思います。
また、dとeditの間に、ランダムな文字列で構成された長い文字列xxxxxxxxxxがあります。
その長い文字列がスプレッドシートIDです。そのスプレッドシートIDは後ほどAppsScriptで使用します。
AppsScriptの記述
Googleスプレッドシートのメニューバーより「拡張機能」から「Apps Script」をクリックします。
すると以下のページが表示されます。
これが、Googleスプレッドシートを操作するための、Apps Scriptのエディタとなります。
早速、以下のコードをコピペします。また、1行目のconst idの値に先ほど取得したスプレッドシートIDを入力します。
const id = "xxxxxxxxxx"; // ここに先ほど取得したスプレッドシートIDを入力します。
function doGet() {
return getRecordsAsJson();
}
function doPost(e) {
const sheet = SpreadsheetApp.openById(id).getSheetByName("Main");
const rows = sheet.getDataRange().getValues();
const address = e.parameter.address;
const name = e.parameter.name;
const score = e.parameter.score;
var index = 0;
for (var i = 1; i < rows.length; i++) {
if (rows[i][0] == address) {
index = i + 1;
}
}
if (index > 0) {
const nowDate = getNowDate();
const currentScore = sheet.getRange(index, 2).getValue();
sheet.getRange(index, 2).setValue(name);
if (score > currentScore) {
sheet.getRange(index, 3).setValue(score);
}
sheet.getRange(index, 5).setValue(nowDate);
}
else {
const nowDate = getNowDate();
const created = nowDate;
const updated = nowDate;
sheet.appendRow([address, name, score, created, updated]);
}
return getRecordsAsJson();
}
function getNowDate() {
const date = new Date();
return Utilities.formatDate(date, "Asia/Tokyo", "yyyy-MM-dd HH:mm:ss");
}
function getRecordsAsJson() {
function getRecords() {
const sheet = SpreadsheetApp.openById(id).getSheetByName("Main");
const rows = sheet.getDataRange().getValues();
const keys = rows.splice(0, 1)[0];
return rows.map(function (row) {
var obj = {};
row.map(function (item, index) {
obj[keys[index]] = item;
});
return obj;
});
}
return ContentService.createTextOutput('{"records":' + JSON.stringify(getRecords(), null, 2) + '}').setMimeType(ContentService.MimeType.JSON);
}
一応、Apps Scriptの名前を「SampleRanking」、ファイル名「Main.gs」とします。
これにて、Apps Scriptの記述は完了です。
デプロイ
記述したスクリプトを動作させるにはデプロイが必要です。
画面上の右上の青い「デプロイ」をクリックして、「新しいデプロイ」をクリックします。
すると、以下のようなダイアログが出現します。
左上の「種類の選択」の右側にある歯車アイコンをクリックして「ウェブアプリ」をクリックします。
新しい説明文に説明文を入力して、アクセスできるユーザーを「全員」に変更します。
その後「デプロイ」をクリックします。
青い「アクセスを承認」ボタンを押します。
すると、以下のポップアップ画面が出現します。
表示されたユーザー名をクリックします。
すると、以下のような警告画面が表示されます。
厳しめの警告画面ですがお気になさらず、左下の「Advanced」をクリックします。
その後、ポップアップの最下部に「Go to SampleRanking (unsafe)」が出現しますので、それをクリックします。
右下の青い「BACK TO SAFETY」はクリックしません。
「Allow」をクリックします。
最終的にポップアップが消え、デプロイIDとURLが出現します。
生成されたデプロイIDはUnityサイドで使用しますので、メモ帳などにコピペします。
Googleスプレッドシート側の実装は以上となります。
Unity側の実装
JSONをParseするためのクラス定義
Google APIが取得してくるJSON情報をParseするためのSerializableなクラスを2つ定義します。
using System;
using System.Collections;
[Serializable]
public class Records
{
public Record[] records;
}
[Serializable]
public class Record
{
public string address;
public string name;
public int score;
public string created;
public string updated;
}
送受信処理の記述
スクリプトファイルを作成し、MonoBehaviour継承クラス内に、送信用と受信用のIEnumeratorメソッドを定義します。また、デプロイIDを格納するためのSerializedFieldのstringプロパティも定義します。
今回はMonoBehaviour継承クラスの内部をそのままコピペして使えるよう、送信用と受信用のIEnumeratorメソッドに簡単な結果の処理と、それらのメソッドをキーボタン1回で呼び出せるよう、Update()メソッドも定義しました。
public class Sample : MonoBehaviour
{
[SerializeField] private string accessKey;
private void Update()
{
if (Input.GetKeyDown(KeyCode.G))
{
StartCoroutine(GetData());
}
if (Input.GetKeyDown(KeyCode.P))
{
StartCoroutine(PostData("abcdefghijklmnopqrstuvwxyz", "Akio", 168));
}
}
private IEnumerator GetData()
{
Debug.Log("データ受信開始・・・");
var request = UnityWebRequest.Get("https://script.google.com/macros/s/" + accessKey + "/exec");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
if (request.responseCode == 200)
{
var records = JsonUtility.FromJson<Records>(request.downloadHandler.text).records;
Debug.Log("データ受信成功!");
foreach (var record in records)
{
Debug.Log("Name:" + record.name + "、Score:" + record.score);
}
}
else
{
Debug.LogError("データ受信失敗:" + request.responseCode);
}
}
else
{
Debug.LogError("データ受信失敗" + request.result);
}
}
private IEnumerator PostData(string address, string username, int score)
{
Debug.Log("データ送信開始・・・");
var form = new WWWForm();
form.AddField("address", address);
form.AddField("name", username);
form.AddField("score", score);
var request = UnityWebRequest.Post("https://script.google.com/macros/s/" + accessKey + "/exec", form);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
if (request.responseCode == 200)
{
var records = JsonUtility.FromJson<Records>(request.downloadHandler.text).records;
Debug.Log("データ送信成功!");
foreach (var record in records)
{
Debug.Log("Name:" + record.name + "、Score:" + record.score);
}
}
else
{
Debug.LogError("データ送信失敗" + request.responseCode);
}
}
else
{
Debug.Log("データ送信失敗" + request.result);
}
}
}
Unityエディタ上での処理
Hierarchyから空のGameObjectを作成し、Inspector上にて、先ほど生成したGameObjectに上記のスクリプトをアタッチします。
また、accessKeyのプロパティに、App Scriptsで取得したデプロイIDを入力します。
動作確認
Unityで再生ボタンをクリックして、Pキーで送信し、Gキーで受信を行います。
うまく動作すれば、Googleスプレッドシートに記録の行が追加され、Unityサイドで正確にParseされた情報が取得できます。
さいごに
適宜Unity側でソースコードを書き換えば、シンプルに名前と整数値のスコアを記録するランキング機能としては十分動作すると思います。
また、Apps Scriptの知識があれば、オンライン上のデータシステムとして様々なカスタマイズが行えまると思います。
GoogleスプレッドシートとApps Scriptによるランキング機能などは、Googleアカウントを所有している限り完全無料で、なおかつ未更新状態でもデータが保持されるなど、何かと便利な存在になると思います。(なお、Apps ScriptのAPI実行回数などは様々な制限がございます。その辺は公式ドキュメントなどをご覧ください)
それでは!よき創作ライフを!