実行時のために最適なデータ構造を作成しよう

21
実実実実実実実実実実実実実実実実実実実実実 実実実実実実実実実実実実実実実実実実実実実 実実実実実実実実実実実実実実実実実実実実実実実実実実 実実実実実実実実実実実実実実実実実実実実実実実実実実

Upload: hiroki-omae

Post on 17-Jan-2017

13.892 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: 実行時のために最適なデータ構造を作成しよう

実行時のために最適なデータ構造を実行時のために最適なデータ構造を作成しよう作成しよう泥臭い世界と決別するためのエディタースクリプト活用法泥臭い世界と決別するためのエディタースクリプト活用法

Page 2: 実行時のために最適なデータ構造を作成しよう

リソースのロードとセットアップのリソースのロードとセットアップの話話キャラクターの顔画像キャラクターの顔画像 (( 連番連番 )) ファイルをプログラムで制御して表示したいファイルをプログラムで制御して表示したいCSVCSV やや XMLXML ファイルに吐いたデータをゲームで利用したいファイルに吐いたデータをゲームで利用したい

Page 3: 実行時のために最適なデータ構造を作成しよう

普通に考えると普通に考えると実行時に画像ファイルを取得実行時に画像ファイルを取得

““/hoge/fuga/chara_%s/face_%d.png” ← /hoge/fuga/chara_%s/face_%d.png” ← キャラキャラ IDID と表情と表情 IDID を入れを入れればいいから簡単じゃない?ればいいから簡単じゃない?CSV/XMLCSV/XML

テキストデータをテキストデータを TextAssetTextAsset として取得として取得実行時にパースして読み込み実行時にパースして読み込み

Page 4: 実行時のために最適なデータ構造を作成しよう

ちょっとまったー!ちょっとまったー!

Page 5: 実行時のために最適なデータ構造を作成しよう

それってゲーム内でやりたいですか?それってゲーム内でやりたいですか?テキストのパース=ゴミ出まくりテキストのパース=ゴミ出まくりゲーム中のデータ構造が元データに制約されるゲーム中のデータ構造が元データに制約される遅い遅いワークフローにも影響ありまくりワークフローにも影響ありまくりビルド時に問題を発見出来ないビルド時に問題を発見出来ない

Page 6: 実行時のために最適なデータ構造を作成しよう

わがままを成立させたいわがままを成立させたい実行時:ゲームシステムから使いやすいこと、速いこと、シンプルなことが実行時:ゲームシステムから使いやすいこと、速いこと、シンプルなことが重要重要ファイル管理:作る時のワークフローが簡単なこと、複雑なルールがないファイル管理:作る時のワークフローが簡単なこと、複雑なルールがないこと、すぐ反映出来ることが重要こと、すぐ反映出来ることが重要

どちらも満たすって難しい!どちらも満たすって難しい!

Page 7: 実行時のために最適なデータ構造を作成しよう

そもそも違う問題なのですそもそも違う問題なのです「ファイルをどこに置くか、どれを読むか」= 「ファイルをどこに置くか、どれを読むか」= アセットパイプラインの問アセットパイプラインの問題題「ゲームで使うデータ構造「ゲームで使うデータ構造 (( クラス構造クラス構造 )) 」=」=ゲーム設計の問題ゲーム設計の問題

一挙に解決するのが難しいのはこれが理由一挙に解決するのが難しいのはこれが理由しかし!しかし!

Page 8: 実行時のために最適なデータ構造を作成しよう

一挙に解決する必要などない!一挙に解決する必要などない!

Page 9: 実行時のために最適なデータ構造を作成しよう

実行時:理想のデータ構造でどうぞ実行時:理想のデータ構造でどうぞファイル管理:エディタースクリプトで!ファイル管理:エディタースクリプトで!

Page 10: 実行時のために最適なデータ構造を作成しよう

XmlToCustomAsset(XmlToCustomAsset( サンプルサンプル ))https://github.com/unity3d-jp/XmlToCustomAsset

Page 11: 実行時のために最適なデータ構造を作成しよう

DemoDemo

Page 12: 実行時のために最適なデータ構造を作成しよう

AssetPostProcessorAssetPostProcessor を使おう!を使おう!拡張子に関係なく対応!拡張子に関係なく対応!ここからデータを読んで、プログラムからここからデータを読んで、プログラムから .assets.assets を作ればよい!を作ればよい!CSVCSV やや XMLXML のパースはエディターで!のパースはエディターで!

Page 13: 実行時のために最適なデータ構造を作成しよう

OnPostprocessAllAssetsOnPostprocessAllAssets

static void OnPostprocessAllAssets ( string[] static void OnPostprocessAllAssets ( string[] importedAssets, string[] deletedAssets, string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { movedAssets, string[] movedFromAssetPaths) { foreach ( foreach (string str in importedAssetsstring str in importedAssets) { ) { if(str.LastIndexOf(".xml" ) != -1) { if(str.LastIndexOf(".xml" ) != -1) { Debug.Log("Reimporting:"+str); Debug.Log("Reimporting:"+str); XMLToCustomAsset.CreateCustomAssetFromXml(str); XMLToCustomAsset.CreateCustomAssetFromXml(str); } }} }

Page 14: 実行時のために最適なデータ構造を作成しよう

.assets.assets って何?って何?.assets.assets とは、とは、本当は本当はシリアライズされたインスタンスのコンテナシリアライズされたインスタンスのコンテナAssetDatabaseAssetDatabase から作成から作成なんでも保存出来ちゃう!なんでも保存出来ちゃう!中身も見られる中身も見られる

Page 15: 実行時のために最適なデータ構造を作成しよう

public class MyCustomAsset : ScriptableObject {public class MyCustomAsset : ScriptableObject { public Color color;public Color color; public string messages;public string messages; public MyCustomAssetInnerClass[] inner;public MyCustomAssetInnerClass[] inner; public public TextAsset source;}TextAsset source;}

実行時のデータ構造実行時のデータ構造

ロード処理の必要なし!ロード処理の必要なし!

Page 16: 実行時のために最適なデータ構造を作成しよう

public MyCustomAsset myData;public MyCustomAsset myData; public public GUIText guiText;GUIText guiText; // Update is called once per // Update is called once per frameframe void Update () {void Update () { if(null != myData) if(null != myData) {{ guiText.text = myData.messages;guiText.text = myData.messages;

}} }}

実行時の利用法実行時の利用法

面倒な処理なし、面倒な処理なし、 D&DD&D も可能も可能

Page 17: 実行時のために最適なデータ構造を作成しよう

.asset.asset からのオブジェクトの読みだからのオブジェクトの読みだししObject objCustom = Object objCustom = AssetDatabase.LoadAssetAtPathAssetDatabase.LoadAssetAtPath(save_path, (save_path, typeof(MyCustomAsset)typeof(MyCustomAsset)););

AssetDatabaseAssetDatabase から、アセットのパスと読み出したい型を指定してから、アセットのパスと読み出したい型を指定してLoadAssetAtPathLoadAssetAtPath を呼ぶことで、そのアセットファイルに保存されてを呼ぶことで、そのアセットファイルに保存されている任意の型のデータを取ってくることが出来ます。いる任意の型のデータを取ってくることが出来ます。

Page 18: 実行時のために最適なデータ構造を作成しよう

オブジェクトの追加とセーブオブジェクトの追加とセーブ

a = CreateMyCustomAssetFromText(ta);a = CreateMyCustomAssetFromText(ta); if(null != a) {if(null != a) { AssetDatabase.CreateAssetAssetDatabase.CreateAsset( a, save_path );( a, save_path ); }} }}if(null != a.inner) {if(null != a.inner) { foreach(MyCustomAssetInnerClass ic in a.inner) {foreach(MyCustomAssetInnerClass ic in a.inner) { AssetDatabase.AddObjectToAssetAssetDatabase.AddObjectToAsset(ic, save_path);(ic, save_path); }}

}} AssetDatabase.SaveAssetsAssetDatabase.SaveAssets();();

Page 19: 実行時のために最適なデータ構造を作成しよう

リプレースではなく変更しようリプレースではなく変更しようシーン内のオブジェクトからシーン内のオブジェクトから .asset.asset 内のオブジェクトを参照している時内のオブジェクトを参照している時に、に、 .asset.asset のオブジェクトを削除&再作成すると参照が切れてしまいますのオブジェクトを削除&再作成すると参照が切れてしまいますすでにあるオブジェクトは、これを取得して編集・保存するようにしますすでにあるオブジェクトは、これを取得して編集・保存するようにしますオブジェクトがすでに存在するかは、オブジェクトがすでに存在するかは、 AssetDatabase.Contains()AssetDatabase.Contains() をを使う事でチェックできます使う事でチェックできます

Page 20: 実行時のために最適なデータ構造を作成しよう

ScriptableObjectScriptableObject を使おうを使おうScriptableObject.CreateInstance<MyCustomAsset>ScriptableObject.CreateInstance<MyCustomAsset>()()

- .asset - .asset に保存するオブジェクトで、に保存するオブジェクトで、 UnityUnity のクラスを継承しなのクラスを継承しないようなものは、いようなものは、 .asset.asset に保存可能にするためにに保存可能にするためにScriptableObjectScriptableObject を継承します。を継承します。- ScriptableObject- ScriptableObject の生成にの生成には、は、 ScriptableObject.CreateInstance() ScriptableObject.CreateInstance() を使用します。を使用します。

Page 21: 実行時のために最適なデータ構造を作成しよう

Happy game development ! :)Happy game development ! :)