Sprite Sheet Packer importer for Unity3D

Dec 20, 2013 at 2:12 AM
Unity 4.3 Update brought new 2D tools for unity, and based on this thread I made a similar importer for Sprite Sheet packer.

It uses slightly edited version of the text parser provided in the "Using Sprite Sheet Packer with XNA GS" found in the documentation, and turns the atlas data in to new Unity Sprites.

Usage is simple, just save the script as SpriteSheetPackerImport.cs and place it in to projects editor folder. Then save your SpriteSheet(.png) and map(.txt) somewhere to the Unity project folder. Make sure they are in the same folder and have the same name. Then just right click the map/atlas file (.txt) and choose Sprite Sheet Packer > Process to sprites. This needs to be done, every time you update the spritesheet.

Thought to share this in case there are people who prefer to use Sprite Sheet Packer in their projects. If anyone wishes to edit/improve/customize the script they are free to do so (Standard MIT or WTFPL)
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;

public static class SpriteSheetPackerImport
{
    [MenuItem("Assets/Sprite Sheet Packer/Process to Sprites")]
    static void ProcessToSprite()
    {
        TextAsset txt = (TextAsset)Selection.activeObject;

        string rootPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(txt));
        string path = rootPath + "/" + txt.name + ".PNG";

        //To get the height of the image
        Texture2D tmpTexture = new Texture2D(1, 1);
        byte[] tmpBytes = File.ReadAllBytes(path);
        tmpTexture.LoadImage(tmpBytes);

        //Parses Sprite Sheet Packer files 
        List<SpriteMetaData> sprites = Parse(txt, tmpTexture.height);
        TextureImporter texImp = AssetImporter.GetAtPath(path) as TextureImporter;

        texImp.spritesheet = sprites.ToArray();
        texImp.textureType = TextureImporterType.Sprite;
        texImp.spriteImportMode = SpriteImportMode.Multiple;

        AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
    }
    static List<SpriteMetaData> Parse(TextAsset text, int height)
    {
        using (StringReader reader = new StringReader(text.text))
        {
            List<SpriteMetaData> Sprites = new List<SpriteMetaData>();

            // while we're not done reading...
            while (true)
            {
                // get a line
                string line = reader.ReadLine();

                if (line != null)
                {
                    // split at the equals sign
                    string[] sides = line.Split('=');

                    // trim the right side and split based on spaces
                    string[] rectParts = sides[1].Trim().Split(' ');

                    // create a rectangle from those parts
                    Rect r = new Rect(
                       int.Parse(rectParts[0]),
                       int.Parse(rectParts[1]),
                       int.Parse(rectParts[2]),
                       int.Parse(rectParts[3]));

                    // add the name and rectangle to the dictionary
                    SpriteMetaData smd = new SpriteMetaData();
                    smd.name = sides[0].Trim();
                    smd.rect = new Rect(r.x, height - r.y - r.height, r.width, r.height); //0,0 is bottom left
                    smd.pivot = Vector2.zero;
                    smd.alignment = 1;
                    Sprites.Add(smd);
                }
                else
                {
                    break;
                }
            }
            return Sprites;
        }
    }
}
Dec 20, 2013 at 12:40 PM
Edited Dec 22, 2013 at 1:24 PM
Note that if you are often updating your spritesheet, it's good to know that Unity doesn't reference the sprites by their name but their index which is based on their order of appearance in the map. But since things are handled alphabetically you can add index to your filenames e.g "01_GroundTexture.png", "02_GrassTexture.png"etc. and they will be ordered accordingly and thus not mess up any prefabs you have made.

Above code puts the pivot point to top-left corner, but you can easily change it where you want it to be by changing the
smd.alignment = 1; to something else in the parse method. e.g smd.alignment = (int)SpriteAlignment.Center;