0
votes

So I'm trying to make a countdown timer for my game. Basically there's a player at the bottom of the screen that fires an arrow at a moving object above it. Eventually I will have an end game where if you run out of arrows or time it will execute. I'm having trouble placing the function and NSTimer/Timer properly in the code. Please help the timer should start at 30 and subtract 1 each passed second. Thanks in advance!!!

Target Code:

let timerLabel = SKLabelNode(fontNamed: "The Bold Font")

var timer = Timer()

var counter = 30

func viewDidLoad() {


        timerLabel.text = String(counter)
        timerLabel.fontSize = 250
        timerLabel.fontColor = SKColor.white
        timerLabel.verticalAlignmentMode = SKLabelVerticalAlignmentMode.center
        timerLabel.position = CGPoint(x: self.size.width/2, y: self.size.height*0.70)
        timerLabel.zPosition = 100
        self.addChild(timerLabel)

        timer = Timer.scheduledTimer(timeInterval: 1, target:self, selector: #selector(GameScene.updateCounter), userInfo: nil, repeats: true)()
    }

    func updateCounter(){

        timerLabel.text = String(describing: counter -= 1)
    }

Full Code:

//
//  GameScene.swift
//  Andrey's Game
//
//  Created by Jeffrey Foster on 12/2/16.
//  Copyright © 2016 Jeffrey Foster. All rights reserved.
//

import SpriteKit
import UIKit




class GameScene: SKScene, SKPhysicsContactDelegate {

var gameScore = 0
let scoreLabel = SKLabelNode(fontNamed: "The Bold Font")

var spermCount = 60
let spermLabel = SKLabelNode(fontNamed: "The Bold Font")

let timerLabel = SKLabelNode(fontNamed: "The Bold Font")
var timer = Timer()
var counter = 30

let andrey = SKSpriteNode(imageNamed: "Andreys_Ass")

let player = SKSpriteNode(imageNamed: "Player_Cucumber")




struct physicsCategories {
    static let None: UInt32 = 0
    static let Arrow : UInt32 = 0b1 //1
    static let Andrey : UInt32 = 0b10 //2
    static let Wall : UInt32 = 0b100 //4

}

var gameArea: CGRect

override init(size: CGSize){

    let maxAspectRatio: CGFloat = 16.0/9.0
    let playableWidth = size.height / maxAspectRatio
    let margin = (size.width - playableWidth) / 2
    gameArea = CGRect(x: margin, y: 0, width: playableWidth, height: size.height)

    super.init(size: size)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


override func didMove(to view: SKView) {

    self.physicsWorld.contactDelegate = self


    andrey.setScale(4)
    andrey.position = CGPoint(x: self.size.width/2, y: self.size.height*0.50)
    andrey.zPosition = 2
    andrey.physicsBody = SKPhysicsBody(rectangleOf: andrey.size)
    andrey.physicsBody!.affectedByGravity = false
    andrey.physicsBody!.categoryBitMask = physicsCategories.Andrey
    andrey.physicsBody!.collisionBitMask = physicsCategories.None
    andrey.physicsBody!.contactTestBitMask = physicsCategories.Arrow
    self.addChild(andrey)

    let wall = SKSpriteNode(imageNamed: "wall")
    wall.position = CGPoint(x: self.size.width/2, y: self.size.height*0.31)
    wall.size.height = 0.000005
    wall.size.width = self.size.width
    wall.zPosition = 3
    wall.physicsBody = SKPhysicsBody(rectangleOf: wall.size)
    wall.physicsBody!.affectedByGravity = false
    wall.physicsBody!.categoryBitMask = physicsCategories.Wall
    wall.physicsBody!.collisionBitMask = physicsCategories.None
    wall.physicsBody!.contactTestBitMask = physicsCategories.Arrow
    self.addChild(wall)



    let background = SKSpriteNode(imageNamed: "background")
    background.size = self.size
    background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
    background.zPosition = 0
    self.addChild(background)


    player.setScale(1)
    player.position = CGPoint(x: self.size.width/2, y: self.size.height*0.05)
    player.zPosition = 2
    self.addChild(player)

    scoreLabel.text = "Score: 0"
    scoreLabel.fontSize = 70
    scoreLabel.fontColor = SKColor.white
    scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.left
    scoreLabel.position = CGPoint(x: self.size.width*0.15, y: self.size.height*0.00)
    scoreLabel.zPosition = 100
    self.addChild(scoreLabel)

    spermLabel.text = "Sperm: 60"
    spermLabel.fontSize = 70
    spermLabel.fontColor = SKColor.white
    spermLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.right
    spermLabel.position = CGPoint(x: self.size.width*0.85, y: self.size.height*0.00)
    spermLabel.zPosition = 100
    self.addChild(spermLabel)

    func viewDidLoad() {


        timerLabel.text = String(counter)
        timerLabel.fontSize = 250
        timerLabel.fontColor = SKColor.white
        timerLabel.verticalAlignmentMode = SKLabelVerticalAlignmentMode.center
        timerLabel.position = CGPoint(x: self.size.width/2, y: self.size.height*0.70)
        timerLabel.zPosition = 100
        self.addChild(timerLabel)

        timer = Timer.scheduledTimer(timeInterval: 1, target:self, selector: #selector(GameScene.updateCounter), userInfo: nil, repeats: true)()
    }

    func updateCounter(){

        timerLabel.text = String(describing: counter -= 1)
    }




    func moveAndrey(){


            let moveAndreyRight = SKAction.moveTo(x: self.size.width, duration: 0.50)
            let moveAndreyLeft = SKAction.moveTo(x: self.size.width*0.00, duration: 1.00)
            let moveAndreyStart = SKAction.moveTo(x: self.size.width/2, duration: 0.50)
            let andreySequence = SKAction.sequence([moveAndreyRight, moveAndreyLeft, moveAndreyStart])
            let endlessAction = SKAction.repeatForever(andreySequence)
            andrey.run(endlessAction)


    }

    moveAndrey()


}







func addScore(){

    gameScore += 1
    scoreLabel.text = "Score: \(gameScore)"
}


func subtractScore(){
    gameScore -= 1
    scoreLabel.text = "Score: \(gameScore)"
}

func subtractSperm(){
    spermCount -= 1
    spermLabel.text = "Sperm: \(spermCount)"

}



func didBegin(_ contact: SKPhysicsContact) {

    var body1 = SKPhysicsBody()
    var body2 = SKPhysicsBody()

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask{
        body1 = contact.bodyA
        body2 = contact.bodyB
    }
    else{
        body1 = contact.bodyB
        body2 = contact.bodyA
    }

    if body1.categoryBitMask == physicsCategories.Arrow && body2.categoryBitMask == physicsCategories.Andrey{
        //if the arrow hits Andrey

        if body1.node != nil {
        spawnHit(spawnPosition: body1.node!.position)
        }

        addScore()

        body1.node?.removeFromParent()

    }

    if body1.categoryBitMask == physicsCategories.Arrow && body2.categoryBitMask == physicsCategories.Wall{
        //if the arrow hits Wall

        if body1.node != nil {
            spawnMissedShot(spawnPosition: body1.node!.position)
        }

        subtractScore()

        body1.node?.removeFromParent()

    }


}

func spawnHit(spawnPosition: CGPoint){

    let hit = SKSpriteNode(imageNamed: "Andrey_Hit")
    hit.position = spawnPosition
    hit.zPosition = 4
    hit.setScale(3)
    self.addChild(hit)


    let scaleIn = SKAction.scale(to: 1, duration: 0.1)
    let fadeOut = SKAction.fadeOut(withDuration: 0.1)
    let delete = SKAction.removeFromParent()

    let hitSequence = SKAction.sequence([scaleIn, fadeOut, delete])

    hit.run(hitSequence)

}

func spawnMissedShot(spawnPosition: CGPoint){

    let missedShot = SKSpriteNode(imageNamed: "missedShot")
    missedShot.position = spawnPosition
    missedShot.zPosition = 4
    missedShot.setScale(3)
    self.addChild(missedShot)


    let scaleIn = SKAction.scale(to: 1, duration: 0.1)
    let fadeOut = SKAction.fadeOut(withDuration: 0.1)
    let delete = SKAction.removeFromParent()

    let hitSequence = SKAction.sequence([scaleIn, fadeOut, delete])

    missedShot.run(hitSequence)

}





func fireArrow() {

    let arrow = SKSpriteNode(imageNamed: "Arrow_Cucumber")
    arrow.name = "Arrow"
    arrow.setScale(0.75)
    arrow.position = player.position
    arrow.zPosition = 3
    arrow.physicsBody = SKPhysicsBody(rectangleOf: arrow.size)
    arrow.physicsBody!.affectedByGravity = false
    arrow.physicsBody!.categoryBitMask = physicsCategories.Arrow
    arrow.physicsBody!.collisionBitMask = physicsCategories.None
    arrow.physicsBody!.contactTestBitMask = physicsCategories.Andrey | physicsCategories.Wall
    self.addChild(arrow)


    let moveArrow = SKAction.moveTo(y: self.size.height+arrow.size.height, duration: 1.50)
    let deleteArrow = SKAction.removeFromParent()
    let arrowSequence = SKAction.sequence([moveArrow, deleteArrow])
    arrow.run(arrowSequence)

}





override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    fireArrow()
    subtractSperm()



    }
}
1

1 Answers

1
votes

You can do this with a Timer or an SKAction with delays and repeats.

To use a timer, call the scheduledTimer class method and specify a method to call when it fires.

timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(GameScene.updateCounter), userInfo: nil, repeats: true)

This method should update some counter variable, display the current time to the user, and check if the game over criteria are met.

func updateCounter() {
    counter -= 1
    timerLabel.text = "\(counter)"
    if counter == 0 { gameOver() }
}

In the gameOver function you can stop the timer by calling

timer.invalidate()

As the complexity of your game grows, you may wish to refactor this differently.

Another method is to use an SKAction.

let waitAction = SKAction.wait(forDuration: 1)
let fireAction = SKAction.run {
    counter -= 1
    timerLabel.text = "\(counter)"
    if counter == 0 { gameOver() }
}
let actionSequence = SKAction.sequence([waitAction, fireAction])
let repeatAction = SKAction.repeatForever(actionSequence)
self.run(repeatAction, withKey: "timer")

In the gameOver function you can stop the action by calling

self.removeAction(forKey: "timer")

Hope that helps! Good luck with your game.