Detect when rotation is complete and move to a new scene

I try to make a transition to another scene when the wheel stops spinning. The code that I have is shown below. I can’t understand how to determine when the speed 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, here I would like to do the following when the wheel stopped spinning:

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

Now I have edited the class and it looks like this:

 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") } } } 

The problem is that I still get the error message in the if statement in the didSimulatePhysics function. The error I get is "Thread 1: EXC_BAD_INSTRUCTION ...."

+5
source share
1 answer

Your SKPhysicsBody wheel has a built-in angularVelocity property that tells you how fast it spins. You are already using it when you set it to r to start the rotation of the wheel.

To view angularVelocity , you can use didSimulatePhysics() . It is called once every frame immediately after performing physical calculations. It 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 angular frequency may never be exactly zero. Therefore, instead, we see that it is less than some arbitrary threshold, in this case 0.001.

You do not want it to execute every frame when the wheel is not moving, so I added the wheelIsSpinning property for tracking. You need to add it as an instance property in GameplayScene and set it to true in spin() .

+4
source

Source: https://habr.com/ru/post/1267075/


All Articles