Symptoms
- Sprite Atlas is not packed in an AssetBundle.
- I can preview the sprite in the Scene, but not in the game.
- I don't know how to use Late Binding with Sprite Atlas.
Resolution
A Sprite can be set as “packed but not referencing any atlas” by not including the atlas in the player build, meaning the sprite appears blank until Unity binds a Sprite Atlas to it. This is called “late binding”. This article describes how to do this.
The benefit of this behavior is that it allows you to have the chance to do late binding if the source of the Sprite Atlas is not available during start-up. This often happens when loading Assets from AssetBundles.
Another benefit of late binding is that it allows you to decide based on your logic which Sprite to use; for example, you could have a high/ low-resolution Sprite Atlas, or you could have one Sprite Atlas per region (JP/EU/SD/HD).
In the Sprite Atlas’s Inspector window, there is a checkbox called Include in Build. This checkbox configures Unity to include the Sprite Atlas in the final build of the player and in AssetBundles. This also affects the build-in Editor mode; if the checkbox is disabled, Unity can no longer automatically load the Sprite Atlas for a Sprite. This means you need to use "late binding" to bind the Sprite Atlas when entering Play Mode, otherwise, your sprites will appear blank.
This check box doesn't affect the AssetBundle build since the Asset Bundle system will pack the reference by default. However, the loading method of the sprite will change.
If you want to pack the Sprite Atlas into an AssetBundle and Include in Build is checked, then you are using Late-binding and it will automatically load the Atlas.
Tip
If for any reason you need to disable the Atlas Include in Build option, you can enable or disable this checkbox via scripting; see the example in the following section.
SpriteAtlasManager.atlasRequested
atlasRequested is a callback that tells you when a Sprite is requested which is not included in the build. You need to manually load the Sprite Atlas and send it to Unity.
Here is an example that shows how to pack a Sprite Atlas into an AssetBundle. This example enables the Include in build option to include the atlas in the Asset Bundle. It then disables that option again, so that it doesn’t include the Sprite Atlas Asset in the player build. Normally, it should not be necessary if there is nothing in the built-in scenes of the player that references the sprites.
public static void BuildBundles(BuildAssetBundleOptions options, string outputPath) { EnableAtlasForBundles(); BuildTarget target = EditorUserBuildSettings.activeBuildTarget; BuildPipeline.BuildAssetBundles(outputPath, options, target); DisableAtlas(); } static void EnableDisableAtlas(bool enable) { string[] paths = AssetDatabase.FindAssets("t:SpriteAtlas"); foreach (var path in paths) { SpriteAtlas atlas = (SpriteAtlas)AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(path), typeof(SpriteAtlas)); SerializedObject so = new SerializedObject(atlas); SerializedProperty AtlasEditorData = so.FindProperty("m_EditorData"); SerializedProperty includeInBuild = AtlasEditorData.FindPropertyRelative("bindAsDefault"); includeInBuild.boolValue = enable; so.ApplyModifiedProperties(); EditorUtility.SetDirty(atlas); AssetDatabase.Refresh(); } }
The example below demonstrates how to set up the callback to load the Sprite Atlas from an AssetBundle using the late-binding method.
void OnEnable() { SpriteAtlasManager.atlasRequested += RequestAtlas; } void OnDisable() { SpriteAtlasManager.atlasRequested -= RequestAtlas; } void RequestAtlas(string tag, System.Action callback) { if (spriteAtlas == null) { StartCoroutine(LoadFromStreammingAsset(callback)); } else { callback(spriteAtlas); } } IEnumerator LoadFromStreammingAsset(System.Action callback) { string path = Application.streamingAssetsPath + "/" + bundleName; print(path); AssetBundleCreateRequest bundleLoadRequest = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + bundleName); yield return bundleLoadRequest; bundle = bundleLoadRequest.assetBundle; if (bundle == null) { Debug.Log("Failed to load AssetBundle!"); yield break; } SpriteAtlas spriteAtlas = bundle.LoadAsset(bundleName); callback(spriteAtlas); }
More information
https://docs.unity3d.com/Manual/class-SpriteAtlas.html
https://docs.unity3d.com/Manual/SpriteAtlasDistribution.html
https://docs.unity3d.com/ScriptReference/U2D.SpriteAtlasManager-atlasRequested.html
Comments
0 comments
Article is closed for comments.