【Unity】ScriptableObject
阿新 • • 發佈:2020-09-17
【Unity】ScriptableObject的介紹 —— CSDN
簡述
最近對unity提供的ScriptableObject比較感興趣,想了解一下這方面的技術知識。故此參考網上的學習資料總結一遍。
ScriptableObject的好處
- 將遊戲資料儲存在了資原始檔中,能夠在遊戲退出後依然保持這一份遊戲資料。
- 能依賴繼承實現很好的複用關係。
個人覺得第一點是非常好的理念,讓遊戲的資料儲存變得更加的優雅便捷。同時能夠實現高複用,來適應多個不同的使用場景。
解決的問題
- 執行時為了儲存資料,基本依靠的是Copy Component Value來解決,非常的麻煩,如果存在多個數據想要儲存的話基本沒辦法。這種時候就應該考慮使用ScriptableObject。
- 在場景和專案之間很難實現共享,基本也是要序列化一個新的資原始檔來實現。
- 在概念上難以定義這種物件,儲存的資料內容不能很好的作區分。擴充套件性不強。
缺點
- 回撥函式較少
- OnEnable
- OnDisable
- OnDestroy
- 真正意義上的共享,因此如果修改了資料,就真的修改了
使用方式
- 繼承自MonoBehavior的改成ScriptabObject
using UnityEngine; [CreateAssetMenu(menuName="MySubMenue/Create MyScriptableObject ")] public class MyScriptableObject : ScriptableObject { public int someVariable; }
CreateAssetMenu
會在資源選單建立一個ScriptaObject的選項,方便建立物件。
回撥函式的呼叫時機
- OnEnable
- 建立的時候
- 載入的時候
- 過載程式碼的完成時候
- OnDisable
- 開始過載程式碼的時候
- 將要銷燬的時候
- OnDestroy
- 銷燬時
參考例子——遊戲設定
遊戲設定繼承自ScriptableObject,並實現單例模式。這樣子在設定中去呼叫GetInstance方法可以就可以訪問到當前的遊戲設定。而且退出遊戲時遊戲資料也繼續保持。
[CreateAssetMenu] public class GameSettings : ScriptableObject { [Serializable] public class PlayerInfo { public string Name; public Color Color; ... } public List<PlayerInfo> players; private static GameSettings _instance; public static GameSettings Instance { get { if (!_instance) _instance = Resources.FindObjectsOfTypeAll<GameSettings>().FirstOrDefault(); #if UNITY_EDITOR if (!_instance) InitializeFromDefault(UnityEditor.AssetDatabase.LoadAssetAtPath<GameSettings>("Assets/Test game settings.asset")); #endif return _instance; } } public int NumberOfRounds; public static void LoadFromJSON(string path) { if (!_instance) DestroyImmediate(_instance); _instance = ScriptableObject.CreateInstance<GameSettings>(); JsonUtility.FromJsonOverwrite(System.IO.File.ReadAllText(path), _instance); _instance.hideFlags = HideFlags.HideAndDontSave; } public void SaveToJSON(string path) { Debug.LogFormat("Saving game settings to {0}", path); System.IO.File.WriteAllText(path, JsonUtility.ToJson(this, true)); } public static void InitializeFromDefault(GameSettings settings) { if (_instance) DestroyImmediate(_instance); _instance = Instantiate(settings); _instance.hideFlags = HideFlags.HideAndDontSave; } #if UNITY_EDITOR [UnityEditor.MenuItem("Window/Game Settings")] public static void ShowGameSettings() { UnityEditor.Selection.activeObject = Instance; } #endif ... }
public class MainMenuController : MonoBehaviour
{
public GameSettings GameSettingsTemplate;
...
public string SavedSettingsPath {
get {
return System.IO.Path.Combine(Application.persistentDataPath, "tanks-settings.json");
}
}
void Start () {
if (System.IO.File.Exists(SavedSettingsPath))
GameSettings.LoadFromJSON(SavedSettingsPath);
else
GameSettings.InitializeFromDefault(GameSettingsTemplate);
foreach(var info in GetComponentsInChildren<PlayerInfoController>())
info.Refresh();
NumberOfRoundsSlider.value = GameSettings.Instance.NumberOfRounds;
}
public void Play()
{
GameSettings.Instance.SaveToJSON(SavedSettingsPath);
GameState.CreateFromSettings(GameSettings.Instance);
SceneManager.LoadScene(1, LoadSceneMode.Single);
}
...
}