I've created a little 2D game engine with parallax scrolling and something has been bugging me for some time.
Layers / objects set at a different depths / z orders don't preserve their position relative to each other. The position of each layer after substaintial camera movement seems to decay and become inaccurate over time.
I have 3 layers / objects, each set at a different Z co-ordinate / layer depth. The higher the Z co-ordinate, the slower the layer moves; basically the more distant the layer is to the camera. Each layer being 1 level deeper than the next. For example:
layer1.z = 4; layer2.z = 3; layer3.z = 2;
Then, when rendering out all the layer positions every update. I use the following algorithm; let's use the first layer as an example:
layer1.x += (layer1.moveX -= cameraTarget.moveX) / layer1.moveZ;
moveX being the layer's / object's potentional movement modifier. So this should take into account not only the cameras movement, but the layers movement (if any) as well. This should allow dynamic bodies to work within the parallax scrolling paradigm.
For simplicities sake, even if I assume there are no dynamic bodies and just want to render background elements, I can simplify the above and do this instead:
layer1.x += (cameraTarget.moveX / layer1.moveZ) * -1;
I ASSUME this is the very core and basic math to doing parallax scrolling. Yet if I move the camera around enough, each layer seems to slightly offeset more and more. To test this, I even created a grid-like puzzle that fits together when all 3 layers match. It starts matching by default, and matches fine during the first initial movements, but after signifcant movements, it is unable to match perfectly again. Basically by moving the camera and tweaking it's position, I can't get the puzzle to match.
What am I doing wrong? I would think if everything passes through this algorithm, it should at least be consistant. Well, in saying that, to a casual observer it looks great, but on closer scrutiny it's flawed (I think). Is parallax scrolling natually decaying / desctructive to objects relational postioning to each other?
I am using Flash / ActionScript 3.0. One possibility I thought of was perhaps Flash's renderer could be doing something funky to my calculations when I assign these numbers to the x and y property of a DisplayObject. I've tried rounding too, in some naive attempt to make it more precise and perhaps have movement only to 1 sub-pixel.
My current setup is this, I have 3 layers, each of equal dimension layed out on the stage. So that at the start, the layers are where I want them, but they must just respond to camera movements.
layer1.z = 4; layer1.x = 80; layer1.y = 60; layer2.z = 3; layer2.x = 80; layer2.y = 60; layer2.z = 2; layer2.x = 80; layer2.y = 60; // Place the player at the center of the screen, the camera directly follows / mimics the player's position player.x = (stage.stageWidth / 2) - (player.width / 2); player.y = (stage.stageHeight / 2) - (player.height / 2);
Then, in my render function that updates every frame:
// Capture camera movement camera.x += cameraTarget.moveX; // cameraTarget being the player camera.y += cameraTarget.moveY; // Move all the layers layer1.x = (camera.x + layer1.x) / layer1.moveZ; layer1.y = (camera.y + layer1.y) / layer1.moveZ; layer2.x = (camera.x + layer2.x) / layer2.moveZ; layer2.y = (camera.y + layer2.y) / layer2.moveZ; layer3.x = (camera.x + layer3.x) / layer3.moveZ; layer3.y = (camera.y + layer3.y) / layer3.moveZ;
I've removed a few things my code has that would just confuse matters, but this is essentially what it does. For example, I have a loop that loops through an array of layers and then applies the transforms. Here, I'm only hardcoding it.
I also was using a Matrix to capture the rotation, scale etc... of the cameraTarget, which was nice.