2

I'm trying to get my "Player" (A circle in the middle) to increase in size once the screen is touched by running a timer.

Once the timer is over 0 seconds, it increases in size. Once the timer is over 3 seconds, it decreases to its original scale size and once the timer is over 7 seconds, it resets and this repeats forever.

What am I doing wrong?

import SpriteKit

class GameScene: SKScene {

    var Center = SKSpriteNode()
    var Player = SKSpriteNode()
    var timer = NSTimer()
    var seconds = 0

    override func didMoveToView(view: SKView) {

        Center = SKSpriteNode(imageNamed: "Center")
        Center.size = CGSize(width: 80, height: 80)
        Center.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
        self.addChild(Center)

        Player = SKSpriteNode(imageNamed: "Player")
        Player.size = CGSize(width: 80, height: 80)
        Player.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
        self.addChild(Player)

    }


    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        timer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: #selector(GameScene.playerScaleUp), userInfo: nil, repeats: true)

       }

    func playerScaleUp(){
        if seconds > 0{
            Player.runAction(SKAction.scaleBy(4, duration: 2))

        }

    }

    func playerScaleDown(){
        if seconds > 3{
            Player.runAction(SKAction.scaleBy(-4, duration: 2))

        }
    }

    func resetScale(){
        if seconds > 7{
            timer.invalidate()

        }
    }

    override func update(currentTime: CFTimeInterval) {



    }

}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253

1 Answers1

1

This can be done in a few different ways:

1) Using SKActions (which my example uses)

2) Using update: method and its passed currentTime parameter

3) Using NSTimer which I wouldn't recommend because it is not affected by scene's, view's or node's paused state, so it can lead you into troubles in the future. Read more in this StackOverflow answer

4) Well, probably some more, but I will stop here.

My example uses SKAction. This means that I don't really check how much time is passed, but rather I organize actions into sequences (where actions are executed sequentially) and into groups (where actions are organized parallel). Means I use SKActions like I am playing with LEGO's :)

Here is the code ...I left debugging code intentionally, because it can help you to learn how you can use SKActions in different situations.

class GameScene: SKScene, SKPhysicsContactDelegate {

    let player = SKSpriteNode(color: .blackColor(), size: CGSize(width: 50, height: 50))

    var timePassed = 0.0 {
        didSet {
            self.label.text = String(format: "%.1f",timePassed)
        }
    }

    let label = SKLabelNode(fontNamed: "ArialMT")

    override func didMoveToView(view: SKView) {

        /* Debugging - Not really needed, I added it just because of a better example */
        let wait = SKAction.waitForDuration(0.1)

        let updateLabel = SKAction.runBlock({[unowned self] in self.timePassed += wait.duration})

        self.label.position = CGPoint(x: frame.midX, y: frame.midY+100.0)
        addChild(self.label)
        let timerSequence = SKAction.sequence([updateLabel, wait])
        self.runAction(SKAction.repeatActionForever(timerSequence), withKey: "counting")

        //This is used later, at the end of scaleUpAndDownSequence to reset the timer
        let resetTimer = SKAction.runBlock({[unowned self] in self.timePassed = 0.0})


        /* End Debugging */


        self.player.position = CGPoint(x: frame.midX, y: frame.midY)
        addChild(self.player)

        let waitBeforeScaleToOriginalSize = SKAction.waitForDuration(3.0)
        let waitBeforeRestart = SKAction.waitForDuration(4.0)

        let scaleUp = SKAction.scaleTo(2.0, duration: 1)
        let scaleDown = SKAction.scaleTo(1.0, duration: 1)

        let scaleUpGroup = SKAction.group([waitBeforeScaleToOriginalSize, scaleUp])
        let scaleDownGroup = SKAction.group([scaleDown, waitBeforeRestart])

        //One cycle, scale up, scale down, reset timer
        let scaleUpAndDownSequence = SKAction.sequence([scaleUpGroup, scaleDownGroup, resetTimer])

        let loop = SKAction.repeatActionForever(scaleUpAndDownSequence)

        self.player.runAction(loop, withKey: "scalingUpAndDown")
    }
}

So here, I have two groups of actions:

1) scaleUpGroup

2) scaleDownGroup

scaleUpGroup group of actions has two actions in it: a scaleUp action, and an action which says how much to wait before the scale down action should occur. Because we want scaling up to happen immediately, we run it in parallel with the waitBeforeScaleToOriginalSize.

Same logic goes for scaleDownGroup. When scaleUpGroup is finished (its duration is determined by the longest action in the group) we start scaleDownGroup which scales down the player to its default size, and waits certain amount of time to repeat the whole thing.

Here is the result:

Scaling Up and Down

I start an animation on touch ( I've removed that code) and as you can see, scale up animation starts immediately, then after 3 seconds the player get scaled down to its original size, and after 4 seconds the whole animation repeats (player gets scaled up again etc).

Community
  • 1
  • 1
Whirlwind
  • 14,286
  • 11
  • 68
  • 157
  • @ddramond You are welcome :) If this answer helped you to solve your issue, please mark it as accepted. You may find this useful to read [this](http://stackoverflow.com/help/accepted-answer). – Whirlwind Apr 17 '16 at 13:58