【Unity】ScriptableObject

转载:【Unity】ScriptableObject的介绍 —— CSDN

简述

最近对unity提供的ScriptableObject比较感兴趣,想了解一下这方面的技术知识。故此参考网上的学习资料总结一遍。

ScriptableObject的好处

  1. 将游戏数据存储在了资源文件中,能够在游戏退出后依然保持这一份游戏数据。
  2. 能依赖继承实现很好的复用关系。

个人觉得第一点是非常好的理念,让游戏的数据存储变得更加的优雅便捷。同时能够实现高复用,来适应多个不同的使用场景。

解决的问题

  • 运行时为了保存数据,基本依靠的是Copy Component Value来解决,非常的麻烦,如果存在多个数据想要保存的话基本没办法。这种时候就应该考虑使用ScriptableObject。
  • 在场景和项目之间很难实现共享,基本也是要序列化一个新的资源文件来实现。
  • 在概念上难以定义这种对象,存储的数据内容不能很好的作区分。扩展性不强。

缺点

  • 回调函数较少
    • OnEnable
    • OnDisable
    • OnDestroy
  • 真正意义上的共享,因此如果修改了数据,就真的修改了

使用方式

  1. 继承自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);
    }

    ...
}
posted @ 2020-09-17 20:27  九梦岛主  阅读(565)  评论(0编辑  收藏  举报