Game Development Community

Parallax Scrolling

by Michael Cordner · in Torque Game Builder · 09/07/2005 (2:30 am) · 3 replies

Hello everyone,

I've been busy the past couple of months working on our game, and I've come up against an interesting problem around parallax scrolling. This is not an engine or scripting problem or a request for someone to explain parallax scrolling, :) I was just wondering if anyone has done anything similar.

I have a three screen wide area, (from 150 to 150, 100x75 each) with a character that walks from either extreme to the other. The screen scrolls to keep up with the character, the 'scrolling' being the result of having the camera attached to the main character (with a bit of physics applied for a 'delay' effect,). The camera limit is set to half a screen width at either end of the area, (so that the camera doesn't scroll off the area at the extremes, so the character, rather than the screen moves once he's reached a certain point.) Standard fare at this point.

Next, I add more layers to the map. Each area is composed of three tile layers, the main layer being the area the camera is scrolling around. There is a foreground layer, which should scroll by faster than the main layer, and a background layer, which should scroll only a little ways in either direction as the character moves from extreme to extreme.

My problem at this point is that I can't think of any obvious way to reconcile scrolling of the foreground and background layers with the movement of the camera. In this setup, the layer itself isn't moving at all, rather the camera is scrolling across a stationary image. However, in order to get the parallax effect, it would be necessary to move these layers, and somehow have them moving at some sort of inverse to the camera position.

The only think I can think of is to check the position of the camera every frame, and do some sort of calculation to correctly position the background and foreground layers, but this isn't really a preferred way of doing things in T2D. Has anyone come up against a similar issue and managed to find an elegant solution?

Thanks!

#1
09/07/2005 (2:38 am)
Off the top of my head, I can't recall if you can getLinearVelocity for the camera/sceneWindow2D, but if you can, you can probably just plug that value+multipliers into the background/foreground layers' linearVelocity. If not, you can getLinearVelocity of the player sprite and use that, taking into account the camera lag.
#2
09/07/2005 (7:06 pm)
@michael- However am curious if you are using fxScroller2D, or if you are using tile maps exclusively? I thought fxScroller2D was the typical way to setup parallax scrolling. Maybe you could put fxScroller2Ds into the scene in addition to your tile map?
#3
09/08/2005 (1:36 am)
@Alex - No, tilemaps exclusively. I had started experimenting with the fxScroller2D, but I found it was a bit limited for my purposes (and buggy under directX, though I imagine that will be addressed at some point). I think they work pretty much the same way, all you need to do is grab each layer from the tile map and scroll them around as you like.

Also, if you have large repetitive areas (say a background sky layer, for instance,) you can repeat the same tile multiple times rather than having to hold a complete background image in memory for that layer. If I want to do something like a sky that fades into night and back (which I do!), it means I only need to create one tile's worth of animation (at a fraction of the memory usage) rather than an entire screen's worth. At least, this is the theory.

What I've ended up doing for the parallax scrolling is using onSceneUpdate() each and every frame to get the current position of the camera and adjusting the foreground and background layers accordingly. Then, I centre those layers on the camera position and apply a parallax multiplier to each layer and adjust to get them moving faster or slower. It looks like this (rough code):

function Room::updateParallaxLayers(%this){
    %cameraPosition=sceneWindow2D.getCurrentCameraPosition();
    %cameraPositionX=getWord(%cameraPosition,0);
    
    %backParallaxFactor=0.8; //moves the background more slowly than the centre
    %frontParallaxFactor=-0.4; //moves the foreground more quickly than the
    
    //Camera is bound between -100 and 100 in the scene, so if the camera
    //goes outside those bounds, no layers move

    if (%cameraPositionX>=-100&&%cameraPositionX<=100) {
        //position each layer as the camera moves
        %this.backLayer.setPosition(%cameraPositionX*%backParallaxFactor@" 0");
        %this.frontLayer.setPosition(%cameraPositionX*%frontParallaxFactor@" 0");
    } else {
        //Anchor each layer 
        if (%cameraPositionX<-100){
            %this.backLayer.setPosition(-100*%backParallaxFactor@" 0");
            %this.frontLayer.setPosition(-100*%frontParallaxFactor@" 0");
        }
        if (%cameraPositionX>100){
            %this.backLayer.setPosition(100*%backParallaxFactor@" 0");
            %this.frontLayer.setPosition(100*%frontParallaxFactor@" 0");
        }
    }
}

This is called every frame via OnSceneUpdate();