进入播放模式时,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();
}