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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 13:44:57