进入播放模式时,ScriptableObject 不保存数据
ScriptableObject not saving data when entering play mode
我有以下可编写脚本的对象:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/SpawnManagerScriptableObject", order = 1)]
public class Style : ScriptableObject
{
public Texture2D[] textures;
public Sprite[] sprites;
public AnimationCurve animationCurve;
Sprite[] MakeSprites(Texture2D[] baseTextures){
Sprite[] output = new Sprite[baseTextures.Length];
for (int i = 0; i < baseTextures.Length; i++)
{
output[i] = MakeSprite(baseTextures[i]);
}
return output;
}
Sprite MakeSprite(Texture2D baseTexture)
{
Sprite sprite = Sprite.Create(baseTexture, new Rect(0, 0, baseTexture.width, baseTexture.height), new Vector2(baseTexture.width / 2f, baseTexture.height / 2f), Mathf.Max(baseTexture.width, baseTexture.height));
return sprite;
}
public void UpdateSprites()
{
sprites = MakeSprites(textures);
}
}
[CustomEditor(typeof(Style))]
public class customStyleEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
Style style = (Style) target;
if (GUILayout.Button("Update Sprites"))
{
style.UpdateSprites();
EditorUtility.SetDirty(target);
}
}
}
这与我预期的一样有效,但是当我进入播放模式时,sprites
字段重置为空,我很确定这与我的自定义编辑器脚本有关,但我已经尝试过几次修复都没有成功。
包括:
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(target)
我尝试过的所有其他方法都导致了错误。
那么,这是什么问题,我该如何解决?
看起来精灵被保存为对统一资产的引用,而不是被序列化。所以看来需要是项目中保存的精灵才可以这样保存。
这意味着,如果您生成的精灵未存储在项目中,那么它将丢失引用,因为它唯一存储的地方是内存,在开始播放模式时会被擦除。
如果您查看资产文件,您就会真正了解它是如何存储它的。
如果我将图像拖入纹理和精灵中,这就是它的样子。看到 guid 和 fileId 都是相同的,并且引用了它在项目中的图像。 (这将在播放和编辑模式之间保持)
textures:
- {fileID: 2800000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
- {fileID: 2800000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
sprites:
- {fileID: 21300000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
- {fileID: 21300000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
然而,当我 运行 提供的代码并保存时,这就是保存的内容:
textures:
- {fileID: 2800000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
- {fileID: 2800000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
sprites:
- {fileID: 0}
- {fileID: 0}
它不是在保存精灵,而是对它不存在的引用。当内存重置后该对象不再存在时,它现在缺少一个引用,该引用被转换为 null。
所以要解决这个问题,您可以将精灵保存到单独的文件中,或者您可以在开始时生成它们。类型 sprite 无法正确序列化,因此如果要缓存它,则必须将其存储在不同的数据类型中。
这是在项目中保存精灵缓存的方法。请注意,您必须对精灵进行一些管理,以确保删除旧精灵。
Sprite[] MakeSprites(Texture2D[] baseTextures){
Sprite[] output = new Sprite[baseTextures.Length];
for (int i = 0; i < baseTextures.Length; i++)
{
output[i] = MakeSprite(baseTextures[i]);
}
//Now save the sprites to the project
List<Sprite> savedSprites = new List<Sprite>();
foreach (Sprite sprite in output)
{
//Create a sprite name, make sure it's prefixed with Assets/ as the assetDatabase won't like it otherwise
string spriteName = "Assets/" + Guid.NewGuid().ToString() + ".asset";
//Create the asset
AssetDatabase.CreateAsset(sprite, spriteName);
//Load the asset back in so we have a reference to the asset that exists in the project and not the reference to the sprite in memory
Sprite newSavedSprite = (Sprite)AssetDatabase.LoadAssetAtPath(spriteName, typeof(Sprite));
savedSprites.Add(newSavedSprite);
}
return savedSprites.ToArray();
}
我有以下可编写脚本的对象:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/SpawnManagerScriptableObject", order = 1)]
public class Style : ScriptableObject
{
public Texture2D[] textures;
public Sprite[] sprites;
public AnimationCurve animationCurve;
Sprite[] MakeSprites(Texture2D[] baseTextures){
Sprite[] output = new Sprite[baseTextures.Length];
for (int i = 0; i < baseTextures.Length; i++)
{
output[i] = MakeSprite(baseTextures[i]);
}
return output;
}
Sprite MakeSprite(Texture2D baseTexture)
{
Sprite sprite = Sprite.Create(baseTexture, new Rect(0, 0, baseTexture.width, baseTexture.height), new Vector2(baseTexture.width / 2f, baseTexture.height / 2f), Mathf.Max(baseTexture.width, baseTexture.height));
return sprite;
}
public void UpdateSprites()
{
sprites = MakeSprites(textures);
}
}
[CustomEditor(typeof(Style))]
public class customStyleEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
Style style = (Style) target;
if (GUILayout.Button("Update Sprites"))
{
style.UpdateSprites();
EditorUtility.SetDirty(target);
}
}
}
这与我预期的一样有效,但是当我进入播放模式时,sprites
字段重置为空,我很确定这与我的自定义编辑器脚本有关,但我已经尝试过几次修复都没有成功。
包括:
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(target)
我尝试过的所有其他方法都导致了错误。
那么,这是什么问题,我该如何解决?
看起来精灵被保存为对统一资产的引用,而不是被序列化。所以看来需要是项目中保存的精灵才可以这样保存。
这意味着,如果您生成的精灵未存储在项目中,那么它将丢失引用,因为它唯一存储的地方是内存,在开始播放模式时会被擦除。
如果您查看资产文件,您就会真正了解它是如何存储它的。 如果我将图像拖入纹理和精灵中,这就是它的样子。看到 guid 和 fileId 都是相同的,并且引用了它在项目中的图像。 (这将在播放和编辑模式之间保持)
textures:
- {fileID: 2800000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
- {fileID: 2800000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
sprites:
- {fileID: 21300000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
- {fileID: 21300000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
然而,当我 运行 提供的代码并保存时,这就是保存的内容:
textures:
- {fileID: 2800000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
- {fileID: 2800000, guid: e8a45d89f3b96e44e82022b97a4860a3, type: 3}
sprites:
- {fileID: 0}
- {fileID: 0}
它不是在保存精灵,而是对它不存在的引用。当内存重置后该对象不再存在时,它现在缺少一个引用,该引用被转换为 null。
所以要解决这个问题,您可以将精灵保存到单独的文件中,或者您可以在开始时生成它们。类型 sprite 无法正确序列化,因此如果要缓存它,则必须将其存储在不同的数据类型中。
这是在项目中保存精灵缓存的方法。请注意,您必须对精灵进行一些管理,以确保删除旧精灵。
Sprite[] MakeSprites(Texture2D[] baseTextures){
Sprite[] output = new Sprite[baseTextures.Length];
for (int i = 0; i < baseTextures.Length; i++)
{
output[i] = MakeSprite(baseTextures[i]);
}
//Now save the sprites to the project
List<Sprite> savedSprites = new List<Sprite>();
foreach (Sprite sprite in output)
{
//Create a sprite name, make sure it's prefixed with Assets/ as the assetDatabase won't like it otherwise
string spriteName = "Assets/" + Guid.NewGuid().ToString() + ".asset";
//Create the asset
AssetDatabase.CreateAsset(sprite, spriteName);
//Load the asset back in so we have a reference to the asset that exists in the project and not the reference to the sprite in memory
Sprite newSavedSprite = (Sprite)AssetDatabase.LoadAssetAtPath(spriteName, typeof(Sprite));
savedSprites.Add(newSavedSprite);
}
return savedSprites.ToArray();
}