unity3d - 在编辑器播放模式下显示从 AssetBundle 加载的 Sprite 的问题
问题描述
我正在努力解决 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,结果都相同)
- AssetBundles 是为正确的构建平台构建的(如上)
我可以看到 TestApp 和 GameApp 之间的唯一区别是 GameApp 更大/更复杂,并且它具有场景变化(我们从加载场景开始,然后进入游戏内场景),但我没有'不知道其中任何一个应该如何影响任何事情。
我还使用 AssetBundle.LoadFromFileAsync() 设置并测试了一个版本,并从 StreamingAssets 文件夹加载文件,结果相同
所以,我的问题是:这是 Unity 编辑器中的错误吗?我应该看什么来尝试解决这个问题?在我找到解决方案之前,我们基本上不能使用 AssetBundles。
我已经使用AssetBundleBrowser资产来设置 AssetBundle。
我已经使用各种版本的 Unity 进行了测试,从较旧的 2018.1 版本到最新版本(撰写本文时为 2018.2.7f1)。
(来自Unity 论坛的交叉发布)
- - 更新 - -
有人提到这是一个重复的问题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);
}
解决方案
事实证明,问题是由 SpritePacker 设置引起的。
如果我将 SpritePacker 模式(在 Edit->Project Settings->Editor 中)设置为“Enabled for Builds”,则精灵不会正确加载,而如果我将其设置为“Always Enabled”(我相信默认设置),那么sprites,并且 SpriteAtlas 已从 AssetBundle 正确加载。
(我已将此作为 Unity 的错误提出,但尚未收到回复)。
推荐阅读
- eclipse-plugin - STS 是否支持 spring 集成插件来查看集成流程?
- javascript - 如何正确检索 JQuery 中的值?
- c - 指向整数数组的指针与指向整数的双精度指针
- javascript - 按钮 Onclick 函数在加载时执行
- laravel-5 - VueJS:尽管数组中有对象,但 v-for 指令不渲染项目
- javascript - 提交通过推送器显示的实时表单时出现 419
- reactjs - 使用 React 中的 Axios 发出 http 请求以表达在预飞行后因 CORS 错误而失败。在服务器上启用了 CORS,但仍然无法正常工作
- regex - 匹配直到符号第一次出现
- reactjs - getDerivedStateFromError 后重置状态
- ios - UITextField 没有在 UIStackView 中归档可用宽度