Moving backgrounds, different speeds

Back when I was younger (which is an obtuse way of saying “I haven’t the friggin’ idea exactly when”), I dabbled a bit in game development. There was a period when I was studying side scroller games. Remember those? The classic Super Mario Brothers was one of them.

I also noticed that in some of the games, the backgrounds moved. Yes, backgrounds, plural. I could understand forming a background “tile” made up of hills, clouds, trees, grass, flowers, rocks and whatever suited the game as background. But there was something, else, moving in the (for lack of a better word) background.

There was another background layer, moving at a different speed. Wait. Oh, it’s moving at a slower speed.

When I moved that little sprite (that’s representing my sole means of interacting with the game) on the screen to the right, the flowers and trees and rocks sped past to the left. But that faraway mountain was moving to the left at a slower speed. And the overall effect was a realistic simulation of 3D, a semblance of depth in an essentially 2D game.

Now that I think about it, I have one question. How do you calculate how slow the other background should be? I searched high and low, though I found what this effect is called (parallax scrolling), I found no trace of any suggestion to the relative speeds between the 2 backgrounds.

So I did a little thinking. And drawing. I was trying to work out mathematically the slower speed, given the “distance” between the background layers (there’s practically no distance in implementation. Maybe 0.01 units…) and the speed of the background that’s “in front”.

It didn’t make sense, because no matter how I pivot the movement, the calculations don’t work out.

Parallax scrolling backgrounds

L1 and L2 are the “distances” between the respective layers. d1 and d2 are the distances from the objects in question to the perpendicular line formed by the sprite position. v1 and v2 are the velocities of the respective layers moving to the left (or right, depending on how you view this whole thing and how you define the direction… never mind).

The layers aren’t really separate. There is a tiny distance between the layers, say 0.01 units. If you’re in a fully 2D environment, then the farthest layer is drawn, then the next closest layer is drawn, subject to transparency to allow elements from the farthest layer to be shown, and then the playing layer is drawn (where our sprite and other objects are). There’s no distance (between the layers) to speak of in a true 2D rendering environment.

I started with the “don’t move the focus, move everything else” approach, keeping the sprite in place, and moving both backgrounds to the left. This meant pivoting around the sprite. The objects drawn on the other two layers are what our sprite would see in a straight line towards somewhere forward. Those objects should coincide at the “perpendicular” line together.

Since the distances d1 and d2 are obviously different, therefore the velocity (or speed. I’m just trying to be scientifically correct here) of the two objects moving to the left must be different. There lies my problem. It meant the farthest object had to travel faster, contradicting our original observation.

What if we pivoted around the object in the “front” layer? The sprite moves to the right, and the object on the “back” layer moves to the left, and all three line up in a perpendicular line (perpendicular to the layers anyway). Too troublesome. Same with pivoting around the farthest object.

I toyed with the idea of pivoting around the vanishing point. At this point (no pun intended), I decided to give up.

So I assumed that the background image(s) in the “back” layer are appropriately sized with respect to the “front” layer. I decided a simple ratio probably worked best. Thus we have
v2 = v1 / (L1 + L2)
which should give an appropriately slowed velocity.

And now, finally, I’m telling you this. It might not matter. What matters is that you test the velocities, and if the 2 background layers scroll at a pleasing velocity, then there you have it. Ultimately, we’re just trying to simulate a 3D perspective given a 2D environment. If it’s believable, then that’s the correct velocity.