Living Without Storyboards: Make a Clock with Sprite Kit

Sprite Kit — it’s not just for games anymore.  Sprite Kit is of course meant to write games, a full 2-d game engine waiting for use inside Xcode and iOS7.  While simulating buttons  writing SlippyFlippyPenguin, I began to realize there’s a lot more here that could be applied to a general UI. I’ve often tried to apply animations to elements on the storyboard ending up with flicker. A true built-in game cycle does much for removing flicker. Sprite Kit can create beautiful animated  user interfaces. This post series will make a basic clock app using Sprite Kit as a demonstration.

Before we do, its important to understand the concept of the game cycle.  Games are based on frames, similar to frames of a motion picture. By flickering images at a rate fast enough, the eye and brain treat the images as a smooth motion. Games run somewhere between 30 and 60 frames per second.

The game cycle treats each frame as unique, gets and reacts to events, and then renders an image that frame. There are a few methods involved with Sprite Kit’s game cycle which the developer overrides to make this happen. The most important for this demonstration is update:.

Make a Sprite Kit App

Open Xcode and Start a new project. There are two ways of getting to Sprite Kit,  but the template is a bit easier to start, so choose the Sprite Kit Game template.  Name  the application SpriteTimeClock.

Xcode will load a template with a Hello World demonstration of Sprite Kit. Click over to the MyScene.m implementation file. Start by deleting all the touchesBegan: method.

Make the Label

Create the label node we will use throughout the class.

@implementation MPMyScene{
    SKLabelNode *myTimeLabel;
}

Change the code in initWithSize: to this:

self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
myTimeLabel = [SKLabelNode labelNodeWithFontNamed:@"AmericanTypeWriter-Bold"];
myTimeLabel.text = @"00:00:00";
myTimeLabel.fontSize = 40;
myTimeLabel.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMaxY(self.frame)*0.80);
myTimeLabel.name = @"myTimeLabel";
[self addChild:myTimeLabel];

Line 1 sets our background color, which we left the same as the template. Line 2 makes a Label node, the Sprite Kit equivalent of a Label View, setting the font to American TypeWriter. Lines 3 and 4 set the text and font size properties, which are self-explanatory.

Line 5 sets the position with a CGPoint, which requires a bit of explanation. As I mentioned in the grids post, using percentages relative to the size of the frame avoids a lot of screen fragmentation problems. The system adjusts for the differences between 3.5″ and 4″ automatically. It will even adjust for iAd banners if they take up part of the view.

A big difference between the coordinate systems of UIView and Sprite Kit is a different origin and coordinate system. The origin is on the lower left corner and increases in value towards the top. While one might expect this label with a Y value of CGRectGetMaxY(self.frame)*0.80 to be in the lower fifth of the screen, it is actually in the upper fifth. Another difference is the node’s positioning anchor for Sprite Kit is not a corner by default, but the center of the node. The x position CGRectGetMidX(self.frame) is centered on the frame.

Line 6 is just good practice. Naming a node allows for searching for the node in the node tree. While I declared an instance variable I don’t have to. I can find the node by its name in any code I write using the childNodeWithName: method. See Making a Basic Obstacle for some examples.

We have not added the node to the node tree. Until we do, it does not exist in the application. Line 7 does this critical step.

Make a Clock

We want to make a clock, and to get the time we have an advantage: the update: method provides one for us. The clock helps a game developer time events in the game, but we will use the raw data from the CFTimeInterval to tell the time. This is a double which has the number of seconds since a reference date. The Core Foundation function CFAbsoluteTimeGetGregorianDate() will convert the time into the struct CFGregorianDate which has the date and time information in a usable form. To adjust for timezone, we use CFTimeZoneCopySystem() in the function. This function needs to be manually released. We can then use our results to make up a formatted string for the label. Add the following to update:

-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
CFGregorianDate currentDate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), CFTimeZoneCopySystem());
CFRelease(CFTimeZoneCopySystem());
NSString *formattedTimeString = [NSString stringWithFormat:@"%02d:%02d:%02.0f", currentDate.hour, currentDate.minute, currentDate.second];
myTimeLabel.text = formattedTimeString;
}

While most of the CFGregorianDate struct is integers, the seconds are a double. Build and run this.

Screenshot 2014-05-07 07.23.04

We have a quick and basic clock in a few lines of code. While this is not impressive by itself, next post we will add animation to the clock to switch between the date and the time.

One Reply to “Living Without Storyboards: Make a Clock with Sprite Kit”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s