Make Your Own Sideways Scroller: Part 3 - Moving the Ground


(Simon) #1

The code described in these lessons can be found at https://github.com/filmote/Steve


" I understand how the engines work now. It came to me in a dream. The engines don’t move the ship at all. The ship stays where it is and the engines move the universe around it."
Cubert Farnsworth

Moving the Ground

The illusion of movement in an endless runner is important to game play. To provide a little variety, I have designed three separate graphics which include flat land, a bump and a pot-hole. The variations are irrelevant to the game play.

0013 0014 0015

These are enumerated in an enum called GroundType, as shown below. The first element in an enumeration is implicitly assigned a value of zero and subsequent elements increase in value by one. An array of images has also been declared with the images arranged in the same order as the enumeration allowing us to use the enumeration elements as index values to retrieve the images.

enum GroundType {
  Flat,
  Bump,
  Hole,
};

const byte *ground_images[] = { ground_flat, ground_bump, ground_hole };

The ‘ground’ itself is made up of five images that are 32 pixels wide to give a combined width of 160 pixels. As you will see in a moment, the array of images will be rendered across the page overlapping the 128 pixels of the screen width. Moving the images a pixel to the left and re-rendering them will provide the illusion that the ground is moving.

The array is declared and initialised as shown below:

GroundType ground[5] = {
  GroundType::Flat,
  GroundType::Flat,
  GroundType::Hole,
  GroundType::Flat,
  GroundType::Flat,
};

When rendering the ground for the first time, the first four images are rendered at X position 0, 32, 64 and 96 respectively. The fifth image is also rendered but as its X position is 128 it is not visible off to the right of the screen.

The following code renders the ground. It loops through the ground array and draws the five elements 32 pixels apart.

for (byte i = 0; i < 5; i++) {
  
  Sprites::drawSelfMasked((i * 32) - groundX, GROUND_LEVEL, ground_images[ground[i]], frame);   

}

In the code above, the variable groundX is used as an offset and is initially set to zero so has no affect. To scroll the ground to the left, the ground variable is incremented. Assuming the value is now one, this results in the five images being rendered at X positions -1, 31, 63, 95, and 127 respectively. The left most pixels of the first image are no longer visible and the left most pixels of the right are now rendered on the right most side of the screen.

The ground can be continued to be scrolled until the offset equals 32 (our image width) at which point the images are being rendered at the X positions -32, 0, 32, 64 and 96 respectively. At this point the first image is completely off screen. At this point, we need to move the elements of the ground array to the left one position and randomly select an image for the fifth position.

The code below detects when the offset has reached the 32 and randomly selects a number between 0 and 5 and assigns the ground type accordingly. One thing to note about the random() function is that the lower bound is inclusive whereas the upper bound is inclusive. A value of 3 or lower results in a flat section of ground whereas the values 4 and 5 are mapped to a bump and a pothole. This approach ensures that many more flat sections of ground are generated.

Finally, the elements of the array are shuffled to the left and the newly generated ground type is assigned to the fifth element.

if (groundX == 32) {
        
  groundX = 0;

  byte type = random(0, 6);

  switch (type) {

    case 0 ... 3:
      type = GroundType::Flat;
      break;

    case 4:
      type = GroundType::Bump;
      break;

    case 5:
      type = GroundType::Hole;
      break;
    
  }

  ground[0] = ground[1];
  ground[1] = ground[2];
  ground[2] = ground[3];
  ground[3] = ground[4];
  ground[4] = (GroundType)type;

}

groundX++;

The code described in these lessons can be found at https://github.com/filmote/Steve

Prev Article > Make Your Own Sideways Scroller: Part 2 - Prerequisite Concepts
Next Article > Make Your Own Sideways Scroller: Part 4 - Moving and Rendering Steve


Make Your Own Sideways Scroller: Part 4 - Moving and Rendering Steve