What is the best current spritesheet solution for Monogame?

Hello!

What is the current (02/2018) best solution for dealing with spritesheets in monogame? I am looking for a workflow similar to TexturePacker but free. Does such a thing exist?

Years ago, around 2012, I used XNA and was using the SpriteSheetPipeline. Using that tool I could just feed in my sprites then at runtime access them all on the spritesheet. I don’t need a GUI for the sprites, just a tool that will combine multiple images on to a sprite sheet and give me the addresses easily and programatically.

I looked at TexturePacker last night and the monogame option costs $40. However, it does output to XML output for free, the output of which looks like this:

<TextureAtlas imagePath="IFPsprites.png" width="512" height="1022">
    <sprite n="asteroid.png" x="144" y="72" w="64" h="48" pX="0.5" pY="0.5"/>
...
</TextureAtlas>

Does this load into XNA? Is there a tutorial anywhere on using this?

Any other tips/tricks/advice on the current way of doing things?

Thanks!

I’ve never used TexturePacker before, but from the looks of it, I think you should be able to parse out the XML contents. Then it would be a matter of storing that data in your game and using it for what you need. If it doesn’t pack your sprites into a new texture in the free version, you’ll have to do so yourself. You should be able to use its XML data to do so in a tool or method you create.

You can also simply pay the $40 and use the tool if you think it’ll save you time. I’m surprised the free trial only allows XML output.

I don’t know if there’s a “best” solution, as MonoGame gives you the flexibility to choose the approach you want. Personally, I manually specify all my frames on each sheet in an AnimationFrame struct. It doesn’t have the benefits of packing sprites from different sheets into a single atlas, but I haven’t needed it yet.

Thanks for your information!

Do you notice a performance hit for using multiple spritesheets?

When I was developing for Xbox 360 I noticed a big improvement when I went from individual sprites to spritesheets, but I’m not sure if it is as big a deal now.

If you’re switching between a lot of sheets often, it can be a problem depending on your game and platform. If your game is running well without atlases, I wouldn’t consider it a problem. You can also use SpriteSortMode.Texture in SpriteBatch to sort draw calls by texture so it changes textures as few times as possible.

Since I do a lot of development in node.js I use it to generate sheets. Here’s how I did building texture atlas in my MonoGameJam entry https://github.com/RetrocadeNet/MachineAtTheHeartOfTheWorld/blob/master/AtlasGenerator/PackTextures.js

If you never used Node.js it might be a bit hard to follow and if you don’t have Node and NPM installed it might be an overkill but there are free ways to make texture atlases.

I ended up using Nick Gravelyn’s SpriteSheetPacker. I had to make a few configuration changes to the project to get it working, which I updated here: https://github.com/walteryoung/SpriteSheetPacker

I have had trouble when accessing assets with file extensions in the content pipeline, so I saved out the PNG and the XML from the SpriteSheetPacker file as extension-less files named ‘sprite’ and ‘spriteIndex’, respectively.

As an aside, I ending up writing a batch script to make copies of all of my assets with no file extension (I have a lot of XML files for level data).

Here is my SpriteSheet class, which loads the spriteSheet Texture2D and has a Dictionary for looking up sprites by name.

internal class SpriteSheet
{
    internal Texture2D Texture;
    Dictionary<String, Rectangle> index;

    public void LoadContent(ContentManager content)
    {
        index = content.Load<Dictionary<String, Rectangle>>("spriteIndex");
        Texture = content.Load<Texture2D>("sprites");
    }

    internal Rectangle? SourceRectangle(string spriteName)
    {
        Rectangle r;
        bool hasValue = index.TryGetValue(spriteName, out r);

        if (hasValue)
        {
            return r;
        }
        else
        {
            throw new Exception("value doesn't exist");
        }
    }
}

This solution ended up being pretty much exactly what I wanted, and super easy to implement.

2 Likes

There’s a complete tutorial about MonoGame + TexturePacker here: https://www.codeandweb.com/texturepacker/tutorials/animation-made-easy-in-monogame-with-texturepacker

The main advantage form TexturePacker over other sprite sheet packers is that it’s optimized for sprite quality. Packing is only 30% of what it does for you. But it also makes sure that you:

  • don’t get thin lines where the background looks through when aligning sprites
  • bleeding artifacts from neighbor sprites
  • outlines halos around sprites
  • jagged sprite borders when rotating sprites

Another big advantage is that TexturePacker also creates definitions for each sprite. This allows you to reference the sprites by const string variables. Why that? Because it gives you errors at compile-time when a sprites is missing - or you have a typo somewhere - instead of crashing at runtime.

Animations are also automatically grouped and create own definitions for easier management. (Requires you to name the sprites with a number at the end - e.g. run-0001.png, run-0002.png,…)

You can also optimize your sprite sheets for size - e.g. using PNG-8 or 16 bit image formats with dithering…

1 Like