Search code examples
c#unity-game-enginetexturesspritetexture2d

Combine Array of Sprite objects into One Sprite - Unity


I have an array of Sprite objects in Unity. Their size vary depending on the image loaded. I want to combine them side by side like a tiled map into one image. I want them to be layout like your are forming a line of images, one after the other. (note: NOT one on top of the other) How may I be able to do this?

The reason why I'm combining (just for those who want to know) is because I'm using a polygon2D Collider. Since there are some weird behaviors happening when I use multiple colliders side by side, I decided to just combine the images before adding one big polygon collider. Note that these things happen during runtime. I can't just create a big image and load that because the order of the images is only determined at runtime.

I hope to receive some help with this. Thanks.


Solution

  • There is PackTextures method in Texture2D class, but since it makes your atlas square you can't make a line of sprites, so there is another way to do it by reading pixels of images and setting them to new image,it's really expensive to do in runtime but gives you the result.

    // Your textures to combine
    // !! After importing as sprite change to advance mode and enable read and write property !!
    public Sprite[] textures;
    
    public Texture2D atlas;    // Just to see on editor nothing to add from editor
    public Material testMaterial;
    public SpriteRenderer testSpriteRenderer;
    
    int textureWidthCounter = 0;
    int width,height;
    private void Start () {
        width = 0;
        height = 0;
    
        foreach(var  t in textures) {
            width += t.texture.width;
            
            if (t.texture.height > height)
                height = t.texture.height;
        }
        
        atlas = new Texture2D(width,height, TextureFormat.RGBA32,false);
        
        for (int i = 0; i < textures.Length; i++)
        {
            int y = 0;
    
            while (y < atlas.height) {
                int x = 0;
    
                while (x < textures[i].texture.width ) {
                    if (y < textures[i].texture.height) 
                         atlas.SetPixel(x + textureWidthCounter, y, textures[i].texture.GetPixel(x, y));  // Fill your texture
                    else atlas.SetPixel(x + textureWidthCounter, y,new Color(0f,0f,0f,0f));  // Add transparency
                    x++;
                }
                y++;
            }
            atlas.Apply();
            textureWidthCounter +=  textures[i].texture.width;
        }
        
        // For normal renderers
        if (testMaterial != null)
            testMaterial.mainTexture = atlas;
    
        // for sprite renderer just make  a sprite from texture
        var s = Sprite.Create(atlas, new Rect(0f, 0f, atlas.width, atlas.height), new Vector2(0.5f, 0.5f));
        testSpriteRenderer.sprite = s;
    
        // add your polygon collider
        testSpriteRenderer.gameObject.AddComponent<PolygonCollider2D>();
    }