3

I have a problem in pausing a sprite kit game with physics. The game contains a ball which moves in the SpriteScene and has the following parameters:

self.ball.physicsBody.friction = 0;
self.ball.physicsBody.linearDamping = 0;
self.ball.physicsBody.restitution = 1.0f;
self.ball.physicsBody.affectedByGravity = NO;
self.ball.physicsBody.usesPreciseCollisionDetection = YES;

The problem is that when I pause the game, I call these methods:

self.scene.physicsWorld.speed = 0;
self.ball_velocity = self.ball.physicsBody.velocity;
self.ball.physicsBody.velocity = CGVectorMake(0, 0);
self.ball.speed = 0;
self.ball.physicsBody.dynamic = NO;
[self.scene.view setPaused:YES];

and when resume, call these:

self.scene.physicsWorld.speed = 1;
self.ball.physicsBody.velocity = self.ball_velocity;
self.ball.physicsBody.dynamic = YES;
self.ball.speed = 1;
[self.scene.view setPaused:NO];

This stops the ball animation, but when resume, the ball position is changed and it seems if that was moving during the pause duration.

BTW, it works fine on iOS 8 but on iOS 9 it always fails.

Any suggestions ?!!

Amani Elsaed
  • 1,558
  • 2
  • 21
  • 36
  • Does this happen always ? Try two cases : 1. Pause the game, and unpause it immediately. 2. Pause the game, wait few seconds, and unpause it. Try to observe fps while [pausing and unpausing the view](http://stackoverflow.com/q/31471288/3402095) It may happen, that some lag occur immediately after the view is unpaused. This is not happening when the scene is paused/unpaused. So instead of a view, you could pause the scene. – Whirlwind Jan 13 '16 at 12:53
  • It seems as the ball is continuing its motion during the pause duration and when unpause, it is immediately transferred to the new location. I have tried to pause the scene itself but the same error happens !!! – Amani Elsaed Jan 13 '16 at 13:09
  • That's odd. I can't produce what you are saying if I pause the scene. Actually, I can produce what you are saying only if I quickly pause/unpause the view. What Xcode , device and simulators do you use ? – Whirlwind Jan 13 '16 at 13:11
  • the question is where are you calling the pause and resume, and is velocity the only thing you use to move the sprite, or do you have actions – Knight0fDragon Jan 13 '16 at 13:53
  • I have tested it on iOS 8 and it works fine - pause and resume correctly -, but on iOS 9, this issues always happens whether I paused quickly or not. @Knight0fDragon: I call pause and resume on button pressed, and there are no actions applied to the ball, only the velocity. BTW, on iOS 8, it works fine only with [self.scene setPaused:YES]. – Amani Elsaed Jan 13 '16 at 14:15
  • that is weird, because scene pause does not pause the update loop, also it does not make sense to be changing your physics, and it is very possible that something is happening behind the scenes that is resetting some of the physics states. Then again, pausing the view might cause it to jump, since the time lapse in your update method is going to show a much higher differential, and the velocity math may take that into consideration – Knight0fDragon Jan 13 '16 at 15:25
  • @Knight0fDragon actually pausing scene calls update loop in iOS 8, but it doesn't call it in iOS 9 !!! pausing the view doesn't call it in both. But pausing the view causes the error to happen in both iOS8 and 9, that is why I pause the scene only now, to make it work on iOS 8. – Amani Elsaed Jan 13 '16 at 16:05
  • well then what I said makes sense, since update is not being called, the time lapsed is not taking into account till the next update. I will verify what is going on, but if scene pause is indeed stopping update, all you need to do is throw all the nodes that are currently on scene into a node, then just pause the node. (Instead of scene - > children nodes, we have scene -> parent node -> children nodes, parent.paused = true – Knight0fDragon Jan 13 '16 at 16:07
  • Just verified, pausing the scene does pause the update, this must have been intentional on Apples part, and was "broken" in iOS 8 – Knight0fDragon Jan 13 '16 at 16:13
  • but this seems to be weird, since the scene pause should pause all actions and physics of all nodes in the scene. – Amani Elsaed Jan 13 '16 at 16:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/100607/discussion-between-knight0fdragon-and-amani-elsaed). – Knight0fDragon Jan 13 '16 at 16:47

1 Answers1

2

After chatting, we have come to the conclusion that between iOS8 and iOS9, Apple has done a change that pausing the scene now pauses the update loop. Since the update loop is being paused, the change in time is not being calculated correctly. What is now happening, is the change in time will be the time at unpause - the time at pause, simulating a lag state. The velocity will take the math into effect, and move objects based on this difference in time. To combat this issue, just make a parent node that will house all of your scenes's objects, and pause the parent. This will allow the update to still be called, thus allowing the change in time to stay consistent with the frame rate.

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • Just an important note, setting ball.paused only doesn't work on iOS 9, it works fine on iOS 8. To fix this, I have set the ball velocity to 0, then after resume, I set it back to the normal velocity. – Amani Elsaed Jan 13 '16 at 18:17
  • Yeah it seems this is not the answer, we must have something that is missing that you are doing. I wrote up a sample app that pauses the scene, and the velocity of the physics is not based on the update timer whatsoever, on both slow and fast pausing, my sprite moved exactly as expected. This example also worked on both iOS 8 and iOS 9. Can you post what is inside your update function, I have a feeling you may be doing something that is not correct, – Knight0fDragon Jan 13 '16 at 18:43
  • @AmaniElsaed, if you want to test it. create a new spritekit app, and in the example, move the touch code that makes a sprite into the moved to view area, instead of using the SKAction rotate, take that out, add a physics body, and set the velocity to -30,0. Then have touch just do self.paused = !self.paused. Your sprite should move at the expected speed – Knight0fDragon Jan 13 '16 at 18:52