How does everyone else organize their sprite sheets?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

How does everyone else organize their sprite sheets?

Post by Inny »

My artist and I ran into this problem, now that we're trying some more complex things. I've found it way too tedious to generate all of the quads for a texture atlas from his sprite sheet image, and want to offload that responsibility to him. That of course leaves a tedious task for him to deal with. Before we start moving heaven and earth to solve this, I'd like to know what others do to deal with this. If we were professionals and used windows, we'd probably do what most XNA devs do and use a digital asset manager, which would keep track of all this for us and stamp out the required texture files and metadata files. Since we're rank amateurs and linux users, about the only thing I can think of is to track down a good gimp plugin.
User avatar
xXxMoNkEyMaNxXx
Party member
Posts: 206
Joined: Thu Jan 10, 2013 6:16 am
Location: Canada

Re: How does everyone else organize their sprite sheets?

Post by xXxMoNkEyMaNxXx »

What do you mean by 'sprite sheets'?
scutheotaku
Party member
Posts: 235
Joined: Sat Dec 15, 2012 6:54 am

Re: How does everyone else organize their sprite sheets?

Post by scutheotaku »

Inny wrote:My artist and I ran into this problem, now that we're trying some more complex things. I've found it way too tedious to generate all of the quads for a texture atlas from his sprite sheet image, and want to offload that responsibility to him. That of course leaves a tedious task for him to deal with. Before we start moving heaven and earth to solve this, I'd like to know what others do to deal with this. If we were professionals and used windows, we'd probably do what most XNA devs do and use a digital asset manager, which would keep track of all this for us and stamp out the required texture files and metadata files. Since we're rank amateurs and linux users, about the only thing I can think of is to track down a good gimp plugin.
I don't think I understand what you're asking...are you wanting an easy way to generate quads? Or are you wanting some sort of project management software?

If it's the former: why not just have it generate all of the quads on start-up? This should be pretty easy if each sprite sheet has a fixed grid size. If each sprite sheet requires quads of various sizes, this is still doable as long as you can have grid lines which have a unique color.

Or maybe something like TexturePacker could streamline the process for you? You can apparently write custom export scripts for it ( http://www.codeandweb.com/texturepacker/features ) which allows you to export for any framework or engine (a few Lua frameworks like Moai, Corona, and Gideros are supported out of the box, among several other non-Lua frameworks and engines). I haven't worked with this myself though, so I can't guarantee it will be helpful (though it's a very popular piece of software).

Still, I think I'm missing what exactly you're asking :/
xXxMoNkEyMaNxXx wrote:What do you mean by 'sprite sheets'?
http://www.codeandweb.com/what-is-a-sprite-sheet
http://upload.wikimedia.org/wikipedia/c ... xample.gif
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: How does everyone else organize their sprite sheets?

Post by Inny »

Sprite sheets are where you use one very large image and fit all the frames of your animations on it, instead of separating them out into individual files.

TexturePacker looks interesting, I'll have my guy look it over. What I was asking was what others were doing in general. If everything is 16x16 or 32x32, just arrange your png and generate all the quads that way, and that works fine. But we don't have that, our sprites are all sorts of crazy sizes. Doing a fixed grid would require a 64x64 box to fit both spear carrying villagers, and bees. Also of equal importance is setting the origin point on each sprite. If someone swings a weapon, the dimensions of the sprite can change and you need an origin point to anchor them to, as opposed to being forced to increase your sprite size to something larger.

The tedious way is this, by the way:

Code: Select all

  spriteBounds = {
    image = "gfx/sprite-antares.png",
    quads = {
      south_stand  = {   0,  0, 16, 24, 7, 21 },
      south_walk_1 = {  16,  0, 16, 24, 23, 21 },
      south_walk_2 = {  32,  0, 16, 24, 39, 21 },
      north_stand  = {  48,  0, 16, 24, 56, 21 },
      north_walk_1 = {  64,  0, 16, 24, 72, 21 },
      north_walk_2 = {  80,  0, 16, 24, 88, 21 },
      east_stand   = {  96,  0, 16, 24, 103, 21 },
      east_walk_1  = { 112,  0, 16, 24, 119, 21 },
      west_stand   = { 128,  0, 16, 24, 135, 21 },
      west_walk_1  = { 144,  0, 16, 24, 151, 21 },
      south_attack_1 = {  0, 24, 24, 24, 15, 44 },
      south_attack_2 = { 24, 24, 16, 32, 31, 44 },
      south_attack_3 = { 40, 24, 24, 24, 47, 44 },
      north_attack_1 = { 64, 24, 24, 24, 72, 44 },
      north_attack_2 = { 88, 24, 16, 32, 96, 51 },
      north_attack_3 = { 104, 24, 24, 24, 120, 44 },
      west_attack_1 = { 160, 0, 16, 24, 165, 21 },
      west_attack_2 = { 176, 0, 24, 24, 191, 21 },
      west_attack_3 = { 200, 0, 16, 24, 209, 21 },
      east_attack_1 = { 128, 24, 16, 24, 139, 45 },
      east_attack_2 = { 144, 24, 24, 24, 151, 45 },
      east_attack_3 = { 168, 24, 16, 24, 174, 45 },
    }
  }
If there's a better way, I'd love to know.
User avatar
Qcode
Party member
Posts: 170
Joined: Tue Jan 10, 2012 1:35 am

Re: How does everyone else organize their sprite sheets?

Post by Qcode »

Here's a bit of code from Mari0 that loads textures.

Code: Select all

local imgwidth, imgheight = smbtilesimg:getWidth(), smbtilesimg:getHeight()
local width = math.floor(imgwidth/17)
local height = math.floor(imgheight/17)
local imgdata = love.image.newImageData("graphics/" .. graphicspack .. "/smbtiles.png")
	
for y = 1, height do
	for x = 1, width do
		table.insert(tilequads, quad:new(smbtilesimg, imgdata, x, y, imgwidth, imgheight))
		local r, g, b = getaveragecolor(imgdata, x, y)
		table.insert(rgblist, {r, g, b})
	end
end
smbtilecount = width*height
Then in quad:new

Code: Select all

function quad:init(img, imgdata, x, y, width, height)
	--get if empty?

	self.image = img
	self.quad = love.graphics.newQuad((x-1)*17, (y-1)*17, 16, 16, width, height)
end
Maybe you could do a method like this, if all of your quads are equal size.
scutheotaku
Party member
Posts: 235
Joined: Sat Dec 15, 2012 6:54 am

Re: How does everyone else organize their sprite sheets?

Post by scutheotaku »

Inny wrote:Sprite sheets are where you use one very large image and fit all the frames of your animations on it, instead of separating them out into individual files.

TexturePacker looks interesting, I'll have my guy look it over. What I was asking was what others were doing in general. If everything is 16x16 or 32x32, just arrange your png and generate all the quads that way, and that works fine. But we don't have that, our sprites are all sorts of crazy sizes. Doing a fixed grid would require a 64x64 box to fit both spear carrying villagers, and bees. Also of equal importance is setting the origin point on each sprite. If someone swings a weapon, the dimensions of the sprite can change and you need an origin point to anchor them to, as opposed to being forced to increase your sprite size to something larger.

The tedious way is this, by the way:

Code: Select all

  spriteBounds = {
    image = "gfx/sprite-antares.png",
    quads = {
      south_stand  = {   0,  0, 16, 24, 7, 21 },
      south_walk_1 = {  16,  0, 16, 24, 23, 21 },
      south_walk_2 = {  32,  0, 16, 24, 39, 21 },
      north_stand  = {  48,  0, 16, 24, 56, 21 },
      north_walk_1 = {  64,  0, 16, 24, 72, 21 },
      north_walk_2 = {  80,  0, 16, 24, 88, 21 },
      east_stand   = {  96,  0, 16, 24, 103, 21 },
      east_walk_1  = { 112,  0, 16, 24, 119, 21 },
      west_stand   = { 128,  0, 16, 24, 135, 21 },
      west_walk_1  = { 144,  0, 16, 24, 151, 21 },
      south_attack_1 = {  0, 24, 24, 24, 15, 44 },
      south_attack_2 = { 24, 24, 16, 32, 31, 44 },
      south_attack_3 = { 40, 24, 24, 24, 47, 44 },
      north_attack_1 = { 64, 24, 24, 24, 72, 44 },
      north_attack_2 = { 88, 24, 16, 32, 96, 51 },
      north_attack_3 = { 104, 24, 24, 24, 120, 44 },
      west_attack_1 = { 160, 0, 16, 24, 165, 21 },
      west_attack_2 = { 176, 0, 24, 24, 191, 21 },
      west_attack_3 = { 200, 0, 16, 24, 209, 21 },
      east_attack_1 = { 128, 24, 16, 24, 139, 45 },
      east_attack_2 = { 144, 24, 24, 24, 151, 45 },
      east_attack_3 = { 168, 24, 16, 24, 174, 45 },
    }
  }
If there's a better way, I'd love to know.
Ah, ok, gotcha.

Well, if you didn't care what the quads were named, you could simply generate them on start. For generating them without a fixed grid size, I think you could do it where there is a visible grid on the sprite sheet, a grid that was a color that was not used anywhere else (like how everyone used to do transparency). Then, for each quad, you could do a loop that checks each pixel across starting at "startX" and ending at the first pixel it finds with a color value equal to the grid's color - then you have the width of that quad. You would then do the same for the height. Then you add the width to startX and start on the next quad. If the height of each quad changes dramatically, it may be hard to figure out how to move to the next row...perhaps you could store each width and height found in the previous row in a table, and then reference them to figure out the startY for each quad on the next row (e.g. if [0,0]'s has an x value of 0, a y of 0, a width of 32, and a height of 48, then [0, 1] which has an x value of 0 and a width of 24 will have a y value of 49...for columns that have a width going across multiple columns above it, you'd just take the height of the tallest column above it)? You'd only be doing this on load, so it's not like it'd slow down your game.

Though this all seems overly complicated...and, of course, unless you were able to figure out some clever way of doing it, you'd have trouble with the "names" of the quads...hmm...

Well, maybe TexturePacker would be the way to go? Again, I don't know a ton about it, but it seems like you should be able to work something out with its custom export script option.
User avatar
xXxMoNkEyMaNxXx
Party member
Posts: 206
Joined: Thu Jan 10, 2013 6:16 am
Location: Canada

Re: How does everyone else organize their sprite sheets?

Post by xXxMoNkEyMaNxXx »

Couldn't you have them all as separate files, then load each one up? It would be just as tedious...
You could also have a SpriteHandler.Lua that stored two files, spritesheet.png and spritemap.
The sprite handler would write the Offset and Size of each sprite to spritemap as it's name followed by two coordinate pairs.
e.g.

Code: Select all

module(...)
function store(self,name,image)
	--Have some packing algorithm to return a position that creates the smallest image size increase,
	--and have a repackaging function to be called when there is too much empty space in the image.
	local offset=spritemap:bestpos(imagesize)
	spritesheet:draw(image,offset)
	spritemap:write(name.."$"..offset_x..","..offset_y..";"..size_x..","..size_y.."\n")
	if spritemap:getpercentblank()>0.3 then
		spritemap:rearrange()
	end
end
function fetch(self,name)
	local offset_x,offset_y,size_x,size_y=spritemap:match(name.."%.?[^$%d]*$(%d+),(%d+);(%d+),(%d+)")
	return spritesheet:liftsnippet(offset_x,offset_y,size_x,size_y)
end
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: How does everyone else organize their sprite sheets?

Post by micha »

Inny wrote: The tedious way is this, by the way:

Code: Select all

  spriteBounds = {
    image = "gfx/sprite-antares.png",
    quads = {
      south_stand  = {   0,  0, 16, 24, 7, 21 },
      south_walk_1 = {  16,  0, 16, 24, 23, 21 },
      south_walk_2 = {  32,  0, 16, 24, 39, 21 },
      north_stand  = {  48,  0, 16, 24, 56, 21 },
      north_walk_1 = {  64,  0, 16, 24, 72, 21 },
      north_walk_2 = {  80,  0, 16, 24, 88, 21 },
      east_stand   = {  96,  0, 16, 24, 103, 21 },
      east_walk_1  = { 112,  0, 16, 24, 119, 21 },
      west_stand   = { 128,  0, 16, 24, 135, 21 },
      west_walk_1  = { 144,  0, 16, 24, 151, 21 },
      south_attack_1 = {  0, 24, 24, 24, 15, 44 },
      south_attack_2 = { 24, 24, 16, 32, 31, 44 },
      south_attack_3 = { 40, 24, 24, 24, 47, 44 },
      north_attack_1 = { 64, 24, 24, 24, 72, 44 },
      north_attack_2 = { 88, 24, 16, 32, 96, 51 },
      north_attack_3 = { 104, 24, 24, 24, 120, 44 },
      west_attack_1 = { 160, 0, 16, 24, 165, 21 },
      west_attack_2 = { 176, 0, 24, 24, 191, 21 },
      west_attack_3 = { 200, 0, 16, 24, 209, 21 },
      east_attack_1 = { 128, 24, 16, 24, 139, 45 },
      east_attack_2 = { 144, 24, 24, 24, 151, 45 },
      east_attack_3 = { 168, 24, 16, 24, 174, 45 },
    }
  }
If there's a better way, I'd love to know.
First of all, all these numbers from the code above need to be contained in the code somewhere. If you really have an unstructured sprite sheet, you have to tell your program where each single sprite is. The the only way to make it less tedious, is to either shorten the syntax of this code, or auto-generate it.
Two ideas:
1) Every time your artist add a new image, let him put the coordinates of the corners and the reference point into a (excel or whaterever-) table. In the end, export everything into a text file that contains all the names and the coordinates and write a small function that is able to read the image and the table together to produces all the quads.
2) Write a love-program that does the job: In this program you open the sprite sheet and let the user klick all the coordinates and from these information you generate a code like the above one.

Edit: Just saw, xXxMoNkEyMaNxXx basically suggested the same already.

Either way you can additionally shorten the amount of data you need. Tell your artist, when he does animations, he has to put all frames of one animation in one row in the sprite sheet. That way you only need to specify the first image of an animation and the number of frames (instead of specifying the position of each single frame).
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: How does everyone else organize their sprite sheets?

Post by kikito »

[quote="Inny"]

Code: Select all

  spriteBounds = {
    image = "gfx/sprite-antares.png",
    quads = {
      south_stand  = {   0,  0, 16, 24, 7, 21 },
      south_walk_1 = {  16,  0, 16, 24, 23, 21 },
     ...
      east_attack_3 = { 168, 24, 16, 24, 174, 45 },
    }
  }
Well, that's incredibly tedious. If you leverage on a couple facts, you can make it a lot less painful.
  • First, the quads are always the same size, so it would make sense to have them specified simply as members of a grid - write two numbers, and then calculate the 4 you need using those.
  • Second, the "anchor point" seems to stay mostly constant. You could use that too.

Code: Select all

sprite = {
  image = "gfx/sprite-antares.png",
  frame = { w = 16, w = 24 },
  anchor = { x = 7, y = 21 },
  frames = { -- notice that I'm using grid coordinates here; no need to manually calculate each vertex
    south_stand =   { 0,0 },
    south_walk_1 = { 1,0 },
    south_walk_2 = { 2,0 },
    ...
    east_attack_3 = { 11, 0 },

  }
}
If you don't need the particular "intermediate" animation frames (south_walk_1, south_walk_2), you can probably abstract those away. If you used anim8 for your animations you should be able to do this (if you don't want to use anim8, you can just copy its grid-parsing code and adapt it to your needs):

Code: Select all

sprite = {
  image = "gfx/sprite-antares.png",
  frame = { w = 16, w = 24 },
  anchor = { x = 7, y = 21 },
  animations = {
    south_stand = { 0,0 },
    south_walk = { '1-2,0' },
    ...
    east_attack = { '9-11,0' },
  }
}
The condition is that all your frames must be of the same size. But that is generally a good idea anyway.

If you need to move the anchor point in some occasions, but it stays in the same place most of the time, then a good compromise is having two "default anchor points" and then being able to specify different ones per animation (changing the anchor point inside an animation is just asking for trouble and not worth it).

Code: Select all

sprite = {
  image = "gfx/sprite-antares.png",
  frame = { w = 16, w = 24 },
  anchor = { x = 7, y = 21 },
  animations = {
    south_stand = { f = { 0,0 } },
    south_walk = { f = { '1-2,0' } },
    ...
    east_attack = { f = { '9-11,0' }, anchor = {5,10} },
  }
}
When I write def I mean function.
User avatar
Ref
Party member
Posts: 702
Joined: Wed May 02, 2012 11:05 pm

Re: How does everyone else organize their sprite sheets?

Post by Ref »

kikito wrote:
Inny wrote:

Code: Select all

sprite = {
  image = "gfx/sprite-antares.png",
  frame = { w = 16, w = 24 },
  anchor = { x = 7, y = 21 },
  animations = {
    south_stand = { f = { 0,0 } },
    south_walk = { f = { '1-2,0' } },
    ...
    east_attack = { f = { '9-11,0' }, anchor = {5,10} },
  }
}
print(sprite.frame.w) returns 24.
Was frame susposed to be frame = { w 16, h = 24 } or am I missing something obvious?
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot], Google [Bot] and 85 guests