SpreadSheetの複数のシートをマスターデータして使う


# 前提
1つのシートをUnityで取得するのは、SpreadSheetのデータをcsvで取得すれば良いので簡単。しかし、複数まとめて取得するのはcsvではできなかった。

# やったこと

スプレッドシートのデータを`MasterDataSet.cs`に格納します。
![スクリーンショット 2018-12-09 2.23.13.png](https://qiita-image-store.s3.amazonaws.com/0/113504/51376517-3da1-bf0a-7643-ddb9e9140cd2.png "スクリーンショット 2018-12-09 2.23.13.png")

```KeyValue.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace CA2.Data.MasterData
{
	[System.Serializable]
	public class KeyValue{
		public string key;
		public string value;
	}
}
```

```MasterDataSet.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace CA2.Data.MasterData{
    [System.Serializable]
    public class MasterDataSet{
        public List<KeyValue> keyValueList;
        public List<Item> itemList;
    }
}

```

# リポジトリ
https://github.com/teach310/commonAsset2

メニューのTools > ConvinientToolsでWindowを開いて、AnyTestボタンを押すことで動作を確認することができます。

# 流れ

1. GASでシートのデータをJson形式で公開する。
2. Unity側でJsonUtilityを用いてMasterDataSetに突っ込む

# ポイント1 GASでシートのデータをJson形式で公開する。

```Loader.gs
var SPREAD_SHEET_ID = "スプレッドシートのIDを入れる";

function onOpen(e){
  var subMenus = [
    {name: "LogMasterData", functionName: "LogMasterData"}
  ];
  var spreadsheet = SpreadsheetApp.getActive();
  spreadsheet.addMenu("Tools", subMenus)
  
}

function logMasterData(){
  var dataJson = JSON.stringify(getAllMasterData(SPREAD_SHEET_ID));
  Logger.log(dataJson);
  Browser.msgBox(dataJson);
}

function doGet(e) {
  var contents= getAllMasterData(SPREAD_SHEET_ID);
  // Jsonをレスポンスとして返す
  return ContentService.createTextOutput(JSON.stringify(contents)).setMimeType(ContentService.MimeType.JSON)
}

var snakeToCamel = function(p){
  //_+小文字を大文字にする(例:_a を A)
  return p.replace(/_./g,
  function(s) {
    return s.charAt(1).toUpperCase();
  }
)}

function getAllMasterData(sheetId){
  var sheets = SpreadsheetApp.openById(sheetId).getSheets();
  var sheetsData = {}
  sheets.map(function(sheet){ // 各シートごとにデータを生成し
    var rows = sheet.getDataRange().getValues();
    // rowsの0インデックス目から2つ取り除き、除いたものを返す
    var keys = rows.splice(0, 2)[0]; //　0: カラム名 1: コメント
    var sheetData = rows.map(function(row) {
      var obj = {}
      row.map(function(item, index) {
        obj[keys[index]] = item;
      });
      return obj;
    })
    sheetsData[snakeToCamel(sheet.getName()) +"List"] = sheetData;
  })
  return sheetsData;
}


```

(1) `getSheets()`を使うと全てのシートを取得することができる。
(2) MasterDataSetの変数名と一致させる

# ポイント2 Unity側でJsonUtilityを用いてMasterDataSetに突っ込む

```MasterDataLoader.cs
using System;
using System.Collections;
using System.Collections.Generic;
using CA2.Data.MasterData;
using UniRx;
using UnityEngine;

namespace CA2.Data {
	public class MasterDataLoader {
		public IObservable<MasterDataSet> Load (string url) {
			return ObservableWWW.Get (url, null, new ProgressLogger())
				.Do(t => Debug.Log(t))
				.Select (x => {
					try {
						return JsonUtility.FromJson<MasterDataSet> (x);
					} catch (System.Exception) {
						throw;
					}
				});
		}

		public class ProgressLogger : IProgress<float> {
			public void Report (float value) {
				Debug.Log (value);
			}
		}
	}
}
```

適切な形でJsonをもらえればJsonUtilityで簡単にデータを格納することが可能。

```KeyValue.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace CA2.Data.MasterData
{
	[System.Serializable]
	public class KeyValue{
		public string key;
		public string value;
	}
}
```

KeyValueのvalueは本当はobject型にしたかったのですが、JsonUtilityで値が入らなかったのでstringにしています。

# まとめ
ここからさらに`ScriptableObject`として保存した後、AssetBundle化して配信することでいい動きができるんじゃないかと思っています。

スクリプト自動生成、AssetBundle化して配信までを1ボタンでできるようにしていければいいなと思います。