2

Just getting into SpriteKit on iOS using Swift. I have a 'Breakout' game from a tutorial and I want to implement a countdown before every ball launches, by putting an SKLabel in the middle of the screen which counts down from 5 to 1 before removing itself and the game starting. Whilst the countdown is going on, you can see the full games screen with the wall, stationary ball etc.

I can't work out where in the game loop to do this. If I do the countdown in didMoveToView (where I create the wall and initialise the ball and paddle), I never see it, but I see my debugging messages in the log. I guess that didMoveToView is called before the SKScene is presented.

I tried to use a flag to call the countdown function the first time 'Update' is called, but again I saw the countdown executed before anything appeared on screen - i think 'update' is called initially before the scene is rendered.

I could implement a 'Tap screen to start' screen in a another SKScene, but I really wanted a countdown on the screen with the wall and the (stationary) ball ready to go. I could create this countdown scene using a background image of the game screen, but this seems awkward.

Any suggestions gratefully received,

Steve

Steve Ives
  • 7,894
  • 3
  • 24
  • 55
  • It's never a good sign when you Google for a solution and the top hit is your own question on SO... – Steve Ives Mar 11 '16 at 15:16
  • update is called exactly once per frame – Simone Pistecchia Mar 11 '16 at 16:24
  • @SteveIves Check out my solution with NSTimers below and let me know if anything doesn't work. – owlswipe Mar 11 '16 at 16:37
  • Ok - bit of a learning experience here. It suddenly hit me why my SKSpritelabel countdown worked in didMoveToView but not in Update - updating an SKLabel in a loop in Update won't work because the label isn't re-rendered between iterations, unlike a UILabel in a UIView. Obvious once you think about it. – Steve Ives Mar 11 '16 at 18:31

2 Answers2

6

Added these functions and a call to countdown(5) at the end of didMoveToView

func countdown(count: Int) {
    countdownLabel.horizontalAlignmentMode = .Center
    countdownLabel.verticalAlignmentMode = .Baseline
    countdownLabel.position = CGPoint(x: size.width/2, y: size.height*(1/3))
    countdownLabel.fontColor = SKColor.whiteColor()
    countdownLabel.fontSize = size.height / 30
    countdownLabel.zPosition = 100
    countdownLabel.text = "Launching ball in \(count)..."

addChild(countdownLabel)

let counterDecrement = SKAction.sequence([SKAction.waitForDuration(1.0),
    SKAction.runBlock(countdownAction)])

runAction(SKAction.sequence([SKAction.repeatAction(counterDecrement, count: 5),
    SKAction.runBlock(endCountdown)]))

}

func countdownAction() {
    count--
    countdownLabel.text = "Launching ball in \(count)..."
}

func endCountdown() {
    countdownLabel.removeFromParent()
    ball.physicsBody!.applyImpulse(CGVectorMake(20, 20))
}

So I create and set up the text of the countdown and then create and run an SKAction that waits for 1 second before decrementing the countdown and updating the label. It repeats this 5 times and then removes the countdown label before finally giving the ball an impulse to start it moving and so the game proper can start.

Seems to work ok...

Steve Ives
  • 7,894
  • 3
  • 24
  • 55
2

This is where NSTimers really come in handy. An NSTimer basically activates a function every so often (you specify how often).

Update: Sometimes it's better not to use an NSTimer; see here: https://stackoverflow.com/a/24950982/5700898

Here's a code sample, using NSTimer:

class ViewController: UIViewController {
var countdownTime = 5
var countdownTimer = NSTimer()
// above, setting your timer and countdown time as global variables so they can be accessed in multiple functions.

func PlayerPressesStart() {
countdownTime = 5
countdownTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "Countdown", userInfo: nil, repeats: true) // calls the function "Countdown" every second.
}

func Countdown() { // this is the function called by the timer every second, which causes your "countdownTime" to go down by 1. When it reaches 0, it starts the game.
countdownTime--
if countdownTime > 0 {
countdownTimer.invalidate()
placewhereyoudisplaycountdown.text = String(countdownTime)
}
if countdownTime == 0 {
// call the function where game action begins here, or call the function that makes the game begin here.
}
} // closing bracket for the View Controller, don't include this if you're copying and pasting to your already existing View Controller.
Community
  • 1
  • 1
owlswipe
  • 19,159
  • 9
  • 37
  • 82
  • Thanks John. I'll give this a try as well as seeing if I can get an SKAction to decrement my countdown SKLabel from 5 to 1 over 5 seconds before firing the ball off (probably by giving it an impulse when the action has completed). – Steve Ives Mar 11 '16 at 18:34
  • 1
    Thanks for the code sample John, but following the advice not to use NSTimer in SpriteKit, I went straight for the SKAction technique. – Steve Ives Mar 14 '16 at 11:13