【问题标题】:Issues displaying Sprites loaded from AssetBundle in Editor Play mode在编辑器播放模式下显示从 AssetBundle 加载的 Sprite 的问题
【发布时间】:2018-09-25 04:03:31
【问题描述】:

我在解决 Unity 从 SpriteAtlas 加载 Sprites 时遇到的问题,下载到 AssetBundle 中。

在我们当前的游戏中,我正在尝试实现 AssetBundles 以消除“资源”文件夹的使用,并减少内存开销(除其他外)。

在游戏应用程序中,下载的精灵在编辑器中运行时无法正确渲染,因此我构建了一个小型测试项目以更好地了解问题。不幸的是,测试项目运行良好,即使我使用相同的代码来下载和显示精灵。从这里开始,我将这两个版本称为 TestAppGameApp。重申一下,这个问题只是在编辑器中运行时出现的问题(不是最终的设备构建),但这对我们来说是一个游戏破坏者,因为我们根本无法开发和测试应用程序。与在编辑器中运行相比,构建到设备的周转时间实在是太长了。

我用于加载资产包的脚本的简化版本如下。 (为简洁起见,这已被大大简化,包括剥离所有对象缓存和错误处理等)

public IEnumerator GetSpriteFromBundle(string bundleURL, string spriteAtlasName, string spriteName, Action<Sprite> onLoadAction)
{
    //  get the AssetBundle
    AssetBundle bundle = null;
    UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(bundleURL);
    yield return request.SendWebRequest();
    if (!request.isNetworkError && !request.isHttpError)
    {
        bundle = DownloadHandlerAssetBundle.GetContent(request);
    }

    //  Get the SpriteAtlas
    SpriteAtlas atlas = null;
    if (bundle != null)
    {
        if (bundle.Contains(spriteAtlasName))
        {
            AssetBundleRequest assetRequest = bundle.LoadAssetAsync<SpriteAtlas>(spriteAtlasName);
            yield return assetRequest;
            if (assetRequest.isDone)
            {
                atlas = assetRequest.asset as SpriteAtlas;
            }
        }
    }

    //  Get the Sprite
    Sprite sprite = null;
    if (atlas != null)
    {
        sprite = atlas.GetSprite(spriteName);
    }
    onLoadAction(sprite);
}

我用来调用它来加载 Sprite 的脚本如下,(再次删除了错误处理):

public void Start()
{
    UnityEngine.UI.Image displayImage = GameObject.Find("Path/To/ImageObject").GetComponent<UnityEngine.UI.Image>();
    StartCoroutine(
         GetSpriteFromBundle(
            "https://mycdn.com/myassetbundles/gamesprites",      // AssetBundleURL
            "GameSprites",          //    SpriteAssetName
            "Icon1",                      //    SpriteName
            (sprite) =>
            {
                displayImage.sprite = sprite;
            })
        );
}

这样做的最终结果是 TestApp 中的一切正常工作并正确加载,但在编辑器中播放 GameApp 时,精灵要么不可见,要么显示为包含 3 个正方形的奇怪图像。

我能看到的唯一区别是,当我使用帧调试器查看TestApp和GameApp之间的差异时,TestApp在批处理中显示SpriteAtlas纹理,而GameApp没有。

正如您在 TestApp 中看到的,纹理设置正确。

在 GameApp 中,没有设置纹理

我在不同版本之间检查并确认的内容

  • GameApp 和 TestApp 都没有任何错误或异常。
  • 在构建和部署到设备时可以正常工作(仅在 Android 到目前为止)
  • 在 GameApp 的 onLoadAction 回调中返回一个精灵对象。
  • 我在两个应用程序中使用相同的 AssetBundle 和 Sprite。
  • 我已经在两个应用程序的检查器中对图像对象设置进行了并排比较。
  • 两个应用程序都设置为相同的构建平台(我尝试过 Android、WebGL 和 StandaloneWindows,并且都具有相同的结果)
  • AssetBundle 是 为正确的构建平台构建(如上)

我可以看到 TestApp 和 GameApp 之间的唯一区别是 GameApp 更大/更复杂,并且它具有场景变化(我们从加载场景开始,然后进入游戏内场景),但我看不出其中任何一个会如何影响任何事情。

我还使用 AssetBundle.LoadFromFileAsync() 设置并测试了一个版本,并从 StreamingAssets 文件夹加载文件,结果相同

所以,我的问题: 这是 Unity 编辑器中的错误吗?我应该看什么来尝试解决这个问题?在我找到解决方案之前,我们基本上不能使用 AssetBundles。

我已使用 AssetBundleBrowser 资产来设置 AssetBundle。

我已经使用各种版本的 Unity 进行了测试,从较旧的 2018.1 版本到最新版本(撰写本文时为 2018.2.7f1)。

(发自Unity Forums

--- 更新---

有人提到这是一个重复的问题this question,但是我问的是一个完全不同的问题。 我的代码在设备上正常工作,但在 Unity 编辑器中不起作用。

我还尝试重组我的代码以查询 Sprite 而不是 SpriteAtlas,并使用 LoadAssetWithSubAssetsAsync 方法和以下代码,但我仍然得到相同的最终结果,即编辑器中没有显示精灵。

private IEnumerator GetSpriteFromBundle(string bundleURL, string spriteName, Action<Sprite> onLoadAction)
{
    //  get the AssetBundle
    AssetBundle bundle = null;
    UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(bundleURL);
    yield return request.SendWebRequest();
    if (!request.isNetworkError && !request.isHttpError)
    {
        bundle = DownloadHandlerAssetBundle.GetContent(request);
    }

    //  Get the Sprite
    Sprite sprite = null;
    if (bundle != null)
    {
        if (bundle.Contains(spriteName))
        {
            AssetBundleRequest assetRequest = bundle.LoadAssetWithSubAssetsAsync<Sprite>(spriteName);
            yield return assetRequest;
            if (assetRequest.isDone)
            {
                for (int i = 0; i < assetRequest.allAssets.Length; i++)
                {
                    sprite = assetRequest.allAssets[i] as Sprite;
                    if (sprite != null && sprite.name == spriteName)
                    {
                        onLoadAction(sprite);
                        yield break;
                    }
                }
            }
        }
    }
    onLoadAction(null);
}

【问题讨论】:

  • 文档中没有关于从 AssetBundle 加载精灵图集的官方示例。这使人们开始为此使用SpriteAtlas。我认为这是错误的。 1. 您将其加载为Sprite 而不是SpriteAtlas2. 您可以使用 LoadAssetWithSubAssetsAsync 函数而不是 LoadAssetAsync 函数来执行此操作。 3. 要访问加载的 Sprite 地图集,您不要使用assetRequest.asset,而是使用assetRequest.allAssets,它返回所有 Sprite 地图集的数组。有关完整的工作示例,请参阅副本。
  • 我已经尝试过您提出的直接查询 Sprite(而不是 SpriteAtlas)的建议,但最终结果仍然相同。
  • 您的原始问题说它在编辑器中不起作用。在尝试了我的解决方案后,编辑说它在浏览器中不起作用。我不确定你的意思是什么,或者你现在的问题是什么......
  • 哦,很好的发现,很抱歉造成混乱。我的意思是它在播放模式下的编辑器中不起作用(不是浏览器)。
  • 在您问题的更新中,您需要添加您正在使用的新代码,然后是您的使用方式。

标签: unity3d assetbundle


【解决方案1】:

原来问题是由 SpritePacker 设置引起的。

如果我将 SpritePacker 模式(在 Edit->Project Settings->Editor 中)设置为“Enabled for Builds”,则精灵不会正确加载,而如果我将其设置为“Always Enabled”(我相信默认设置) ) 然后是精灵,SpriteAtlas 会从 AssetBundle 中正确加载。

(我已将此作为 Unity 的错误提出,但尚未收到回复)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-03
    • 2014-11-23
    • 1970-01-01
    相关资源
    最近更新 更多