G2U4Sは、SpreadsheetやExcelで作成したゲームデータを1クリックでScriptやScriptableObjectに変換するアセットです。
Spreadsheetの連携にはG2Uを使用しています(オフラインではExcelで動作可能です)。
- G2U連携
- SpreadsheetとExcelに対応(チーム開発にも個人開発にも最適)
- 様々なゲームデータを1クリックで変換(Const, Enum, ScriptableObject)
- ScriptableObjectにScriptableObjectを参照可能(ScriptableObject in ScriptableObject)
- 新しいEnumシステム『Subenum』
- ローカライズ対応可能(サンプルあり)
- プラットフォームに依存しないデータ形式(Unity完結)
- ソースコード同梱(カスタマイズ自由)
- 日本語と英語のドキュメント
G2U4Sは、作者の10年のゲーム開発ノウハウを集約して作られたゲームデザインアセットです!
G2U4Sを使用してゲーム開発を楽しみましょう☆
※2020年4月9日追記:G2UがAssetStoreから公開終了になったようです。G2U4Sを使用する場合はExcelをご利用ください(一応過去バージョンのG2UがあればSpreadsheetも動作可能です)
動作環境
動作確認バージョン:Unity2018.4.23, Unity2019.4.1
動作保証バージョン:Unity2018.4 LTS, Unity2019.4 LTS
G2U 2.1.13+
- 動作確認バージョンは作者が動作確認を行ったバージョンです
- 動作保証バージョンはアセット利用可能なバージョンです(どのLTSでも動く想定です)
- G2UなしでもExcelだけで動作可能です(Spreadsheetの連携でG2Uを使用)
使用方法
SpreadsheetかExcelでゲームデータを入力します(どちらも入力形式に違いはありません)。
Spreadsheetの場合はG2UでCSVを出力します(Excelではこの手順は不要)。
「Tools/G2U4S」でCSVやExcelをScriptやScriptableObjectに変換します。
G2U4S.xlsxで設定を変更
アセット直下にG2U4Sの設定ファイル「G2U4S.xlsx」があります。G2U4SConstが設定値です(G2U4SEnumはプログラムで使用しているenum)。Value
の値を変更することで、アセットの動作を変更出来ます。
余談ですが、本アセット自体もG2U4Sで作成したスクリプト(G2U4SConst、G2U4SEnum)で動作しています(アセットの開発自体が動作検証を兼ねてました)。
SpreadsheetかExcelでゲームデータを入力
シート左上セルがデータタイプです。データタイプごとにScriptやScriptableObjectに変換されます(Noneの場合はそのシートは無視されます)。
Const
定数スクリプト(const
とstatic readonly
)。
GameConst.cs
// Auto-generated files
using G2U4S;
using GAMEST;
using UnityEngine;
using System;
namespace GAMEST
{
/// <summary>
/// ゲーム定数
/// </summary>
public static class GameConst
{
/// <summary>
/// リリースフラグ
/// </summary>
public const bool IsRelease = true;
/// <summary>
/// アプリバージョン
/// </summary>
public static readonly string Version = Application.version;
/// <summary>
/// ローカライズ言語
/// </summary>
public static readonly SystemLanguage Language = SystemLanguage.Japanese;
}
}
Enum
enumスクリプト(Subenum
は拡張メソッド)。
GameEnum.cs
// Auto-generated files
using G2U4S;
using GAMEST;
using UnityEngine;
using System;
namespace GAMEST
{
/// <summary>
/// 向き
/// </summary>
public enum Dir : int
{
/// <summary>
/// なし
/// </summary>
None = -1,
/// <summary>
/// 上
/// </summary>
Up = 0,
/// <summary>
/// 右
/// </summary>
Right = 1,
/// <summary>
/// 下
/// </summary>
Down = 2,
/// <summary>
/// 左
/// </summary>
Left = 3,
}
/// <summary>
/// モーション
/// </summary>
public enum MotionType : int
{
/// <summary>
/// 待機
/// </summary>
Idle,
/// <summary>
/// 歩く
/// </summary>
Walk,
/// <summary>
/// 走る
/// </summary>
Run,
/// <summary>
/// 防御
/// </summary>
Guard,
/// <summary>
/// ダメージ
/// </summary>
Damage,
/// <summary>
/// 通常攻撃
/// </summary>
NormalAttack,
/// <summary>
/// 必殺技
/// </summary>
SpecialAttack,
}
public static partial class G2U4Subenum
{
/// <summary>
/// 待機
/// </summary>
public static bool IsIdle(this MotionType value) { return value == MotionType.Idle; }
/// <summary>
/// 歩く
/// </summary>
public static bool IsWalk(this MotionType value) { return value == MotionType.Walk; }
/// <summary>
/// 走る
/// </summary>
public static bool IsRun(this MotionType value) { return value == MotionType.Run; }
/// <summary>
/// 防御
/// </summary>
public static bool IsGuard(this MotionType value) { return value == MotionType.Guard; }
/// <summary>
/// ダメージ
/// </summary>
public static bool IsDamage(this MotionType value) { return value == MotionType.Damage; }
/// <summary>
/// 通常攻撃
/// </summary>
public static bool IsNormalAttack(this MotionType value) { return value == MotionType.NormalAttack; }
/// <summary>
/// 必殺技
/// </summary>
public static bool IsSpecialAttack(this MotionType value) { return value == MotionType.SpecialAttack; }
/// <summary>
/// 移動か
/// </summary>
public static bool IsMove(this MotionType value) { return value == MotionType.Walk || value == MotionType.Run; }
/// <summary>
/// 攻撃か
/// </summary>
public static bool IsAttack(this MotionType value) { return value == MotionType.NormalAttack || value == MotionType.SpecialAttack; }
/// <summary>
/// 攻撃可能か
/// </summary>
public static bool CanAttack(this MotionType value) { return value == MotionType.Idle || value == MotionType.Walk || value == MotionType.Run || value == MotionType.Guard; }
}
}
ScriptableObject
単体ScriptableObject。
TestData.cs
// Auto-generated files
using G2U4S;
using GAMEST;
using UnityEngine;
using System;
namespace GAMEST
{
/// <summary>
/// テストデータ
/// </summary>
public class TestData : ScriptableObject
{
/// <summary>
/// テスト中か
/// </summary>
public bool IsTest;
/// <summary>
/// ワールドタイム
/// </summary>
public SerializableDateTime WorldTime;
/// <summary>
/// モーション
/// </summary>
public MotionType Motion;
/// <summary>
/// 武器IDリスト
/// </summary>
public int[] WeaponIds;
/// <summary>
/// 当たり時間範囲
/// </summary>
public Vector2 CollidableTime;
}
}
LocalizeData.cs
// Auto-generated files
using G2U4S;
using GAMEST;
using UnityEngine;
using System;
namespace GAMEST
{
/// <summary>
/// ローカライズデータ
/// </summary>
public class LocalizeData : ScriptableObject
{
/// <summary>
/// キー
/// </summary>
public string[] Keys;
/// <summary>
/// 日本語
/// </summary>
public string[] Japanese;
/// <summary>
/// 英語
/// </summary>
public string[] English;
}
}
ScriptableObjects
複数ScriptableObject。
WorldData.cs
// Auto-generated files
using G2U4S;
using GAMEST;
using UnityEngine;
using System;
namespace GAMEST
{
/// <summary>
/// ワールドデータ
/// </summary>
public class WorldData : ScriptableObject
{
/// <summary>
/// ID
/// </summary>
public int Id;
/// <summary>
/// 名前キー
/// </summary>
public string NameKey;
/// <summary>
/// マップデータリスト
/// </summary>
public MapData[] Maps;
}
}
MapData.cs
// Auto-generated files
using G2U4S;
using GAMEST;
using UnityEngine;
using System;
namespace GAMEST
{
/// <summary>
/// マップデータ
/// </summary>
public class MapData : ScriptableObject
{
/// <summary>
/// ID
/// </summary>
public int Id;
/// <summary>
/// 名前キー
/// </summary>
public string NameKey;
}
}
Spreadsheetの場合はG2UでCSVを出力
G2U GoogleスプレッドシートのデータをUnityに取り込むエディタ ゼロから始める解説付き
G2Uを使用するに当たり、上記記事を参考にさせていただきました☆
G2Uをインストールして「Window/Google2u」を開く
Googleにログイン
「Sign in with Google」をクリックしてGoogleへログイン。
ログイン後、コードをコピーして、「OAuth Token」に貼り付けて「Log In」。
「Workbooks/Account Workbooks」を開く
ゲームデータ以外のシートの瞳を閉じる
「Do Not Export」を「CSV」に変更
右下のフロッピーボタンでCSVを出力
Google2uGenフォルダにCSVが出力される。
Spreadsheet更新時は、左下のリロードボタン → 右下のフロッピーボタンで更新。
「Tools/G2U4S」でCSVやExcelをScriptやScriptableObjectに変換
スキル
SpreadsheetとExcelに対応
- 個人開発やローカル環境ではExcel
- チーム開発ではSpreadsheet
というような住み分けが可能です。
Excelの標準機能(計算式等)を問題なく使えます。
Spreadsheetの連携にはG2Uを使用しているので安心です。
柔軟な型と型の追加
ユーザ定義型は同じ名前空間内であれば何でも使えます(名前空間はG2U4S.xlsx/G2U4SConst/YourNamespace
で変更可能です)。
その他の型は以下の通りです。
型 | 指定方法 |
---|---|
配列 | 通常:値1, 値2 構造体: (値1, 値2), (値3, 値4) |
enum | Idle enum名 |
ScriptableObject | 空文字(型名で決まるため) |
ScriptableObjects | 1 ScriptableObjectのキー(1列目の値) |
sbyte | 1 |
byte | 1 |
short | 1 |
ushort | 1 |
int | 1 |
uint | 1 |
long | 1 |
ulong | 1 |
char | a |
float | 1.0 |
double | 1.0 |
bool | true 1 ○ G2U4S.xlsx/G2U4SConst/BoolTrueValues 参考 |
string | M4u |
SerializableDateTime | 2019-03-22 00:51 |
Vector2 | 1, 1 カンマ指定の数値は後ろを省略すると 0 で初期化される |
Vector3 | 1, 1, 1 |
Vector4 | 1, 1, 1, 1 |
Rect | 1, 1, 1, 1 |
Vector2Int | 1, 1 |
Vector3Int | 1, 1, 1 |
RectInt | 1, 1, 1, 1 |
Quaternion | 1, 1, 1, 1 |
Color | 1, 1, 1, 1 |
Color32 | 255, 255, 255, 255 |
また、型の追加はG2U4SUtil.Parse(Type type, string str, bool isArray, string assetDir = "")
で行えます(分岐を追加してください)。
SerializableDateTime
上記記事で書きましたが、元々G2U4Sのために作ったクラスでした。
実際、ゲームでは時間を扱う機会は多いと思います。
ScriptableObject in ScriptableObject
G2U4Sの最大の強みはScriptableObjectの中にScriptableObjectを参照できるところです。
こうすることで、データ間の参照が可能になるので「データ」と「プログラム」を完全に分離出来ます(ConstやEnumもそれを補助しています)。
プランナー・プログラマーで作業分担がしやすくなります。
1点注意点があるとしたら、AssetBundleにした時は重複してメモリに乗ってしまう可能性があるので、その辺はパフォーマンスを気にした設計を行ってください。
Subenum
Subenumとはenumを拡張メソッド化した機能です。
例えば以下のようなenumがあった場合、
IsMove
は以下のように展開され、
/// <summary>
/// 移動か
/// </summary>
public static bool IsMove(this MotionType value)
{
return value == MotionType.Walk || value == MotionType.Run;
}
以下のように使えるようになります。
var motion = MotionType.Walk;
if(motion == MotionType.Walk || motion == MotionType.Run)
{
// 移動中の処理
}
// ↑ が ↓ こう書ける
if(motion.IsMove())
{
// 移動中の処理
}
C#でenumをクラスのように扱う
元々、上記記事を作ってから、ちょいちょいenumの拡張メソッド化を試していたのですが、
- 定義が面倒
- 修正箇所が増える
- C#7の
using static
を使えば拡張メソッド化せずとも短く記述できる
等の理由から、抵抗を感じていました。しかし、G2U4Sの開発中に、
「enumを自動生成するなら拡張メソッドも自動生成すればいんじゃね?」
と思いつき、
「どうせ自動生成するなら列挙子も複数まとめてみたらどうだろう?」
と行き着き、この機能が完成しました。
名付けて Subenum!
enumの中に小さなenumがあるイメージ。
メリット | デメリット |
---|---|
コード量の削減 | メソッド化による呼び出しコスト |
可読性の向上 | アプリサイズ増加 |
個人的には気に入ってるのですが、ここらへんのトレードオフかなぁ。
ローカライズ対応
G2U4Sはローカライズ対応も行えます。
実際、個人開発のゲームをローカライズするためにG2U4Sを作りました。
以下のように使用します(やり方はいろいろあるかと思うので一例です)。
[SerializeField] SystemLanguage language = SystemLanguage.Japanese;
[SerializeField] LocalizeData localizeData;
[SerializeField] WorldData worldData;
Dictionary<string, string> japanese = new Dictionary<string, string>();
Dictionary<string, string> english = new Dictionary<string, string>();
void Start()
{
var keys = localizeData.Keys;
for(var i = 0; i < keys.Length; i++)
{
japanese.Add(keys[i], localizeData.Japanese[i]);
english.Add(keys[i], localizeData.English[i]);
}
var key = worldData.NameKey;
var worldName = (language == SystemLanguage.Japanese) ? japanese[key] : english[key];
Debug.Log($"worldName = {worldName}");
}
イベント(OnInit, OnScriptCreated, OnAssetCreated, OnAssetUpdated)
G2U4Sは以下のシーケンスで実行され、それぞれの終了時にコールバックが呼ばれます。
シーケンス | 内容 |
---|---|
Init | G2U4S.xlsx の設定を初期化(G2U4SConst、G2U4SEnumの作成)。G2U4SUtil.OnInit() が呼ばれる。 |
CreateScript | Const, Enum, ScriptableObject, ScriptableObjects のスクリプトを作成。G2U4SUtil.OnScriptCreated() が呼ばれる。 |
CreateAsset | ScriptableObject, ScriptableObjects のアセットを作成。G2U4SUtil.OnAssetCreated() が呼ばれる。 |
UpdateAsset | ScriptableObject, ScriptableObjects のアセットの値を更新。G2U4SUtil.OnAssetUpdated() が呼ばれる。 |
実行後に何らかの処理を加えたい場合は、これらのコールバックをご使用ください。
最後に
正直、威力は高くないけど、使い勝手のいい能力だと思う。
〜オセロを作りながらゲームのプログラムを学ぼう〜