Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect when rotation has completed and move to new Scene

Tags:

I am trying to implement moving to another scene when a wheel stops rotating. The code I have is shown below. I cannot figure out how to detect when the velocity has reached 0.0?

import SpriteKit
import GameplayKit

class GameplayScene: SKScene {

    var player: Player?;

    override func didMove(to view: SKView) {
        player = self.childNode(withName: "spinner") as! Player?;
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: self)
            if atPoint(location).name == "play_button" {
               spin()
            }
        }
    }

    func spin () {
        let random = GKRandomDistribution(lowestValue: 20, highestValue: 90)
        let r = random.nextInt()
        player?.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(self.frame.width))
        player?.physicsBody?.affectedByGravity = false
        player?.physicsBody?.isDynamic = true
        player?.physicsBody?.allowsRotation = true
        player?.physicsBody?.angularVelocity = CGFloat(r)
        player?.physicsBody?.angularDamping = 1.0
    }

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

     }
}

So from here, I would like to execute the following when the wheel has stopped spinning:

let play_scene = Questions(fileNamed: "QuestionsScene")
play_scene?.scaleMode = .aspectFill
self.view?.presentScene(play_scene!, transition: SKTransition.doorsOpenVertical(withDuration: 1))

I have now edited the class and it looks as follows:

import SpriteKit
import GameplayKit

class GameplayScene: SKScene, SKSceneDelegate {


var player: Player?

override func didMove(to view: SKView) {
    self.delegate = self
    player = self.childNode(withName: "spinner") as! Player?;

}

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

    for touch in touches {
        let location = touch.location(in: self)
        if atPoint(location).name == "play_button" {
            spin()
        }
    }
}
    func spin () {
        let random = GKRandomDistribution(lowestValue: 20, highestValue: 90)
    let r = random.nextInt()
    player?.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(self.frame.width))
    player?.physicsBody?.affectedByGravity = false
    player?.physicsBody?.isDynamic = true
    player?.physicsBody?.allowsRotation = true
    player?.physicsBody?.pinned = true
    player?.physicsBody?.angularVelocity = CGFloat(r)
    player?.physicsBody?.angularDamping = 1.0

}

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

}
    override func didSimulatePhysics() {
        if ((player?.physicsBody?.angularVelocity)! <= CGFloat(0.01)) 
        {
            print("Got it")
        }
    }
}

Problem is I still receive an error on the if statement within didSimulatePhysics function. The error I receive is "Thread 1: EXC_BAD_INSTRUCTION...."

like image 759
Nick Avatar asked Apr 24 '17 04:04

Nick


1 Answers

Your wheel's SKPhysicsBody has a built-in property, angularVelocity, that tells you how fast it's spinning. You're already using it when you set it to r to start the wheel spinning.

To watch angularVelocity you can use didSimulatePhysics(). It gets called once every frame, right after the physics calculations are done. That will look something like this:

func didSimulatePhysics() {
    if wheelIsSpinning && angularVelocity != nil && angularVelocity! <= CGFloat(0.001) {
        wheelIsSpinning = false
        // wheel has stopped
        // add your code here
    }
}

Due to the vagaries of physics modeling, the angularVelocity might never be exactly zero. So instead we watch for it to be less than some arbitrary threshold, in this case 0.001.

You don't want it to execute every frame when the wheel isn't moving, so I added a property wheelIsSpinning to keep track. You'll need to add it as an instance property to GameplayScene, and set it to true in spin().

like image 141
Robert Avatar answered Sep 24 '22 11:09

Robert