Swift 3 (SpriteKit): stopping a continuous SKAction loop has a delay

I am trying to make SKAction launch forever, which I can stop when I want. I did it like this:

override func didMove(to view: SKView) { run(SKAction.repeatForever ( SKAction.sequence ([ SKAction.run(drawFrame), SKAction.wait(forDuration: 0.01), ])), withKey: "frameDrawing" ) } 

Then, in the drawFrame function, stop SKAction as follows:

 func drawFrame() { //(code) if stop { removeAction(forKey: "frameDrawing") } } 

For some reason, SKAction stops only when it starts 3 or 4 times after the stop has become true. I want it to stop instantly when stop is set to true, and not after 3 or 4 repetitions.

If anyone knows how to fix this, tell me because I have tried many things and they never fix the problem. Thanks!

Edit: Here is my code:

 var drawingFrame = SKAction() class GameScene: SKScene, SKPhysicsContactDelegate { override func didMove(to view: SKView) { drawingFrame = SKAction.repeatForever ( SKAction.sequence ([ SKAction.run(drawFrame), SKAction.wait(forDuration: 0.03), ])) run(drawingFrame) } func drawFrame() { //(code) if stop { drawingFrame.speed = 0.0 } } 

If you're wondering why I set the SKAction drawing frame to an empty SKAction at the beginning, this is because I needed to define a SKAction in front of both functions. Otherwise, it will not be defined for both functions.

CHANGE ANY Tough Problem: I fixed the problem using my own thinking and @appzYourLife solution. The most efficient way that works every time is to only run the code if the stop is false. But make sure that the if statement that stops the program is outside of this bracket, so SKAction will eventually stop. This is the working code:

 var drawingFrame = SKAction() class GameScene: SKScene, SKPhysicsContactDelegate { override func didMove(to view: SKView) { drawingFrame = SKAction.repeatForever ( SKAction.sequence ([ SKAction.run(drawFrame), SKAction.wait(forDuration: 0.03), ])) run(drawingFrame) } func drawFrame() { if stop = false { //(code) } if stop { removeAllActions() } } 

If you prefer this, you can use the if else statement for the stop = false statement.

+6
source share
3 answers

I have no exact explanation why drawFrame () is being called several times at the moment (but I will try to find that: D) ​​... In any case, try this code:

 import SpriteKit class GameScene: SKScene, SKPhysicsContactDelegate { var stop = false override func didMove(to view: SKView) { run(SKAction.repeatForever ( SKAction.sequence ([ SKAction.run({[unowned self] in if self.stop { self.action(forKey: "frameDrawing")?.speed = 0.0 }else{ self.drawFrame() } }), SKAction.wait(forDuration:0.03), ])), withKey: "frameDrawing" ) } func drawFrame() { //(code) print("drawFrame") } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) stop = !stop print(stop ? "stopped": "running") if !stop { self.action(forKey: "frameDrawing")?.speed = 1.0 } } } 

Use touchhesBegan to switch pause mode.

+4
source

You can delete all actions performed in the current node. This will immediately remove not only the sequence action, but also the inline actions.

 func drawFrame() { if stop { removeAllActions() } } 
+4
source

Try creating a link to SKAction and cause a speed change (up to 0.0) on it when you want it to stop. Both of them will be faster than you need to search for the name of the action, and then delete it. But at 0.01, you already repeat it faster than the frame rate (0.01666), so you will always get at least one additional iteration of the action, no matter how well you stop it.

sort of:

 let myAction = SKAction.repeatForever ( SKAction.sequence ([ SKAction.run(drawFrame), SKAction.wait(forDuration: 0.01), ])) //when you want to run it run(myAction) // when you want to stop it: myAction.speed = 0.0 
0
source

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


All Articles