Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
KenneySpriteSheetBuilder.cs
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using UnityEditor;
using UnityEngine;
class KenneySpriteSheetBuilder : AssetPostprocessor
{
#region Customization
//
// If you want to only process kenney spritesheets in a specific folder you can do it by setting
// this string to the name of the folder relative to your assets directory.
//
const string m_RequiredRootFolder = null;
#endregion
#region Internals
// This is a brilliant method by unity form member numberkruncher
// Here's the post that provided the guts of this method, not taken quite verbatum:
// http://forum.unity3d.com/threads/getting-original-size-of-texture-asset-in-pixels.165295/
public static bool GetImageSize(TextureImporter importer, out int width, out int height)
{
if (importer != null)
{
object[] args = new object[2] { 0, 0 };
MethodInfo mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Invoke(importer, args);
width = (int)args[0];
height = (int)args[1];
return true;
}
height = width = 0;
return false;
}
private static void HandleSpritesheet(TextureImporter importer, XmlDocument document, ref int totalSprites)
{
// don't over-write sprite sheets that have already been setup (either by hand, or previously).
if (importer.spriteImportMode != SpriteImportMode.Multiple)
{
Vector2 pivot = new Vector2(0.5f, 0.5f);
importer.spriteImportMode = SpriteImportMode.Multiple;
List<SpriteMetaData> sprites = new List<SpriteMetaData>();
int textureWidth = 0,
textureHeight = 0;
if (!GetImageSize(importer, out textureWidth, out textureHeight))
{
Debug.LogWarning("Couldn't determine the texture dimensions for this asset. Asset path is\"" + importer.assetPath + "\"");
}
foreach (XmlNode xmlNode in document.DocumentElement.ChildNodes)
{
string childName = xmlNode.Name;
if (childName == "SubTexture")
{
string
name = null,
x = null,
y = null,
width = null,
height = null;
int _x = 0,
_y = 0,
_width = 0,
_height = 0;
foreach (XmlAttribute attr in xmlNode.Attributes)
{
switch (attr.Name)
{
case "name":
name = attr.Value;
break;
case "x":
x = attr.Value;
break;
case "y":
y = attr.Value;
break;
case "width":
width = attr.Value;
break;
case "height":
height = attr.Value;
break;
// It seems like we can ignore these attributes coming from the shoebox exporter.
// If they need to be considered in the future we can add support here.
case "frameX":
case "frameY":
case "frameWidth":
case "frameHeight":
break;
default:
Debug.LogWarning("[Kenney] While loading a spritesheet, we found a subtexture attr that was unexpected... It was \"" + attr.Name + "\"");
break;
}
}
if (name == null)
{
Debug.LogWarning("[Kenney] While loading a spritesheet, we found a subtexture without a name.");
continue;
}
if (x == null || !int.TryParse(x, out _x))
{
Debug.LogWarning("[Kenney] While loading a spritesheet, we found a subtexture without an x position. The name was \"" + name + "\"");
continue;
}
if (y == null || !int.TryParse(y, out _y))
{
Debug.LogWarning("[Kenney] While loading a spritesheet, we found a subtexture without a y position. The name was \"" + name + "\"");
continue;
}
if (width == null || !int.TryParse(width, out _width))
{
Debug.LogWarning("[Kenney] While loading a spritesheet, we found a subtexture without a width. The name was \"" + name + "\"");
continue;
}
if (height == null || !int.TryParse(height, out _height))
{
Debug.LogWarning("[Kenney] While loading a spritesheet, we found a subtexture without a height. The name was \"" + name + "\"");
continue;
}
SpriteMetaData meta = new SpriteMetaData();
meta.name = name;
meta.pivot = pivot;
// note the required modification to the y position to work with unity sprite co-ords
meta.rect = new Rect(_x, textureHeight - _y - _height, _width, _height);
sprites.Add(meta);
}
}
if (sprites.Count > 0)
{
totalSprites += sprites.Count;
importer.spritesheet = sprites.ToArray();
// refresh the sprite sheet so it can apply our changes.
AssetDatabase.ImportAsset(importer.assetPath);
}
}
}
private static void HandleAsset(string asset, ref int totalSprites)
{
if (m_RequiredRootFolder != null && !asset.Contains("Assets/" + m_RequiredRootFolder))
{
return;
}
AssetImporter importer = AssetImporter.GetAtPath(asset);
if (importer != null)
{
if(!(importer is TextureImporter))
{
return;
}
if (((TextureImporter)importer).textureType == TextureImporterType.Sprite)
{
string imagePath = asset;
string xmlPath = imagePath.Substring(0, imagePath.LastIndexOf('.')) + ".xml";
if (File.Exists(xmlPath))
{
//document
XmlDocument document = new XmlDocument();
document.Load(xmlPath);
//TODO: validate document.
HandleSpritesheet((TextureImporter)importer, document, ref totalSprites);
}
}
}
}
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPath)
{
int totalSprites = 0;
foreach (var asset in importedAssets)
{
HandleAsset(asset, ref totalSprites);
}
foreach (var asset in movedAssets)
{
HandleAsset(asset, ref totalSprites);
}
foreach (var asset in movedFromAssetPath)
{
HandleAsset(asset, ref totalSprites);
}
if (totalSprites > 0)
{
Debug.Log("[Kenney] Successfully added " + totalSprites + " sprites!");
}
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.