3
votes

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"?

1
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.LearnCocos2D
@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: i.imgur.com/xhb6ZNp.pngCodecat
@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
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.LearnCocos2D
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: stackoverflow.com/a/23978854/201863LearnCocos2D

1 Answers

0
votes

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;