You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中ScriptableObject修改保存及兼容打包的场景构建方法咨询

解决Unity运行时保存ScriptableObject修改的方案

这个问题在Unity开发里太常见了——毕竟EditorUtility.SetDirty()和EditorSceneManager.MarkSceneDirty()这类API本来就是编辑器专属的,打包后完全无法使用。要实现构建包内的持久化修改,核心思路是将ScriptableObject的数据序列化到本地可写目录的文件中,而不是依赖编辑器的资产脏标记机制。

具体实现步骤

1. 确保ScriptableObject类可序列化

首先,你的ScriptableObject类需要保证字段能被Unity序列化(公开字段默认支持,私有字段可加[SerializeField]标记):

using UnityEngine;

[CreateAssetMenu(fileName = "PlayerSettings", menuName = "ScriptableObjects/PlayerSettings")]
public class PlayerSettings : ScriptableObject
{
    public int highScore;
    public string playerNickname;
    [SerializeField] private float soundVolume; // 私有字段也能被序列化
    
    // 封装私有字段的修改逻辑
    public void SetSoundVolume(float volume)
    {
        soundVolume = Mathf.Clamp(volume, 0f, 1f);
    }
}

2. 编写保存方法:序列化到本地文件

用Unity自带的JsonUtility把数据转成JSON格式,存储到Application.persistentDataPath——这个目录在所有平台都是可写的,适合保存用户自定义数据:

using System.IO;
using UnityEngine;

public static class SaveManager
{
    // 通用保存方法,支持任意ScriptableObject子类
    public static void SaveScriptableObject<T>(T data, string fileName) where T : ScriptableObject
    {
        string json = JsonUtility.ToJson(data);
        string savePath = Path.Combine(Application.persistentDataPath, $"{fileName}.json");
        File.WriteAllText(savePath, json);
    }
}

3. 编写加载方法:从文件恢复数据

加载时读取本地文件,用JsonUtility.FromJsonOverwrite()直接覆盖已有ScriptableObject实例的字段,这样能保持原有的引用关系,避免出现新实例导致的引用丢失问题:

public static class SaveManager
{
    // 上面的Save方法...
    
    // 通用加载方法,覆盖传入的ScriptableObject实例数据
    public static void LoadScriptableObject<T>(T data, string fileName) where T : ScriptableObject
    {
        string loadPath = Path.Combine(Application.persistentDataPath, $"{fileName}.json");
        if (File.Exists(loadPath))
        {
            string json = File.ReadAllText(loadPath);
            JsonUtility.FromJsonOverwrite(json, data);
        }
        // 如果文件不存在,保持原ScriptableObject的默认值
    }
}

4. 在业务代码中调用保存和加载

比如在游戏启动时加载数据,退出或用户修改设置时保存:

public class GameManager : MonoBehaviour
{
    public PlayerSettings playerSettings; // 在Inspector中引用你的ScriptableObject
    
    private void Start()
    {
        // 启动时加载之前保存的用户设置
        SaveManager.LoadScriptableObject(playerSettings, "PlayerSettings");
    }

    private void OnApplicationQuit()
    {
        // 退出游戏时保存当前设置
        SaveManager.SaveScriptableObject(playerSettings, "PlayerSettings");
    }

    // 用户修改设置后即时保存
    public void OnSettingsUpdated()
    {
        SaveManager.SaveScriptableObject(playerSettings, "PlayerSettings");
    }
}

额外优化建议

  • 编辑器与运行时兼容:如果你想在编辑器调试时依然能保存到原始资产文件(方便预览修改),可以用条件编译区分环境:
public void SaveSettings()
{
    #if UNITY_EDITOR
    UnityEditor.EditorUtility.SetDirty(this);
    UnityEditor.AssetDatabase.SaveAssets();
    #else
    SaveManager.SaveScriptableObject(this, "PlayerSettings");
    #endif
}

这样在编辑器中调试时用编辑器API保存到资产,打包后自动切换到文件存储。

  • 避免修改原始资产:打包后的原始ScriptableObject资产是只读的,绝对不要尝试修改它们,所有用户自定义数据都要通过序列化到persistentDataPath的文件来实现。

  • 复杂数据处理:如果你的ScriptableObject包含字典、自定义类等JsonUtility难以直接序列化的类型,可以实现ISerializationCallbackReceiver接口处理序列化逻辑,或者导入第三方序列化库(比如Newtonsoft Json的Unity适配包)。

内容的提问来源于stack exchange,提问作者user664653

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:14:40