Unity打包游戏时AssetDatabase无法使用,求替代方案
问题描述
我使用AssetDatabase制作关卡编辑器,每个对象都保存为单独的asset文件。但Unity打包游戏时无法使用AssetDatabase,将含AssetDatabase的脚本放入Editor文件夹或添加#if UNITY_EDITOR标记的方案,打包后无法生效,不符合需求。曾三次尝试用JSON保存文件但未成功,打包时出现报错:"The name 'AssetDatabase' does not exist in the current context"。现寻求可用于打包游戏的AssetDatabase替代工具或Unity Asset Store中的相关资源。
现有实现代码
using System.IO; using UnityEditor; using UnityEngine; using UnityEngine.Rendering.Universal; using DG.Tweening; [CreateAssetMenu(fileName = "Level Object", menuName = "Level Object")] public class ObjectProperty : ScriptableObject { [Header("Main")] public string objectName; public string shape = "Ball"; public Vector2 position = Vector2.zero; public float rotation = 0; public int sortingOrder; public Color color = Color.white; public float opacity = 1f; public bool glow = false; public float glowIntensity = .2f; public float glowRadius = 1f; public float glowSmoothness = .5f; [Header("Extended")] public float spawnDelay = 0f; public float movingSpeed = 5f; public float rotationSpeed = 1f; public Ease easing = Ease.InOutCubic; public static int number = 1; public static string assetPath = "Assets/Scripts/LevelEditor/Object/ObjectSaving/LevelTest"; public static GameObject CreateObjectByAsset(ObjectProperty data) // Reads asset file at the given path and spawns the GameObject from the file data { GameObject spawnedObject = Instantiate(Resources.Load<GameObject>($"Objects/EditorPrefabs/{data.shape}"), data.position, Quaternion.Euler(0f, 0f, data.rotation)); SpriteRenderer renderer = spawnedObject.GetComponent<SpriteRenderer>(); Light2D glow = spawnedObject.GetComponent<Light2D>(); spawnedObject.name = data.objectName; renderer.color = new(data.color.r, data.color.g, data.color.b, data.opacity); renderer.sortingOrder = data.sortingOrder; glow.enabled = data.glow; glow.color = renderer.color; glow.intensity = data.glowIntensity; glow.pointLightOuterRadius = data.glowRadius; glow.falloffIntensity = data.glowSmoothness; return spawnedObject; } public static ObjectProperty SaveGameObjectInAsset(GameObject obj) // Saves the GameObject to an asset file with return ability { SpriteRenderer renderer = obj.GetComponent<SpriteRenderer>(); Light2D glow = obj.GetComponent<Light2D>(); if (Directory.GetFiles(assetPath).Length == 0) number = 1; while (File.Exists($"{assetPath}/{number}.asset")) number++; ObjectProperty data = CreateInstance<ObjectProperty>(); data.objectName = obj.name; data.shape = renderer.sprite.name; data.position = obj.transform.position; data.rotation = obj.transform.rotation.eulerAngles.z; data.sortingOrder = renderer.sortingOrder; data.color = new(renderer.color.r, renderer.color.g, renderer.color.b); data.opacity = renderer.color.a; data.glow = glow.enabled; data.glowIntensity = glow.intensity; data.glowRadius = glow.pointLightOuterRadius; data.glowSmoothness = glow.falloffIntensity; AssetDatabase.CreateAsset(data, $"{assetPath}/{number}.asset"); ObjectProperty asset = AssetDatabase.LoadAssetAtPath<ObjectProperty>($"{assetPath}/{number}.asset"); return asset; } public static ObjectProperty FindAssetByNumber(int number) // Finds an asset file by number: Obj1, Obj2, Obj3... { ObjectProperty data = AssetDatabase.LoadAssetAtPath<ObjectProperty>($"{assetPath}/{number}.asset"); return data; } public static ObjectProperty[] GetObjectProperties() { string[] guids = AssetDatabase.FindAssets($"t:{nameof(ObjectProperty)}", new[] {ObjectProperty.assetPath}); ObjectProperty[] datas = new ObjectProperty[guids.Length]; for (int i = 0; i < guids.Length; i++) { string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]); datas[i] = AssetDatabase.LoadAssetAtPath<ObjectProperty>(assetPath); } return datas; } public static void DeleteAsset(int number) // Finds an ObjectProperty asset and deletes it { AssetDatabase.DeleteAsset($"{assetPath}/{number}.asset"); } public static void ClearAllAssets() // Clears all the assets in the ObjectProperty assets directory and resets the number { string[] files = Directory.GetFiles(assetPath); foreach (string file in files) File.Delete(file); number = 1; PlayerPrefs.SetInt("number", number); AssetDatabase.Refresh(); PlayerPrefs.Save(); } public static void SaveAssets() => AssetDatabase.SaveAssets(); }
解决方案建议
一、原生替代方案(无需第三方资源)
- ScriptableObject + JSON/二进制序列化:
放弃生成.asset文件,直接将ObjectProperty实例序列化为JSON或二进制数据,存储到Application.persistentDataPath(打包后可读写的目录)。修改现有代码中依赖AssetDatabase的方法:- 保存:用
JsonUtility.ToJson(data)将对象转为JSON字符串,通过File.WriteAllText()写入文件; - 加载:用
File.ReadAllText()读取文件内容,再通过JsonUtility.FromJson<ObjectProperty>(content)还原数据; - 注意:
ScriptableObject.CreateInstance在运行时仍可调用,用于创建数据实例。
- 保存:用
- Unity Addressables:
官方资源管理系统,支持运行时加载资源,打包后可正常使用。将关卡对象数据标记为Addressable资源,运行时通过地址或标签加载,替代AssetDatabase的资源查询与加载逻辑。
二、Unity Asset Store 第三方资源
- Easy Save 3:
成熟的序列化工具,支持多种数据格式(JSON、二进制等),可快速实现对象数据的本地存储与读取,兼容所有打包平台,无需手动处理复杂的IO逻辑。 - Save Game Pro:
功能全面的存档系统,支持ScriptableObject、GameObject状态的保存与加载,适配多平台,打包后稳定运行,内置数据加密功能。 - 关卡编辑器框架类插件:
如Level Builder、Pro Level Editor等现成关卡编辑器插件,自带运行时关卡加载功能,已内置AssetDatabase的替代方案,可直接集成到现有项目中。
内容的提问来源于stack exchange,提问作者Fr33zE
相关产品推荐
相关产品推荐

