Unity 5 Atlas at runtime basic solution

I’ve ran into many threads talking about unity Atlas and changing sprites in code. Some came up with solutions that load all sprites and index them, or used animations to swap between sprites in a sheet.

I needed an atlas solution that allows me to swap easily between sprite but also load/unload the atlas at runtime, as it would sometime not be needed and take memory for no reason.

Here’s the code I came solution I came up with:

  1. Create an empty GameObject, it will be used to prefab our atlas.

  2. Create an Atlas.cs code file, and drop the following code in it:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;

    public class Atlas : MonoBehaviour
    {
        [System.Serializable]
        public class SpritePair
        {
            public string m_spriteName;
            public Sprite m_sprite;
        }

        protected static Atlas s_atlas;

        private List<Texture> m_assets = new List<Texture>();
        private List<Image> m_atlasReferences;

        public List<SpritePair> m_spritesList;
        private Dictionary<string, Sprite> m_atlasSprites;

        void Awake()
        {
            //init static reference and list
            s_atlas = this;
            m_atlasReferences = new List<Image>();

            //convert list to dictionary, for faster lookup
            m_atlasSprites = new Dictionary<string,Sprite>();
            foreach (SpritePair pair in m_spritesList)
            {
                m_atlasSprites.Add(pair.m_spriteName, pair.m_sprite);
            }
        }

        Sprite GetSprite(string zSpriteName)
        {
            Sprite sprite = null;

            //fetch sprite in dictionary
            if (m_atlasSprites.ContainsKey(zSpriteName))
                sprite = m_atlasSprites[zSpriteName];
            return sprite;
        }

        public static void AssignSprite(Image zImage, string zSpriteName)
        {
            s_atlas.SetSprite(zImage, zSpriteName);
        }

        protected void SetSprite(Image zImage, string zSpriteName)
        {
            if (!m_atlasReferences.Contains(zImage))
            {
                //add reference
                m_atlasReferences.Add(zImage);
            }

            //assign sprite to image
            Sprite sprite = s_atlas.GetSprite(zSpriteName);
            zImage.sprite = sprite;

            //keep reference of the atlas texture loaded with this sprite
            if (!m_assets.Contains(zImage.mainTexture))
                m_assets.Add(zImage.mainTexture);
        }

        public static void RemoveSprite(Image zImage)
        {
            s_atlas.DeleteSprite(zImage);
        }

        protected void DeleteSprite(Image zImage)
        {
            //clean-up sprite and atlas reference
            if (m_atlasReferences.Contains(zImage))
            {
                m_atlasReferences.Remove(zImage);
                zImage.sprite = null;
            }
        }

        void CleanUp()
        {
            //clear images refering the atlas
            foreach (Image img in m_atlasReferences)
                img.sprite = null;
            m_atlasReferences.Clear();
                      
            //clean-up list and dictionary
            m_spritesList.Clear();
            m_atlasSprites.Clear();

            //finally unload atlas textures
            for (int i = 0; i < m_assets.Count; i++)
            {
                Resources.UnloadAsset(m_assets[i]);
                m_assets[i] = null;
            }
            m_assets.Clear();
        }

        public static void DestroyAtlas()
        {
            GameObject obj = s_atlas.gameObject;
            s_atlas.CleanUp();
            s_atlas = null;
            Destroy(obj);
        }
}
  1. Drop the script on the empty object we created in 1

  2. Populate the object by creating SpriteName and Sprite pairs (in editor)

  3. Prefab it by dragging the object into your Resources folder.

So that’s our atlas created.

How to use:

  • You first need to do a Resources.Load<GameObject>("Path/YourAtlasName"); so it is added to your scene.

  • Then, you need an image in your scene, and assign it with the static function, like so:

public Image someImage;

...

Atlas.AssignSprite(someImage, "spriteName");
  • When you are done with a sprite, you can clean it up by doing:Atlas.RemoveSprite(someImage);

  • Finally, when you are done with it, clean-up the atlas and all the sprite being referenced from it

Atlas.DestroyAtlas();

Careful:
Destroying the atlas, removes all the sprite referenced from images. It also delete the atlas texture from memory. So I suggest that you be careful that all sprites in that atlas are using the same Packing Tag.

If you want to use more than one atlas, I suggest creating sub-classes to the Atlas, and creating a prefab with the script on it for each.

I hope it helps some people.

1 Like

Thank you! It’s work perfectly!

You dont need to load the atlas with resource load, this load the atlas in runtime so it’s better to just drop the atlas prefab in the hierachy to use it.