ユーセンブログ

ゲーム開発に関することをたまに書きます

【Unity】Google Spreadsheetsでリアルタイムにパラメーター調整する話

初めに

まず、チームでゲームを制作する際、一つ問題になるのがゲームのバランス調整をどのように行うのかということです。

基本的にチームのプランナーが行うと思うのですが、例えばデータをエクセルに書いてプログラマーに渡すといったやり方はデータの受け渡しやデータの差し替えなどが非常に大きなコストになります。

UnityやUE4などのゲームエンジンを使って直接調整していたり、gitなどを使ってデータを管理している場合もビルドやそもそもツールを起動するなど手間がかかります。

なのでそれらの反映をできる限り簡単したいということで、GoogleのSpreadsheetsとGoogle Action Script(以下GAS)を使ってリアルタイムに実機で調整できるようにします。

f:id:k_tachiban:20171114213026g:plain
今回は起動時のみ取って来るようにしていますが更新ボタンを用意したり定期的に取得するようにしたりもっと使いやすくすることは十分可能です。

Google Spreadsheetsとは

ざっくり言ってしまうとGoogleが提供しているブラウザ版のExcelです。

  • 複数人での同時編集が可能
  • 共有が楽ちん
  • 通信で取得することが可能   大体この辺が特徴でしょうか。

ここで提供されているGASというAPIを活用することでデータを取得したり逆にデータを書き込むといったことも可能です。(超便利!)

実際にGoogle SpreadSheetのデータを取れるようにする

  1. スプレッドシートを作成する
  2. ツールからスクリプトエディタを開く
function test() {
Logger.log(SpreadsheetApp.getActiveSpreadsheet().getId());
}
  1. ↑の処理を走らせてスプレッドシートのログからID取得*1

  2. 上の処理を消して本番の処理を書く

function doGet(e) {
  var sheetName = e.parameter.sheetName;
  var sheet = SpreadsheetApp.openById('調べたID');  
  if (sheet.getSheets().some(function(s) {
    return s.getSheetName() === sheetName;
  })) {

    var ss = sheet.getSheetByName(sheetName);
   //シートに書かれている情報をすべてJSONにして投げる
   var json = ss.getDataRange().getValues();
    return ContentService
      .createTextOutput(JSON.stringify(json))
      .setMimeType(ContentService.MimeType.JSON);
  }
}
  1. これを新たに書き込んだら公開→webアプリケーションとして導入
  2. アプリケーションにアクセスできるユーザーを全員(匿名ユーザーを含む)に設定して公開

これでスプレッドシートの情報が取れるようになりました。

Unity上でデータを扱う

Unity上でデータを取得するにはWWWかUnityWebRequestを使ってデータを取得し、その取得したデータをJSONからクラスなどにパースして扱います。

この際、やり方はとてもたくさんあるのですが今回はUnityWebRequestとminiJSONを使っています。

このやり方はお手軽かついろいろなバージョンで動くのですが処理的にはかなり無駄が多いのでもし調整以外の目的で使う場合はUnityWebRequestやJSONUtilityなどを使ったり取得するデータの範囲をきちんと指定するなどして最適化してください。

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using MiniJSON;

public class SpreadsheetsManager : MonoBehaviour
{
    //ダウンロードしたデータを格納する。
    [SerializeField]
    List<Character> downloadData = new List<Character>();

    private IEnumerator LoadGoogleSpreadSheet(string _sheetName)
    {
        string URL = "https://script.google.com/macros/s/AKfycbyj8ZQoHjnnxii_KH2Wj1NmNRdMn0mRNAgfSXYqhQHb5UtiAmY/exec";
        var download = UnityEngine.Networking.UnityWebRequest.Get(URL + "?sheetName=" + _sheetName);
        
        yield return download.SendWebRequest();

        //JSONの読み込みにはminiJSONを使用
        var json = (List<object>)Json.Deserialize(download.downloadHandler.text);
        if (json != null)
        {
            //先頭一行目は無視、本来は無視しないようにデータを送るべき
            for (int i = 1; i < json.Count; i++)
            {
                var tex = (List<object>)json[i];
                string[] str = tex.Select(n => n.ToString()).ToArray();

                Character chara = downloadData[i - 1];
                //先頭一列目は無視
                chara.charaID = str[1];
                chara.charaName = str[2];
                chara.hp = int.Parse(str[3]);
                chara.Attack = int.Parse(str[4]);
            }

        }
        else
        {
            Debug.LogError(download.downloadHandler.text);
        }

        for(int i=0;i< downloadData.Count;i++)
        {
            downloadData[i].ReflectState();
        }
    }

    void Start ()
    {
        StartCoroutine(LoadGoogleSpreadSheet("Sheet1"));
    }
}

とりあえずの例としては

  1. UnityWebRequestからjsonのデータを取得
  2. 取得したjsonを何らかの形でパース(今回はminiJSON)
  3. ゲームに使用する

大体このような流れになるかと思います。 データの扱い方はゲームによってさまざまだと思うのでそこらへんは各自応用してみてください。

参考

Google Spreadsheetに書いたシナリオをUnityのScriptableObjectにする - Qiita

Google Apps Script で spreadsheet のデータを JSON として読み込む - プログラマってこんなかんじ??

*1:ログは表示タブから開けます。