I'm struggling with an issue in Unity loading Sprites from a SpriteAtlas, downloaded in an AssetBundle.
In our current game I am trying to implement AssetBundles to remove "Resources" folder usage, and reduce memory overhead (among other things).
In the Game app, the downloaded sprites aren't rendering correctly when running in the editor, so I built a small test project to better understand the problem. Unfortunately the test project works perfectly, even though I'm using identical code to download and display the sprites. I'll refer to these two versions as TestApp and GameApp from here on. Just to reiterate, this issue is only a problem when running in the Editor (not the final device builds), however this is a game breaker for us because we simply can't develop and test the application. The turnaround getting builds to device is simply too long compared to running in the Editor.
A simplified version of the script that I use for loading asset bundles is as follows. (This has been hugely simplified for brievity, including stripping out all object caching and error handling, etc)
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);
}
The script that I use to call this to load the Sprite is as follows, (again error handling is stripped out):
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;
})
);
}
The end result of this is that everything works and loads correctly in the TestApp, but when playing the GameApp in the editor, the sprites are either invisible, or display as a weird image with 3 squares in it.
The only difference that I can see is that when I use the frame debugger to look at the differences between the TestApp and the GameApp, the TestApp shows the SpriteAtlas texture in the batch, but the GameApp does not.
As you can see here in the TestApp, the Texture is correctly set.
And here in the GameApp, the texture is not set
Things that I have checked and confirmed between versions
- Neither the GameApp nor the TestApp has any errors or exceptions.
- It works correctly when built and deployed to a device (Only tested on Android so far)
- A sprite object IS being returned in the onLoadAction callback in the GameApp.
- I'm using the same AssetBundles and Sprites in both applications.
- I've done side by side comparisons of the Image object settings in the inspector in both apps.
- Both apps are set to the same build platform (I've tried Android, WebGL, and StandaloneWindows, and all have the same result)
- The AssetBundles are built for the correct build platform (as above)
The only difference that I can see between the TestApp and the GameApp is that the GameApp is much larger / more complex, and it has a scene change (we start with a loading scene before going to the in-game scene), but I don't see how either of those should affect anything.
I've also set up and tested a version using AssetBundle.LoadFromFileAsync() and loading the file from the StreamingAssets folder, with the same results
So, my questions: Is this a bug in the Unity Editor? What should I be looking at to try and fix this? We basically can't use AssetBundles until I find a solution.
I've used the AssetBundleBrowser asset to set up the AssetBundles.
I've tested with various versions of Unity, from older 2018.1 releases up to the latest release (2018.2.7f1 at the time of writing).
(Cross posted from the Unity Forums)
--- Update ---
It's been mentioned that this is a duplicate question this question , however I am asking an entirely different question. My code works correctly on a device, but does not work in the Unity Editor.
I have also tried restructuring my code to query for a Sprite rather than a SpriteAtlas, and using the LoadAssetWithSubAssetsAsync method, with the following code, and I am still having the same end result of no sprite being displayed in the editor.
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);
}