1

I would like to take a two-dimensional array of Sprites and turn it into one single sprite image at runtime. All sprites are square and exactly the same size, but the resulting image does not necessarily need to be square, as the width and height of the array can vary.

I have yet found this resource: Combine Array of Sprite objects into One Sprite - Unity

But I don't think it works for my purposes.

Community
  • 1
  • 1
uncanny
  • 65
  • 1
  • 10
  • If any answer solved your problem, please consider accepting it as the right one. _(Accepting an answer helps future visitors coming on this page)_ – Kardux Apr 12 '17 at 08:53

1 Answers1

2

If you have those sprites in your project already you can simply edit their import settings to Advanced and check the Read/Write Enable toggle.

Then you should be able to read your sprites content and merge them like this:

public Sprite CombineSpriteArray(Sprite[][] spritesArray)
{
    // Set those two or get them from one the the sprites you want to combine
    int spritesWidth = (int)spritesArray[0][0].rect.width;
    int spritesHeight = (int)spritesArray[0][0].rect.height;

    Texture2D combinedTexture = new Texture2D(spritesWidth * spritesArray.Length, spritesHeight * spritesArray[0].Length);

    for(int x = 0; x < spritesArray.Length; x++)
    {
        for(int y = 0; y < spritesArray[0].Length; y++)
        {
            combinedTexture.SetPixels(x * spritesArray.Length, y * spritesArray[0].Length, spritesWidth, spritesHeight, spritesArray[x][y].texture.GetPixels((int)spritesArray[x][y].textureRect.x, (int)spritesArray[x][y].textureRect.y, (int)spritesArray[x][y].textureRect.width, (int)spritesArray[x][y].textureRect.height));
            // For a working script, use:
            // combinedTexture.SetPixels32(x * spritesWidth, y * spritesHeight, spritesWidth, spritesHeight, spritesArray[x][y].texture.GetPixels32());
        }
    }
    combinedTexture.Apply();

    return Sprite.Create(combinedTexture, new Rect(0.0f, 0.0f, combinedTexture.width, combinedTexture.height), new Vector2(0.5f, 0.5f), 100.0f);
}

Warning: code untested

Be aware that such an operation is heavy and that doing it asynchronously in a coroutine may be a good idea to avoid a freeze.


EDIT:

Since you seem new to Stack Overflow, please keep in mind it's not a script providing service, people are here to help each others: this means code provided won't always be perfect but may simply guide you to the right path (this is also why I added the "Warning: code untested" after my code).

You claimed that the code was "completely broken" and "puts out errors all over the place". I wrote a small piece of script to test the script and the only error I got was that one (agreed it popped-up multiple times):

So after searching for it on Google (what you should have done by yourself), I noticed there were GetPixels32() / SetPixels32() methods that could also be used instead of GetPixels() / SetPixels() (here are the 3rd and 5th results that showed this methods). By simply changing this, the code now worked flawlessly.

Only problems I obtained was sprites were packed together at the bottom left of the texture: my bad on this I made a small mistake. Not hard to find where: just change
x * spritesArray.Length, y * spritesArray[0].Length, ...
to
x * spritesWidth, y * spritesHeight, ...
inside the SetPixels method.

So please find the whole test script I wrote and feel free to use it:

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

public class TestScript : MonoBehaviour
{
    public Image m_DisplayImage;
    public Sprite m_Sprite1, m_Sprite2;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            StartCoroutine(CombineSpritesCoroutine());
        }
    }

    private IEnumerator CombineSpritesCoroutine()
    {
        Sprite[][] spritesToCombine = new Sprite[4][];
        for (int i = 0; i < spritesToCombine.Length; i++)
        {
            spritesToCombine[i] = new Sprite[4];
        }

        for (int x = 0; x < spritesToCombine.Length; x++)
        {
            for (int y = 0; y < spritesToCombine[x].Length; y++)
            {
                spritesToCombine[x][y] = ((x + y) % 2 == 0 ? m_Sprite1 : m_Sprite2);
            }
        }

        Sprite finalSprite = null;
        yield return finalSprite = CombineSpriteArray(spritesToCombine);

        m_DisplayImage.sprite = finalSprite;
    }

    public Sprite CombineSpriteArray(Sprite[][] spritesArray)
    {
        // Set those two or get them from one the the sprites you want to combine
        int spritesWidth = (int)spritesArray[0][0].rect.width;
        int spritesHeight = (int)spritesArray[0][0].rect.height;

        Texture2D combinedTexture = new Texture2D(spritesWidth * spritesArray.Length, spritesHeight * spritesArray[0].Length);

        for (int x = 0; x < spritesArray.Length; x++)
        {
            for (int y = 0; y < spritesArray[0].Length; y++)
            {
                combinedTexture.SetPixels32(x * spritesWidth, y * spritesHeight, spritesWidth, spritesHeight, spritesArray[x][y].texture.GetPixels32());
            }
        }
        combinedTexture.Apply();

        return Sprite.Create(combinedTexture, new Rect(0.0f, 0.0f, combinedTexture.width, combinedTexture.height), new Vector2(0.5f, 0.5f), 100.0f);
    }
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Kardux
  • 2,117
  • 1
  • 18
  • 20