Creating an Outlined Countdown Timer in SpriteKit with Swift

There’s a reason that most game developers don’t use Apple’s tools: they’re very limited. For instance, with UIKit, you can create a label and easily adjust its stroke color and stroke width. With SKLabelNodes in SpriteKit, those properties don’t exist. Therefore, it is (as of iOS 9 and Xcode 7.2) impossible to create an outlined SKLabelNode without doing some extra work.

I want my countdown timer in Corgi Corral to be white with a black outline. I combined two excellent tutorials to do this: Creating a Countdown Timer in SpriteKit with Swift and Outline Text in SpriteKit. Here’s the end result:

countdown timer with outline

In order to do this, you’ll need to use the great custom class ASAttributedLabelNode by Alex Studnicka. Just download the zip file from GitHub and copy the ASAttributedLabelNode.swift file into your project.

The timer tutorial has you create a custom subclass of SKLabelNode, adding several functions that compare dates and allow the label to update itself. I changed it to be a subclass of ASAttributedLabelNode instead and added two extra functions: one that formats the time as M:SS (single digit minutes and seconds) and one that sets the attributes of the string (stroke width, color, font, etc.). Here’s the full class:

class CountdownTimer: ASAttributedLabelNode {
    
    var endTime: NSDate!
    
    
    func update() {
        let remainingTime = timeLeft()
        attributedString = stringFromTimeInterval(remainingTime)
        
    }
    
    func startWithDuration(duration: NSTimeInterval) {
        let timeNow = NSDate()
        endTime = timeNow.dateByAddingTimeInterval(duration)
        
    }
    
    func hasFinished() -> Bool {
        
        return timeLeft() == 0
    }
    
    func createAttributedString(string: String) -> NSMutableAttributedString {
        let font =  UIFont(name: "Futura-Medium", size: 65)
        let textAttributes = [
            NSFontAttributeName : font!,
            // Note: SKColor.whiteColor().CGColor breaks this
            NSForegroundColorAttributeName: UIColor.whiteColor(),
            NSStrokeColorAttributeName: UIColor.blackColor(),
            // Note: Use negative value here if you want foreground color to show
            NSStrokeWidthAttributeName: -3
        ]
        return NSMutableAttributedString(string: string , attributes: textAttributes)
    }
    
    func stringFromTimeInterval(interval: NSTimeInterval) -> NSMutableAttributedString {
        let interval = Int(interval)
        let seconds = interval % 60
        let minutes = (interval / 60) % 60
        let timeString = String(format: "%01d:%02d", minutes, seconds)
        return createAttributedString(timeString)
    }
    
    private func timeLeft() -> NSTimeInterval {
        
        let now = NSDate()
        let remainingSeconds = endTime.timeIntervalSinceDate(now)
        return max(remainingSeconds, 0)
    }
}

Next, all you have to do is create a new CountdownTimer in your game’s scene class (by default it’s called GameScene.swift). Assuming your timer is named “timer”, whenever you want the timer to start, call timer.startWithDuration(seconds). In the scene’s update method, you can simply put timer.update().

Note: The end result of this is that you get an SKNode that you can do all sorts of SpriteKit-y things with. However, since it’s not actually an SKLabelNode, the vertical and horizontal alignment methods won’t work. You’ll have to position it like a regular node.

Obviously you can change the font to whatever you want, as well as the time format. And if you want to be able to have multiple timers with different attributes, you could always override the initializer to take a font name, size, color, etc. In fact, I might do that just to make it more flexible. Anyway, hope this helps somebody!