3

I've been struggling with this problem for a while, which appears to be buried deep inside the spritekit physics engine.

My first question would be: Does Spritekit process its physics updates in a different thread than the main thread?

I have a "world" node in the scene which I move around to simulate a "camera" view. As such, I can center the "camera" on my player character node. Since the player jumps up and down a lot, I want to smooth the camera. Without camera smoothing, there's no problems. But when I add camera smoothing, as such: (this code is called from didFinishUpdate)

CGPoint ptPosition = self.position;
float fSmoothY = m_fLastCameraY + (ptPosition.y - m_fLastCameraY) * 0.1;

CGPoint pointCamera = [self.scene convertPoint:CGPointMake(ptPosition.x, fSmoothY) fromNode:self.parent];
[gameScene centerOnPoint:pointCamera];

m_fLastCameraY = fSmoothY;

If I call the above code from didSimulatePhysics, it does the exact same thing. It stutters whenever it falls down (due to the Y camera smoothing).

When plotting it out, you can see that the player Y (the red line) is stuttering over the course of the frames.

How can I fix this, or work around it if it can't be truly "fixed"?

Codecat
  • 2,213
  • 3
  • 28
  • 39
  • Did you plot this on the device or simulator? Did you use NSLog to create the plot data? If so, try avoiding that because logging adds overhead, instead collect the data in an array and log it after the test is complete. Try moving the node with a move action (disable physics) to see whether the effect is truly connected to physics. And monitor framerate to see if maybe framerate fluctuates whenever there's a variance. – CodeSmile Dec 10 '14 at 11:23
  • @LearnCocos2D I have been testing this on an iPad Mini, iPad 3, and even iPhone 5C. I've used `NSLog` to plot the graph (in Google Docs), but I'm sure the results are the same when not actively logging the data. The delta time is mostly the same (I plotted it earlier to see it in detail), so I'm fairly sure the FPS is smooth: http://i.imgur.com/xhb6ZNp.png – Codecat Dec 10 '14 at 12:21
  • @LearnCocos2D Sometimes the stuttering doesn't happen, and sometimes it does. It's like a 50/50 chance, which makes me think that physics are being done in parallel of the regular game updates. – Codecat Dec 10 '14 at 12:24
  • I doubt that because as you can see in the SK Programming Guide the update loop diagram shows a clearly linear process. It also wouldn't make any sense - what should Sprite Kit do in the time the physics are being calculated? It has already run the update: method, it evaluated the actions because both could influence the physics simulation. Then it simulates physics but has to wait for it to complete (and didFinishSimulation to run) before it can render the results to the screen. Multithreading isn't the cause. – CodeSmile Dec 10 '14 at 13:08
  • But ... maybe you are doing something "fishy"? For instance if you use NSTimer, GCD (dispatch_... methods) or performSelector:afterDelay or inBackground: then it's possible that this code sometimes runs before, other times after the physics update. See: http://stackoverflow.com/a/23978854/201863 – CodeSmile Dec 10 '14 at 13:09
  • And on other occassions other devs have already noticed that SK physics are non-deterministic, which indicates that the physics simulation itself uses delta time in some form during its update. So if nothing else, minute delta time variances are probably the cause. You could fight this by averaging your movement, ie take the combined direction vector over the last 5 to 10 frames and allow the camera to lag slightly behind (which seems to be what you're after anyway). – CodeSmile Dec 10 '14 at 13:12
  • I had this same problem. You probably borrowed this code from raywederlich book on spritekit right? I think it happens because you have your sprite moving in one direction but you're pulling it's parent node in the other to create that camera effect. When those two things happen at a different rate you get the stutter. It would only happen for me after loading my second level. I could never figure this out =/ i had to remove my camera easing to fix the stutter – hamobi Dec 10 '14 at 15:38
  • @hamobi I did not use that book, this is my own solution. I'll try to get to a solution over the next few days. Good to know I'm not the only one though. Thanks for the input. – Codecat Dec 11 '14 at 10:10
  • could this be a value rounding issue? –  Dec 11 '14 at 20:08
  • @Okapi I don't think so - the stuttering in the Player Y seems to be caused internally by Spritekit physics. – Codecat Dec 13 '14 at 22:00
  • As a temporary workaround, I've changed the amount of smoothing (from *0.1 to *0.02), so that it doesn't cause these visual annoyances, but ultimately that's not a great solution to something that seems to be a fundamental problem in SK physics. – Codecat Dec 13 '14 at 22:01

1 Answers1

0

I suggest you apply an infinite impulse response (IIR) filter to smooth the camera. You can do that by...

First, declare the instance variables

CGFloat alpha;
CGFloat fSmoothY;

and then Initialize alpha and fSmoothY

// alpha should be in [0, 1], where a larger value = less smoothing
alpha = 0.5;
fSmoothY = ptPosition.y;

Lastly, apply the filter with

fSmoothY = fSmoothY * (1-alpha) + ptPosition.y * alpha;
0x141E
  • 12,613
  • 2
  • 41
  • 54
  • I tried this, but it still seems to be stuttering. It's not much different from what I was doing before, is it? – Codecat Dec 10 '14 at 10:33
  • It's the same after you added the `* 0.1` to the code in your question. Note that `didSimulatePhysics` is being called about 60 times a second. You will likely need a much smaller value for `alpha` to see any smoothing. – 0x141E Dec 10 '14 at 14:51
  • What is `self`? Is it the camera node or an `SKScene` subclass? – 0x141E Dec 13 '14 at 18:59
  • `self` in the code in my question is an object inherited from `SKSpriteNode`, representing the player. – Codecat Dec 13 '14 at 21:59
  • Are you moving the player or the camera? How are you moving the player or camera? – 0x141E Dec 15 '14 at 07:47
  • The player movement is done entirely by spritekit with the occasional velocity change so that its velocity on the X axis is always the same value. – Codecat Dec 15 '14 at 11:26
  • In Apple's [Advanced Scene Processing](https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Actions/Actions.html) example, the player is always in center of the scene and the camera moves. As the camera moves, the world is adjusted so that the camera is back in the center of the scene. – 0x141E Dec 15 '14 at 18:35