SpritePacker.py
The SpritePacker class takes a folder of sprites and generates the following:
- texture.png : single texture with all sprites in the folder packed into it
- texmap.py : python file containing a dictionary which maps the sprite names to texture co-ordinates
Example texmap.py file using various Sheep Snaggers sprites:
texmap = { 'kisschicklogo' : [0, 0, 500, 300], 'ming' : [501, 0, 202, 162], 'ship' : [704, 0, 32, 32], 'alien' : [737, 0, 32, 32], 'alien_shadow' : [770, 0, 32, 32], 'fighter' : [803, 0, 32, 32], 'sheep' : [836, 0, 32, 32], 'star' : [869, 0, 20, 20], 'star2' : [890, 0, 20, 20], 'bullet' : [911, 0, 4, 4], 'beerman_logo' : [0, 301, 477, 305], }
Full source code of SpritePacker.py:
#Beercave Gamews Beerware license v1.0 #This code is free to use for anything you want. #If you find it useful, I'd appreciate it if you buy me a beer :) #See http://www.beercave.co.uk/content/beerware for details #quick and dirty spritesheet packer #based on http://www.blackpawn.com/texts/lightmaps/default.html import os, pygame, glob from operator import itemgetter class SpritePacker(): def __init__(self, **kwargs): #defaults for input/output folders and texture size self.folder = kwargs.get("folder", "input") self.outfolder = kwargs.get("outfolder", "output") self.texturew = kwargs.get("texturew", 1024) self.textureh = kwargs.get("textureh", 1024) def Pack(self): patterns = ["*.gif", "*.png", "*.bmp"] #check for files in folder print os.path.abspath(self.folder) result = [] for pattern in patterns: pattern = os.path.join(self.folder, pattern) result.extend(glob.glob(pattern)) if len(result) == 0: print "No files in input folder!" return #build a new texture print "processing %d files:" % len(result) texture = pygame.Surface((self.texturew, self.textureh), pygame.SRCALPHA, 32) NodeTree = Node(texture, 0, 0, self.texturew, self.textureh) #sort our sprites by size sprites = [] for filepath in result: head, tail = os.path.split(filepath) filename = tail spritename, ext = os.path.splitext(tail) surface = pygame.image.load(filepath) x,y = surface.get_rect().size size = x*y #area should work as a proxy for size unless we get some badly out of proportion sprites sprites.append([filepath, spritename, size]) sprites.sort(key = itemgetter(2), reverse=True) print sprites for filepath, spritename, size in sprites: surface = pygame.image.load(filepath) print "Inserting %s - %s" %(spritename, surface) NodeTree.Insert(surface, spritename) #save the finished texture to outfolder outfile = os.path.join(self.outfolder, "texture.png") mapfile = os.path.join(self.outfolder, "texmap.py") pygame.image.save(texture, outfile) print "texture written to %s" % outfile #now dump the list of nodes map = NodeTree.Dump(True) + "}" with open(mapfile, 'w') as f: f.write(map) print "texture map written to %s" % mapfile class Node(): def __init__(self, texture, x, y, w, h): print "Creating node %d, %d, %d, %d" %(x,y,w,h) self.texture = texture self.bottom = None self.right = None self.rect = [x,y,w,h] self.imagerect = [0,0,0,0] self.image = None def Insert(self, surface, name): if self.image != None: print "node at %s contains %s. Adding to child node" % (self.rect, self.image) result = self.AddChild(surface, name) if not result: print "Could not add %s!" %name return result x,y,myw,myh = self.rect rect = surface.get_rect() print "image size : (%d,%d)" % rect.size w,h = rect.size #add some padding around sprites h += 1 w += 1 if w > myw or h > myh: print "Node too small!" return False print "adding to node at %s" % self.rect self.texture.blit(surface, (x,y)) self.image = name self.imagerect = [x,y,w-1,h-1] print self.imagerect #generate ChildNodes dw = myw - w dh = myh - h if dw > dh: self.right = Node(self.texture, x+w, y, dw, myh) self.bottom = Node(self.texture, x, y+h, w, dh) else: self.right = Node(self.texture, x+w, y, dw, h) self.bottom = Node(self.texture, x, y+h, myw, dh) return True def AddChild(self, surface, name): if not self.right.Insert(surface, name): return self.bottom.Insert(surface, name) return True #dump structure #{"filename" : [x,y,w,h], #} def Dump(self, first = False): #print "Dumping node" if self.image == None: return "" result = "'%s' : %s,\n" % (self.image, self.imagerect) if first: result = "texmap = {\n%s" %result result += self.right.Dump() result += self.bottom.Dump() return result packer = SpritePacker() packer.Pack()
This code is released under the Beerware license. It's completely free to use, but if you like it, why not buy me a beer? :)
*All donations are covered by the Beercave Games Beerware Pledge.
Other Stuff
Input.py
Input wrapper class for handling multiple controllers in pygame.
SpritePacker.py
Quick and dirty spritesheet generator
Beerware
The Beercave Games Beerware license. Like my games? Buy me a pint!
