Recently I made some changes to my parallax scrolling implementation for SpriteKit. In some settings, there was a noticeable flickering effect on the slowest layer of backgrounds. After some research, I found out that there was a cumulative error when reseting the position of the backgrounds that went out of screen that will, on the long run, cause them to fall out of sync. The problem is due to the nature of the C float number representation. This has been discussed in depth a lot [1][2][3], so I am not discussing it here again.

Because of this issue, there could be a situation where the two backgrounds forming a layer in the Parallax Scrolling would fall apart from each other, little by little, until reaching a noticeable sub-pixel length (less than a pixel, but close enough to create a flickering effect). The problem was aggravated by the fact that I was resetting each background according to its own position (i.e: go back two full lengths to get again to the starting point) instead of relative to the other background (i.e: go back one full length from the position of the other showing background), because if calculation were correct and representation was exact, the relative positions of the two backgrounds would be adjusted.

parallaxFlickering

For testing purposes, I set up a parallax scrolling with three layers, at initial speed of 2 and a differential of 0,5 (so speeds should be ‘2’, ‘1’ and ‘0,5). Here is a description of the layers of the parallax backgrounds as they were progressively falling apart:

Parallax background state:
Layer 0: background1 at (-146.000000, 0.000000), background2 at (878.000000, 0.000000), speed: 2.000000
Layer 1: background1 at (-76.842140, 0.000000), background2 at (947.159302, 0.000000), speed: 1.052632
Layer 2: background1 at (-40.443199, 0.000000), background2 at (983.556824, 0.000000), speed: 0.554017

Parallax background state:
Layer 0: background1 at (-120.049988, 0.000000), background2 at (903.900024, 0.000000), speed: 2.000000
Layer 1: background1 at (906.906433, 0.000000), background2 at (-117.045891, 0.000000), speed: 1.052632
Layer 2: background1 at (-600.553528, 0.000000), background2 at (423.446533, 0.000000), speed: 0.554017

Parallax background state:
Layer 0: background1 at (-602.049988, 0.000000), background2 at (421.900024, 0.000000), speed: 2.000000
Layer 1: background1 at (653.226868, 0.000000), background2 at (-370.730865, 0.000000), speed: 1.052632
Layer 2: background1 at (-734.071411, 0.000000), background2 at (289.928650, 0.000000), speed: 0.554017

Notice how the speeds (‘2.0000000’, ‘1.052632’, ‘0.554017’) don’t actually represent the exact values we were supposed to be applying to our layers,and what’s even worse, when adding or subtracting these speeds, the backgrounds’ positions would suffer a similar effect. This, after too much calculations, would cause them to get out of sync.

So let’s stop the flickering. For that, I decided first to round the speeds to two decimal places. This would have the effect of stabilizing the speeds. Then, I re-calculated the position of the backgrounds that need to be reset (when they get out of the screen) so their new position depends on the position and length of the background that is currently showing (the one that now is covering all the screen). Last, I added a overlap correction to the backgrounds, so the new background gets placed slightly overlapping the previous one. This overlap is less than a pixel (actually, tests showed me that nice values are among 0.05 and 0.25), so would not cause an effect on the drawing of the backgrounds, but would help glueing them together.

Parallax background state:
Layer 0: background1 at (-562.000000, 0.000000), background2 at (462.000000, 0.000000), speed: 2.000000
Layer 1: background1 at (-295.050079, 0.000000), background2 at (728.953430, 0.000000), speed: 1.050000
Layer 2: background1 at (-154.550430, 0.000000), background2 at (869.453430, 0.000000), speed: 0.550000

Parallax background state:
Layer 0: background1 at (-456.149963, 0.000000), background2 at (567.800049, 0.000000), speed: 2.000000
Layer 1: background1 at (-341.832764, 0.000000), background2 at (682.120728, 0.000000), speed: 1.050000
Layer 2: background1 at (796.171082, 0.000000), background2 at (-227.784805, 0.000000), speed: 0.550000

Parallax background state:
Layer 0: background1 at (27.650085, 0.000000), background2 at (-996.299927, 0.000000), speed: 2.000000
Layer 1: background1 at (-190.216797, 0.000000), background2 at (833.735779, 0.000000), speed: 1.050000
Layer 2: background1 at (-197.118607, 0.000000), background2 at (826.836426, 0.000000), speed: 0.550000

With these corrections, the flickering is gone, although I have noticed that for optimal representation, you must experiment with different values of speed and speed differential in Parallax Scrolling, as the number of layers and the speed and differential you choose have a direct impact in the cumulative calculations.

Apart from that fix, I have added a cool reverse scrolling effect in the Parallax Scrolling, so you can just reverse the direction of the parallax scrolling movement, and I think that’s pretty interesting for a game.