2015年5月4日 星期一

迅速掌握ScriptableObject

0. 什麼是ScriptableObject?
ScriptableObject就是個資料載體, 他允許你把程式中的資料儲存成檔案, 並且用程式再重新取用那些資料.



官方詳細的解釋有興趣可以自己看看

1. ScriptableObject長什麼樣子?
程式中, 我們可能會定義一個類似這樣的資料類別
public DataClass
{
public int hp;
public int maxhp;
public string name;
}
view raw DataClass.cs hosted with ❤ by GitHub

然後用這樣的資料類別儲存了大量相似的資料
這時候我們一般會用XML, json, 或者Server去進行這些值的儲存

但有些值, 其實我們可以直接存成一個ScriptableObject就好
一個已經存成檔案的ScriptableObject就像這樣




點了以後你可以在Inspector介面即時看到


























2. 這樣的資料會怎樣用到我的程式裡?
只要你把產出的.asset檔, 例如: DataClass.asset放到Resources資料夾去
程式中你只要再這樣宣告
DataClass data = Resources.Load<DataClass>("DataClass");
這時你就可以隨時得到data.hp的值了
想像一下, 我們進一步把DataClass從簡單的變數變成List
這樣一來你就可以迅速像在用json, XML那樣做好自己的資料物件了

3. 可以開始寫了嗎?
以下直接列出所有的code, 簡單粗暴的做完示範後再進行說明
using UnityEngine;
using System.Collections;
[System.Serializable]
public class MemberData
{
public string name;
public int hp;
public int exp;
}
view raw MemberData.cs hosted with ❤ by GitHub

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MyGroupData : ScriptableObject
{
public List<MemberData> members = new List<MemberData>();
}
view raw MyGroupData.cs hosted with ❤ by GitHub

using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections;
public class MyMenu
{
public static string filePath = @"Assets/Sample/MyGroupData.asset";
[MenuItem("Component/GenerateMyGroupData")]
public static void Generate()
{
MyGroupData gData = (MyGroupData)ScriptableObject.CreateInstance<MyGroupData>();
MemberData tom = new MemberData();
tom.name = "Tom";
tom.hp = 10;
tom.exp = 20;
MemberData sam = new MemberData();
sam.name = "Tom";
sam.hp = 30;
sam.exp = 40;
MemberData bob = new MemberData();
bob.name = "Tom";
bob.hp = 50;
bob.exp = 60;
gData.members.Add(tom);
gData.members.Add(sam);
gData.members.Add(bob);
string folder = Path.GetDirectoryName(filePath);
if(Directory.Exists(folder) == false)
{
Directory.CreateDirectory(folder);
}
AssetDatabase.CreateAsset(gData, filePath);
}
[MenuItem("Component/GenerateRandomMember")]
public static void GenerateRandom()
{
if(File.Exists(filePath))
{
MyGroupData gData = (MyGroupData)AssetDatabase.LoadAssetAtPath(filePath, typeof(MyGroupData));
MemberData randomMember = new MemberData();
randomMember.name = Random.Range(55, 999).ToString();
randomMember.hp = Random.Range(1, 99);
randomMember.exp = Random.Range(1, 999);
gData.members.Add(randomMember);
EditorUtility.SetDirty(gData);
}
}
}
view raw MyMenu.cs hosted with ❤ by GitHub

4. 仔細說明一下
<MemberData.cs>
這個就跟我們先前的DataClass差不多, 是單純的資料載體類別
需要說明的是[System.Serializable]標籤
這個標籤是告訴Unity, 我要把這個類別定義成可序列化類別

什麼是可序列化類別?
粗略的解釋就是, Unity會自動幫你做存檔的一種機制
我們MonoBehaviour上寫public 變數
再到Inspector改變數, Unity會自動幫我們記住改的結果
這就是利用了可序列化搞的

<MyGroupData.cs>
這裡我直接繼承了ScriptableObject, 把MyGroupData整個定義成可序列化類別
並且用List去做了MemberData列表

請注意:
可序列化目前只支援primitive類型的變數
string, array, list, int, float, vector, 有標[System.Serializable]的自訂類別

<MyMenu.cs>
首先, 看到using UnityEditor; 就可以知道這是一個編輯器類別
請務必放到Editor為名的資料夾內

這裡我簡單用MenuItem在Component這個分類裡簡單做了兩個按鈕

GenerateMyGroupData示範了怎樣產生ScriptableObject資料檔

GenerateRandomMember示範了怎樣去修改已經存出的asset檔

EditorUtility.SetDirty(gData);
這行是精華, 你要把物件弄髒了, Unity才會知道要儲存

5. 我寫完以後需要做什麼測試嗎?
我會建議你把Unity關掉重開
然後去看看MyGroupData.asset的資料還在不在
只要還在那就100%完成了
如果不在, 那麼上面步驟你一定有漏掉, 再多看幾次

沒有留言:

張貼留言