Edit: Update here!
Starling Framework’s spritesheets are described by the TextureAtlas XML files.
Recently I have donated to the KenneyLand crowdfund and Kenney (www.kenney.nl) has sent me an asset pack containing a lot of spritesheets and other great assets. The spritesheets also came with XML files next to them. I currently use Unity3D as my main development tool and wanted to use these spritesheets for some of my game ideas.
I will now explain how I wrote a script to let me easily slice 2D sprites.
We will use the UI pack: Space extension by Kenney as an example. The spritesheet looks like this:
As you can see, it is not evenly divided, so the grid slicer will not work. Also, the pixels are mostly touching, so the automatic slicing will not work either. To our luck, it comes with an XML file:
1 2 3 4 5 6 7 8 9 10 11 12
<TextureAtlas imagePath="sheet.png"> <SubTexture name="barHorizontal_blue_left.png" x="400" y="78" width="6" height="26"/> <SubTexture name="barHorizontal_blue_mid.png" x="388" y="420" width="16" height="26"/> <SubTexture name="barHorizontal_blue_right.png" x="400" y="0" width="6" height="26"/> <SubTexture name="barHorizontal_green_left.png" x="400" y="104" width="6" height="26"/> <SubTexture name="barHorizontal_green_mid.png" x="386" y="366" width="16" height="26"/> <SubTexture name="barHorizontal_green_right.png" x="400" y="26" width="6" height="26"/> <!-- ... --> <SubTexture name="squareWhite.png" x="384" y="476" width="19" height="26"/> <SubTexture name="squareYellow.png" x="380" y="236" width="19" height="26"/> <SubTexture name="square_shadow.png" x="386" y="288" width="19" height="26"/> </TextureAtlas>
We could use this XML file to manually create the rectangles… just kidding.
Here is what the script will do:
- Add a context menu item to TextureImporter inspector
- This item will open a window to configure slicing
- Then the window will close itself after slicing is completed.
If you do not care about the implementation details, you can skip to the script.
In your project explorer, create an ‘Editor’ folder for the script, if it does not exist already. This folder needs to be named ‘Editor’ because that’s how Unity3D knows that these scripts will be used only for editor-specific functions. More information can be found here.
In there, create a C# script. I named mine ‘TextureAtlasSlicer’. Here is what it looks like now:
Adding a custom context menu item
We need to use the MenuItem attribute. This menuitem’s name should start with
"CONTEXT/TextureImporter/", because that is how Unity3D understands that it is a context menu, and it is for the TextureImporter inspector.
ValidateSliceUsingXML function tells Unity3D to enable the menu item only for ‘sprite’ or ‘advanced’ texture types.
The actual function,
SliceUsingXML is used to open a window and save the reference to the
TextureImporter, as it will be used by the window to do the slicing. The TextureImporter is extracted out of the MenuCommand.
Configuring the slicing
xmlAsset field is used to choose which file will be used for slicing.
We can also customize the
customOffset, which will set the default pivot for the slices.
And finally, the
Slice button, that’s why we’re here!
We use the XmlDocument#LoadXml method in order to create an XmlDocument object in c#.
As specified above, the XML document has a
TextureAtlas node as root, and
SubTexture child nodes. Each SubTexture has five attributes: the name and the rectangle definitions (x, y, width, height).
In Unity3D, for textures, the y coordinate is 0 at the bottom. This is not the case for
SubTexture rectangles, so we need to fix that. In order to get the texture height, we need to load the image file as a texture (line 10 in gist). Then, the y value for the rectangle is
(texture height - (SubTexture.height + SubTexture.y)) (line 22 in gist).
In order to get the pivot, we can use the GetPivotValue function (borrowed from the Unity3D Editor’s internal
We can use this information to create a
SpriteMetaData, which basically describe the slices for a sprite (line 24).
If there were no errors, we can slice the sprite: set the
Multiple, and then assign the
spritesheet array. Afterwards, we just need to tell the
AssetDatabase to reimport the texture, and we’re done!
Here’s the whole code for the script: