I'm trying to animate my game using a sprite sheet. How would I go about cutting out each sprite from the sprite sheet and using the sprite in xcode? I'm currently using obj -c. I read somewhere that i need to use a frame work, cocoa2d, in order to do this?
-
cocos-2d is an open source gam engine a bit like sprite kit. to cut out each sprite make an SKTexture from the sprite sheet then cut out each frame using [rect:InTexture:](https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKTexture_Ref/index.html#//apple_ref/occ/clm/SKTexture/textureWithRect:inTexture:) – Jan 18 '15 at 09:56
-
Take a look at Texture Packer. It's a free app which creates texture atlases, handles animations and does pretty much everything else you need. https://www.codeandweb.com/texturepacker – sangony Jan 18 '15 at 14:44
-
@Okapi, I'm trying to use integration frameworks for this project. I've looked at some of [raywenderlich tutorials](http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners) but the examples seem to be outdated, for instance the example he mentions uses a myscene rather than a gameviewcontroller, which has different properties. I'm trying to find other examples as well, do you know of any? – AzureWorld Jan 18 '15 at 21:13
-
Where the tutorials reference MyScene use GameScene not GameViewController. You can cut out and animate sprite sheets in SpriteKit without using other frameworks, I can provide you with code for this if you need – Jan 19 '15 at 16:43
-
@Okapi, Where exactly (in what file in the project) would I put the code to accomplish this? – sbru Jan 20 '15 at 08:50
4 Answers
In sprite kit you can cut part of a texture out using SKTexture(rect: inTexture:)
initializer. This is a helper class which manages an evenly spaced sprite sheet and can cut out a texture at a given row and column. It is used like So
let sheet=SpriteSheet(texture: SKTexture(imageNamed: "spritesheet"), rows: 1, columns: 11, spacing: 1, margin: 1)
let sprite=SKSpriteNode(texture: sheet.textureForColumn(0, row: 0))
Here is the full code
//
// SpriteSheet.swift
//
import SpriteKit
class SpriteSheet {
let texture: SKTexture
let rows: Int
let columns: Int
var margin: CGFloat=0
var spacing: CGFloat=0
var frameSize: CGSize {
return CGSize(width: (self.texture.size().width-(self.margin*2+self.spacing*CGFloat(self.columns-1)))/CGFloat(self.columns),
height: (self.texture.size().height-(self.margin*2+self.spacing*CGFloat(self.rows-1)))/CGFloat(self.rows))
}
init(texture: SKTexture, rows: Int, columns: Int, spacing: CGFloat, margin: CGFloat) {
self.texture=texture
self.rows=rows
self.columns=columns
self.spacing=spacing
self.margin=margin
}
convenience init(texture: SKTexture, rows: Int, columns: Int) {
self.init(texture: texture, rows: rows, columns: columns, spacing: 0, margin: 0)
}
func textureForColumn(column: Int, row: Int)->SKTexture? {
if !(0...self.rows ~= row && 0...self.columns ~= column) {
//location is out of bounds
return nil
}
var textureRect=CGRect(x: self.margin+CGFloat(column)*(self.frameSize.width+self.spacing)-self.spacing,
y: self.margin+CGFloat(row)*(self.frameSize.height+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
textureRect=CGRect(x: textureRect.origin.x/self.texture.size().width, y: textureRect.origin.y/self.texture.size().height,
width: textureRect.size.width/self.texture.size().width, height: textureRect.size.height/self.texture.size().height)
return SKTexture(rect: textureRect, inTexture: self.texture)
}
}
The margin property is the gap between the edge of the image and the sprites. The spacing is the gap between each sprite. The fameSize is the size each sprite will be. This image explains it:

- 4,498
- 2
- 30
- 39
-
1Thanks for providing a solution with all the code, but this is in Swift :/, the OP is tagged as Objective-C – sbru Jan 20 '15 at 19:49
-
-
@bagelboy Please see my response - a `SpriteSheet.m` class in Objective-C. – JaredH Dec 26 '15 at 21:54
-
So this doesnt require cocoa 2d or anything, just add this to any normal swift app and you could crop sprite sheets filled with images?! – Famic Tech Jan 20 '18 at 16:05
Since the original question was tagged as Objective-C, here's a rough version of this SpriteSheet class in that language. Hope this is helpful:
#import "SpriteSheet.h"
@interface SpriteSheet ()
@property (nonatomic, strong) SKTexture *texture;
@property (nonatomic) NSInteger rows;
@property (nonatomic) NSInteger cols;
@property (nonatomic) CGFloat margin;
@property (nonatomic) CGFloat spacing;
@property (nonatomic, getter=frameSize) CGSize frameSize;
@end
@implementation SpriteSheet
- (instancetype)initWithTextureName:(NSString *)name rows:(NSInteger)rows cols:(NSInteger)cols margin:(CGFloat)margin spacing:(CGFloat)spacing {
SKTexture *texture = [SKTexture textureWithImageNamed:name];
return [self initWithTexture:texture rows:rows cols:cols margin:margin spacing:spacing];
}
- (instancetype)initWithTexture:(SKTexture *)texture rows:(NSInteger)rows cols:(NSInteger)cols {
return [self initWithTexture:texture rows:rows cols:cols margin:0 spacing:0];
}
- (instancetype)initWithTexture:(SKTexture *)texture rows:(NSInteger)rows cols:(NSInteger)cols margin:(CGFloat)margin spacing:(CGFloat)spacing {
if (self == [super init]) {
_texture = texture;
_rows = rows;
_cols = cols;
_margin = margin;
_spacing = spacing;
_frameSize = [self frameSize];
}
return self;
}
- (CGSize)frameSize {
CGSize newSize = CGSizeMake((self.texture.size.width - (self.margin * 2.0 + self.spacing * ((CGFloat)self.cols - 1.0))) / ((CGFloat)self.cols),
(self.texture.size.height - ((self.margin * 2.0) + (self.spacing * ((CGFloat)self.rows - 1.0))) / ((CGFloat)self.rows)));
return newSize;
}
- (SKTexture *)textureForColumn:(NSInteger)column andRow:(NSInteger)row {
if (column >= (self.cols) || row >= (self.rows)) {
NSLog(@"Asking for row or col greater than spritesheet");
return nil;
}
CGRect textureRect = CGRectMake(self.margin + (column * self.frameSize.width + self.spacing) - self.spacing,
self.margin + (row * self.frameSize.width + self.spacing) - self.spacing, // note using width here
self.frameSize.width,
self.frameSize.height);
textureRect = CGRectMake(textureRect.origin.x / self.texture.size.width, textureRect.origin.y / self.texture.size.height, textureRect.size.width / self.texture.size.width, textureRect.size.height/self.texture.size.height);
return [SKTexture textureWithRect:textureRect inTexture:self.texture];
}

- 2,338
- 1
- 30
- 40
I am adding this into a separate answer, because it contains two important things, that I found:
First :
var textureRect=CGRect(x: self.margin+CGFloat(column)*(self.frameSize.width+self.spacing)-self.spacing,
y: self.margin+CGFloat(row)*(self.frameSize.width+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
This code in Swift and its Objective-C counterpart both have a bug. The self.frameSize.width
is used for both row and column calculations. The height needs to be used for column.
Second :
The coordinate system for SKTexture
places its (0,0) origin at the bottom left corner of the image, this has to be considered when making your sprites or the code needs to be altered.
For example You can get all the frames of the sprite from top left corner to bottom right corner of the sprite like this:
var anim = [SKTexture]()
for row in (0..<self.rows).reversed() {
for column in 0..<self.columns {
if let frame = textureForColumn(column: column, row: row) {
anim.append(frame)
}
}
}
PS. I don't have the much experience with SpriteKit, so if there are any mistakes in my answer, please correct me.

- 1,351
- 1
- 13
- 18
I did a fix for getting sprites from top to bottom, left to right.
Also added a totalFrames so if you don't have a sprite with all frames, you can set the total frames so the array only contains the sprites, no blank sprites.
//
// SpriteSheet.swift
//
import SpriteKit
class SpriteSheet {
let texture: SKTexture
let rows: Int
let columns: Int
var margin: CGFloat=0
var spacing: CGFloat=0
var frameSize: CGSize {
return CGSize(width: (self.texture.size().width-(self.margin*2+self.spacing*CGFloat(self.columns-1)))/CGFloat(self.columns),
height: (self.texture.size().height-(self.margin*2+self.spacing*CGFloat(self.rows-1)))/CGFloat(self.rows))
}
init(texture: SKTexture, rows: Int, columns: Int, spacing: CGFloat, margin: CGFloat) {
self.texture=texture
self.rows=rows
self.columns=columns
self.spacing=spacing
self.margin=margin
}
convenience init(texture: SKTexture, rows: Int, columns: Int) {
self.init(texture: texture, rows: rows, columns: columns, spacing: 0, margin: 0)
}
func textureForColumn(column: Int, row: Int)->SKTexture? {
if !(0...self.rows ~= row && 0...self.columns ~= column) {
return nil
}
var textureRect = CGRect(x: self.margin + CGFloat(column) * (self.frameSize.width+self.spacing)-self.spacing, y: self.margin + CGFloat(self.rows - row - 1) * (self.frameSize.height+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
textureRect = CGRect(x: textureRect.origin.x/self.texture.size().width, y: textureRect.origin.y/self.texture.size().height,
width: textureRect.size.width/self.texture.size().width, height: textureRect.size.height/self.texture.size().height)
return SKTexture(rect: textureRect, in: self.texture)
}
}
To call, just add the animation like this:
fileprivate let framesOpening: [SKTexture] = {
let totalFrames = 28
let rows = 6
let columns = 5
let sheet = SpriteSheet(texture: SKTexture(imageNamed: "GETREADY"), rows: rows, columns: columns, spacing: 0, margin: 0)
var frames = [SKTexture]()
var count = 0
for row in (0..<rows) {
for column in (0..<columns){
if count < totalFrames {
if let texture = sheet.textureForColumn(column: column, row: row) {
frames.append(texture)
}
}
count+=1
}
}
return frames
}()
and call it
let sprite1 = SKSpriteNode(texture: framesOpening.first)
let openingAnimation: SKAction = SKAction.animate(with: framesOpening, timePerFrame: 0.2, resize: false, restore: true)
sprite1.position = CGPoint(x: frame.midX, y: frame.midY)
sprite1.zPosition = 2000
self.addChild(sprite1)
sprite1.run(SKAction.repeatForever(openingAnimation))

- 598
- 1
- 6
- 11