Parallax background

When travelling by train, mountains in the distance seem to be static, but trees and grass next to the track move very fast. In 2D games, a similar effect is simulated by a parallax background. It adds a feeling of depth to the game. A parallax background contains a few layers. The player is usually in the front, but there can be a layer in front of the player as well. This simulates objects that are closer to the camera.

When the camera moves, the layers in the back are scrolled slowly and the layers in front are scrolled faster; the same as in our train example.

In platformers, we often use a static background with a few parallax layers. It's a good idea to make the background less prominent and less distracting, but nevertheless beautiful. Some of the layers can move automatically; for example, clouds can move even though the camera is static.

Here's a typical example of a parallax background: a blue sky and a sun as a background, clouds that can move a little, slow scrolling mountains, and fast scrolling grass. The background layers are typically seamlessly wrapped around.

Parallax background

AndEngine offers a horizontal parallax background. It can have an arbitrary number of layers that can move in different speeds. However, we need a vertical parallax background for our game. We will have to create our own class. However, the use of our class is exactly the same as the original parallax background.

VerticalParallaxEntity

In the following example, we will explain how the parallax background with the entities works. To begin, we are going to extend a ParallaxEntity class:

public class VerticalParallaxEntity extends ParallaxEntity {
  
  IEntity entity;
  float parallaxFactor;

  public VerticalParallaxEntity(float parallaxFactor, IEntity entity) {
    super(parallaxFactor, entity);
    this.entity = entity;
    this.parallaxFactor = parallaxFactor;
  }
  
  public void onDraw(final GLState pGLState, final Camera pCamera, final float pParallaxValue) {
    pGLState.pushModelViewGLMatrix();
    {
      final float cameraHeight = pCamera.getHeight();
      final float entityHeightScaled = entity.getHeight() * entity.getScaleY();
      float baseOffset = (pParallaxValue * parallaxFactor) % entityHeightScaled;

      while (baseOffset > 0) {
        baseOffset -= entityHeightScaled;
      }
      pGLState.translateModelViewGLMatrixf(0, baseOffset, 0);

      float currentMaxY = baseOffset;

      do {
        entity.onDraw(pGLState, pCamera);
        pGLState.translateModelViewGLMatrixf(0, entityHeightScaled, 0);
        currentMaxY += entityHeightScaled;
      } while (currentMaxY < cameraHeight);
    }
    pGLState.popModelViewGLMatrix();
  }  
}

The code for the layer might seem a bit intimidating. It deals with low-level OpenGL calls. The highlighted code is the most important part. The onDraw() method first measures the camera height and the real height of the entity. Then there are two float numbers: parallax value and parallax factor. The value says how much the camera moved. It can be an arbitrary number and we will be passing the camera's y coordinate. The factor determines how much should the entity (layer) move.

We are setting the factor at the beginning when we create this entity. In our case, a positive number means scrolling the layer in the same direction as the camera and negative number scrolls it in the opposite way. Zero would mean a static layer. The higher the absolute number, the faster the scroll speed. So, in our case, we need numbers between 0 and -1.

Creating a parallax background

The code that creates the background belongs to the GameScene class. It replaces our old static background. First, let's add a method to create it:

  private void createParallaxBackground() {
    parallaxBackground = new ParallaxBackground(0.82f, 0.96f, 0.97f);
    
    // layer in the back
    Entity clouds = new Entity();
    clouds.setSize(480, 800);
    clouds.setAnchorCenter(0, 0);
    Sprite cloud1 = new Sprite(200, 300, res.cloud1TextureRegion, vbom);
    Sprite cloud2 = new Sprite(300, 600, res.cloud2TextureRegion, vbom);
    clouds.attachChild(cloud1);
    clouds.attachChild(cloud2);
    
    VerticalParallaxEntity cloudsLayer = new VerticalParallaxEntity(-0.1f, clouds);
    parallaxBackground.attachParallaxEntity(cloudsLayer);

    //layer in front
    Entity platforms = new Entity();
    platforms.setSize(480, 800);
    platforms.setAnchorCenter(0, 0);
    Sprite platform1 = new Sprite(150, 200, res.platformTextureRegion, vbom);
    platform1.setColor(0.3f, 0.3f, 0.3f, 0.3f);
    platform1.setScale(0.8f);
    Sprite platform2 = new Sprite(250, 550, res.platformTextureRegion, vbom);
    platform2.setColor(0.3f, 0.3f, 0.3f, 0.3f);
    platform2.setScale(0.8f);
    Sprite platform3 = new Sprite(350, 450, res.platformTextureRegion, vbom);
    platform3.setColor(0.3f, 0.3f, 0.3f, 0.3f);
    platform3.setScale(0.8f);
    platforms.attachChild(platform1);
    platforms.attachChild(platform2);    
    platforms.attachChild(platform3);
    
    VerticalParallaxEntity platformsLayer = new VerticalParallaxEntity(-0.5f, platforms);
    parallaxBackground.attachParallaxEntity(platformsLayer);
    
    setBackground(parallaxBackground);
}

Our background has two layers. Each layer can be a single image (a sprite) or an entity assembled from multiple objects. We are doing the latter. The first layer is a very slow moving layer with two clouds. We also set the size of the entity and its center, because the parallax background needs to know the size to correctly wrap around the layer. The second layer is assembled from three semi-transparent and scaled-down platforms. They will appear as if they are in the background and we will make them move a bit slower than the camera.

We must also change the populate() method to use this background:

  private ParallaxBackground parallaxBackground;
  
  @Override
  public void populate() { 
//    createBackground();
    createParallaxBackground();
    createPlayer();
…
}

And finally, we must be passing the parallax value to the background in each update cycle to make it scroll properly:

@Override
protected void onManagedUpdate(float pSecondsElapsed) {
  super.onManagedUpdate(pSecondsElapsed);  
  parallaxBackground.setParallaxValue(camera.getCenterY());
    
  boolean added = false;
…
}

The final effect is that the clouds move very slowly and the platforms in the back move a bit faster but still slower than the platforms that the player can use. In the following screenshot, we can see how the platforms are wrapped (the top background platform is visible both on top and the bottom):

Creating a parallax background
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.214.27