Custom Drawing in Sprite Kit
SpriteKit makes it easy to add and manipulate images on iOS (thus the name), but I've occasionally wanted to draw simple elements. I recently worked out a method that works.
The gist of the technique is to draw onto a Graphics Context, then turn that into an image and then into a sprite.
First, create an image context, using whatever size you ultimately need to produce.
UIGraphicsBeginImageContext(CGSizeMake(240, 240));
CGContextRef ctx = UIGraphicsGetCurrentContext();
Then draw whatever you need, remember to set fill and stroke colors.
[[SKColor whiteColor] setFill];
CGContextFillRect(ctx, CGRectMake(0, 0, 240, 240));
[[UIColor brownColor] setFill];
CGContextFillEllipseInRect(ctx, CGRectMake(v.x-2, v.y-2, 4, 4));
CGContextFillRect(ctx, CGRectMake(c.center.x, c.center.y, 30, 30));
and so on. Polygon shapes and lines are a little more complicated, as you have do make them as a path first.
A line
CGContextMoveToPoint(ctx, de.left.x, de.left.y);
CGContextAddLineToPoint(ctx, de.right.x, de.right.y);
CGContextDrawPath(ctx, kCGPathStroke);
A filled polygon, with a trick that I saw somewhere to use an if statement to move to the first vertex of a list of points, and adding the rest to make a polygon shape.
for (NSInteger i=0; i<verts.count; i++) {
CGPoint p = [[verts objectAtIndex:i] CGPointValue];
if (i==0) {
CGContextMoveToPoint(ctx, p.x, p.y);
} else {
CGContextAddLineToPoint(ctx, p.x, p.y);
}
}
CGContextDrawPath(ctx, kCGPathFill);
By far the easiest mistake to make here is to leave off the CGContextDrawPath
call, and then wonder why nothing shows up on your image.
Finally, build the image and generate a SpriteNode
UIImage *textureImage = UIGraphicsGetImageFromCurrentImageContext();
SKTexture *texture = [SKTexture textureWithImage:textureImage];
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithTexture:texture];
[self addChild:bg];
To start out, I added all this to the initWithSize
method of MyScene.m
in a SpriteKit project. At some point it will make sense to pull this out and make a subclass of SKSpriteNode
. I used a class method that returned the SpriteNode to the scene, but the hard part for me is usually just getting started in the first place.
The only other gotcha is that Image Context here uses typical screen coordinate origin of upper left (and +y being down the screen), where SpriteKit uses a lower left origin. I'm sure you could transform out of it if it was really in the way, but I think for most cases that is overkill, but it is something to keep in mind.
Update: Don't forget to call UIGraphicsEndImageContext
when you are done.