【发布时间】:2018-09-25 04:03:31
【问题描述】:
我在解决 Unity 从 SpriteAtlas 加载 Sprites 时遇到的问题,下载到 AssetBundle 中。
在我们当前的游戏中,我正在尝试实现 AssetBundles 以消除“资源”文件夹的使用,并减少内存开销(除其他外)。
在游戏应用程序中,下载的精灵在编辑器中运行时无法正确渲染,因此我构建了一个小型测试项目以更好地了解问题。不幸的是,测试项目运行良好,即使我使用相同的代码来下载和显示精灵。从这里开始,我将这两个版本称为 TestApp 和 GameApp。重申一下,这个问题只是在编辑器中运行时出现的问题(不是最终的设备构建),但这对我们来说是一个游戏破坏者,因为我们根本无法开发和测试应用程序。与在编辑器中运行相比,构建到设备的周转时间实在是太长了。
我用于加载资产包的脚本的简化版本如下。 (为简洁起见,这已被大大简化,包括剥离所有对象缓存和错误处理等)
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没有。
我在不同版本之间检查并确认的内容
- 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而不是SpriteAtlas。 2. 您可以使用LoadAssetWithSubAssetsAsync函数而不是LoadAssetAsync函数来执行此操作。 3. 要访问加载的 Sprite 地图集,您不要使用assetRequest.asset,而是使用assetRequest.allAssets,它返回所有 Sprite 地图集的数组。有关完整的工作示例,请参阅副本。 -
我已经尝试过您提出的直接查询 Sprite(而不是 SpriteAtlas)的建议,但最终结果仍然相同。
-
您的原始问题说它在编辑器中不起作用。在尝试了我的解决方案后,编辑说它在浏览器中不起作用。我不确定你的意思是什么,或者你现在的问题是什么......
-
哦,很好的发现,很抱歉造成混乱。我的意思是它在播放模式下的编辑器中不起作用(不是浏览器)。
-
在您问题的更新中,您需要添加您正在使用的新代码,然后是您的使用方式。
标签: unity3d assetbundle