流れ
スコアの送信はUnity側からGAS(Google Apps Script)にデータを送り
GASがデータを成型してスプレッドシートに書き込む。
成型といっても先頭に現在時刻を足し、送られてきたデータ順に列を埋めるだけ。
あとハイスコア、つまり送られたデータが二行目のスコア列より高ければ二行目を上書きする。
ハイスコアの受信はその二行目のデータを持ってくるだけで良い。
この流れを楽にするため、送受信するデータの構造体は
String(CSV形式)→構造体と構造体→String(CSV形式)の関数を作っておく。
Unity
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// スコアデータの管理とGoogleスプレッドシートとの連携を行うクラス
/// </summary>
public class ScoreDataManager : MonoBehaviour
{
private ScoreData currentScoreData;
/// <summary>
/// スコアデータを格納する構造体
/// </summary>
public struct ScoreData
{
public string name;
public int score;
public int shotCount;
public List<string> targetHitRate;
public ScoreData(string name, int score, int shotCount, List<string> targetHitRate)
{
this.name = name;
this.score = score;
this.shotCount = shotCount;
this.targetHitRate = targetHitRate;
}
/// <summary>
/// CSVデータからスコアデータを生成
/// </summary>
public ScoreData(string data)
{
data = data.Replace("\"", "");
var parts = data.Split(',');
name = parts[1];
score = int.Parse(parts[2]);
shotCount = int.Parse(parts[3]);
targetHitRate = parts.Skip(4).ToList();
}
/// <summary>
/// スコアデータをCSV形式の文字列に変換
/// </summary>
public override string ToString()
{
return $"{name},{score},{shotCount},{string.Join(",", targetHitRate)}";
}
}
[SerializeField] private string spreadsheetID = ""; // スプレッドシートのID
[SerializeField] private string spreadsheetName = ""; // 取得するシート名
[SerializeField] private string gasUrl = ""; // Google Apps ScriptのURL
private List<ScoreData> highScoreDataList = new List<ScoreData>();
/// <summary>
/// Googleスプレッドシートからスコアデータを取得
/// </summary>
private IEnumerator GetData()
{
highScoreDataList.Clear();
string url = $"https://docs.google.com/spreadsheets/d/{spreadsheetID}/gviz/tq?tqx=out:csv&sheet={spreadsheetName}";
using (UnityWebRequest req = UnityWebRequest.Get(url))
{
yield return req.SendWebRequest();
if (req.result == UnityWebRequest.Result.Success)
{
string[] rows = req.downloadHandler.text.Split(new[] { "\n" }, System.StringSplitOptions.RemoveEmptyEntries);
// ヘッダー行をスキップして二行目のハイスコア行を取得
foreach (string row in rows.Skip(1))
highScoreDataList.Add(new ScoreData(row));
}
}
}
/// <summary>
/// スコアデータをGoogleスプレッドシートに送信
/// </summary>
private IEnumerator PostData()
{
WWWForm form = new WWWForm();
form.AddField("val", currentScoreData.ToString());
using (UnityWebRequest req = UnityWebRequest.Post(gasUrl, form))
yield return req.SendWebRequest();
}
}
GAS
function doPost(e) {
// スクリプトのロックを取得(同時実行を防ぐため)
var lock = LockService.getScriptLock();
lock.waitLock(30000); // 最大30秒待機
try {
// Googleスプレッドシートを開く
//https://docs.google.com/spreadsheets/d/ ここを /edit?gid=0#gid=0
var ss = SpreadsheetApp.openById(ここに);
var sheet = ss.getSheetByName("シート(ページ)名");
// POSTされたデータを取得
// parameter."val" は 自分でUnity側から送った名前
var val = e.parameter.val.split(","); // カンマ区切りのデータを配列に変換
// 先頭に現在の日時を追加(記録時刻)
val.unshift(new Date());
// スプレッドシートの既存データを取得して最高スコアを保存する
var data = sheet.getDataRange().getValues(); // 全データ取得
if (data.length >= 2) { // 念のため2行目が存在するか確認
var highScore = parseFloat(data[1][スコアが保存される列]); // 2行目のスコア
var newScore = parseFloat(val[スコアが保存される列]); // 新しいスコア
if (!isNaN(highScore) && !isNaN(newScore) && newScore > highScore) {
// 新しいスコアの方が大きければ2行目を上書き
sheet.getRange(2, 1, 1, val.length).setValues([val]);
}
}
// 新しい行を追加
sheet.appendRow(val);
return ContentService.createTextOutput("Success").setMimeType(ContentService.MimeType.TEXT);
} catch (error) {
// エラー処理
Logger.log(error.toString());
return ContentService.createTextOutput("Error: " + error.toString()).setMimeType(ContentService.MimeType.TEXT);
} finally {
// 入力ロック解除
lock.releaseLock();
}
}