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/
来自资产的实例:
这是您当前的代码。您无需获取共享资产,而是创建一个全新的实例,与磁盘上保存的内容断开连接,这意味着您不会保存在运行时所做的任何更改。
这非常好,在某些情况下可能更可取,但如果您确实想保留更改,那么您应该使用资产资源方法。
我有一个单例 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/
来自资产的实例: 这是您当前的代码。您无需获取共享资产,而是创建一个全新的实例,与磁盘上保存的内容断开连接,这意味着您不会保存在运行时所做的任何更改。
这非常好,在某些情况下可能更可取,但如果您确实想保留更改,那么您应该使用资产资源方法。