Unity:Singleton ScriptableObjects 在播放后重置

Unity : Singleton ScriptableObjects resets after play

我有一个单例 class,其中包含有关我的游戏的一般信息。

public class GeneralGameData : ScriptableObject
{
    private static GeneralGameData _currentGeneralGameData;

    public static GeneralGameData CurrentGeneralGameData
    {
        get
        {
            if (_currentGeneralGameData == null)
            {
                _currentGeneralGameData = CreateInstance<GeneralGameData>();
            }

            DontDestroyOnLoad(_currentGeneralGameData);

            return _currentGeneralGameData;
        }
    }

    public string GameName;

    public string GameVersion;

}

这个class场景中没有礼物。

我还有一个 window 来显示和更改

 public class GeneralGameDataMenuItem : EditorWindow
{
    [MenuItem("CoreMaker/GeneralGameData")]
    private static void _generalGameData()
    {
        GetWindow<GeneralGameDataMenuItem>("GeneralGameData");
    }

    void OnGUI()
    {
        GeneralGameData.CurrentGeneralGameData.GameName = EditorGUILayout.TextField("GameName", GeneralGameData.CurrentGeneralGameData.GameName);
        GeneralGameData.CurrentGeneralGameData.GameVersion = EditorGUILayout.TextField("GameVersion", GeneralGameData.CurrentGeneralGameData.GameVersion);

        EditorUtility.SetDirty(GeneralGameData.CurrentGeneralGameData);
    }
}

问题是在我点击播放或重新启动 unity 后它不会保存我的更改。 有什么解决办法吗??

A​​ ScriptableObject 旨在保存为资产。在 ScriptableObject class 声明上方添加 [CreateAssetMenu(menuName = "MyGame/GeneralGameData")] 行,然后右键单击项目窗格,单击 Create > MyGame > GeneralGameData。填写您需要的所有字段。任何需要引用它的脚本都可以添加类型为 GeneralGameData 的 public 字段并在检查器中添加该资产。

这是基于 Nailuj29s 答案的固定代码,但您不需要通过 public 字段来引用它,而您只需要使用 GeneralGameData.CurrentGeneralGameData.

public class GeneralGameData:ScriptableObject { 私人静态 GeneralGameData _currentGeneralGameData;

    public static GeneralGameData CurrentGeneralGameData
    {
        get
        {
            if (_currentGeneralGameData == null)
            {
                if (AssetDatabase.FindAssets("GeneralGameData", new []{ "Assets/CoreMaker" }).Length != 1)
                {
                    _currentGeneralGameData = CreateInstance<GeneralGameData>();

                    if (!AssetDatabase.IsValidFolder("Assets/CoreMaker"))
                    {
                        AssetDatabase.CreateFolder("Assets", "CoreMaker");
                    }

                    AssetDatabase.CreateAsset(_currentGeneralGameData,"Assets/CoreMaker/GeneralGameData.asset");
                }
            }

            _currentGeneralGameData = AssetDatabase.LoadAssetAtPath<GeneralGameData>("Assets/CoreMaker/GeneralGameData.asset");

            return _currentGeneralGameData;
        }
    }

    public string GameName;
  

    public string GameVersion;
    
}

请记住,当您引用 GeneralGameData.CurrentGeneralGameData 时,它将创建和资产,如果您删除该资产,您将丢失数据。

您丢失数据的原因是人们有两种方式将 ScriptableObject 用于单例。关键区别在于静态值的设置方式。 (例如代码中的 _currentGeneralGameData = CreateInstance<GeneralGameData>() 行)

来自资产资源: 这是一个共享的“实际”object/file,存在于您的项目资源中。当您更改它时,更改是“永久的”(保存到该实际对象),我相信这就是您要寻找的。在您的情况下,这意味着简单地获取对现有资产资源的引用,而不是创建一个新实例,类似于:

_currentGeneralGameData = Resources.Load<GeneralGameData>("GeneralGameData");

_currentGeneralGameData = Resources.FindObjectsOfTypeAll<GeneralGameData>().FirstOrDefault();

注意:为清楚起见,跳过 verification/error 处理代码。 重要提示:运行时(独立)与编辑器将获得不同的行为:您可能需要在场景中明确引用 ScriptableObject 资产,以确保它没有被优化掉。更多详细信息,请访问:https://baraujo.net/unity3d-making-singletons-from-scriptableobjects-automatically/

来自资产的实例: 这是您当前的代码。您无需获取共享资产,而是创建一个全新的实例,与磁盘上保存的内容断开连接,这意味着您不会保存在运行时所做的任何更改。

这非常好,在某些情况下可能更可取,但如果您确实想保留更改,那么您应该使用资产资源方法。