Introduction
This brief code is meant to read and parse a spritesheet coordinates file and extract its corresponding Image
objects. I wrote it to be able to use spritesheets generated with TexturePacker and may be compatible with other tools.
Background
A spritesheet is an Image
which contains smaller images like a map, to be used especially in games.
What is a sprite sheet?
Using the Code
A small class called Spritesheet
with a static
factory method LoadSpriteSheet
to parse a coordinates (XML) file.
It holds a Dictionary
to map the spriteFrameName
to the actual Image
it represents.
class Spritesheet
{
public string Name { get; set; }
public Dictionary<string, Image> Sprites { get; set; }
public Spritesheet(string spriteSheetName)
{
this.Sprites = new Dictionary<string, Image>(50);
this.Name = spriteSheetName;
}
public static Spritesheet LoadSpriteSheet(string coordinatesFile)
{
XmlDocument doc = new XmlDocument();
doc.Load(coordinatesFile);
XmlNode metadata = doc.SelectSingleNode("/plist/dict/key[.='metadata']");
XmlNode realTextureFileName =
metadata.NextSibling.SelectSingleNode("key[.='realTextureFileName']");
string spritesheetName = realTextureFileName.NextSibling.InnerText;
Image spriteSheetImage = Image.FromFile(spritesheetName);
XmlNode frames = doc.SelectSingleNode("/plist/dict/key[.='frames']");
XmlNodeList list = frames.NextSibling.SelectNodes("key");
Spritesheet spritesheet = new Spritesheet(coordinatesFile);
foreach (XmlNode node in list)
{
XmlNode dict = node.NextSibling;
string strRectangle = dict.SelectSingleNode
("key[.='frame']").NextSibling.InnerText;
string strOffset = dict.SelectSingleNode
("key[.='offset']").NextSibling.InnerText;
string strSourceRect = dict.SelectSingleNode
("key[.='sourceColorRect']").NextSibling.InnerText;
string strSourceSize = dict.SelectSingleNode
("key[.='sourceSize']").NextSibling.InnerText;
Rectangle frame = parseRectangle(strRectangle);
Point offset = parsePoint(strOffset);
Rectangle sourceRectangle = parseRectangle(strSourceRect);
Point size = parsePoint(strSourceSize);
string spriteFrameName = node.InnerText;
Image sprite = new Bitmap(size.X, size.Y);
Graphics drawer = Graphics.FromImage(sprite);
drawer.DrawImage(spriteSheetImage, sourceRectangle, frame, GraphicsUnit.Pixel);
drawer.Save();
drawer.Dispose();
spritesheet.Sprites.Add(spriteFrameName, sprite);
}
return spritesheet;
}
private static Rectangle parseRectangle(string rectangle)
{
Regex expression = new Regex(@"\{\{(\d+),(\d+)\},\{(\d+),(\d+)\}\}");
Match match = expression.Match(rectangle);
if (match.Success)
{
int x = int.Parse(match.Groups[1].Value);
int y = int.Parse(match.Groups[2].Value);
int w = int.Parse(match.Groups[3].Value);
int h = int.Parse(match.Groups[4].Value);
return new Rectangle(x, y, w, h);
}
return Rectangle.Empty;
}
private static Point parsePoint(string point)
{
Regex expression = new Regex(@"\{(\d+),(\d+)\}");
Match match = expression.Match(point);
if (match.Success)
{
int x = int.Parse(match.Groups[1].Value);
int y = int.Parse(match.Groups[2].Value);
return new Point(x, y);
}
return Point.Empty;
}
}
Here is a usage example:
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "property list (*.plist)|*.plist|XML files (*.xml)|
*.xml|Supported Files|*.xml;*.plist";
dialog.FilterIndex = 3;
if (dialog.ShowDialog(this) == DialogResult.OK)
{
Spritesheet spritesheet = Spritesheet.LoadSpriteSheet(dialog.FileName);
}
History
- Initial post, basic usage guidelines
Note: Doesn't support sprite rotation, yet!