Efficient Parallax Scrolling

What's the most efficient way to implement parallax scrolling using multiple image layers?

Implementing efficient parallax scrolling with multiple image layers in SDL2 involves carefully managing image rendering and movement. Here's an approach that balances performance and visual quality:

Parallax Layer Class

First, let's create a ParallaxLayer class to manage each layer:

#include <SDL.h>
#include <string>
#include <vector>

class ParallaxLayer {
public:
  ParallaxLayer(SDL_Renderer* renderer,
                const std::string& imagePath,
                float scrollSpeed)
    : ScrollSpeed{scrollSpeed}, Offset{0} {
    SDL_Surface* surface = SDL_LoadBMP(
      imagePath.c_str());
    Texture = SDL_CreateTextureFromSurface(
      renderer, surface);
    SDL_FreeSurface(surface);
    SDL_QueryTexture(Texture, nullptr, nullptr,
                     &Width, &Height);
  }

  void Update(float deltaTime) {
    Offset += ScrollSpeed * deltaTime;
    if (Offset > Width) Offset -= Width;
    if (Offset < 0) Offset += Width;
  }

  void Render(SDL_Renderer* renderer,
              int screenWidth,
              int screenHeight) {
    int x = static_cast<int>(-Offset);
    while (x < screenWidth) {
      SDL_Rect destRect{
        x, 0, Width, screenHeight};
      SDL_RenderCopy(renderer, Texture, nullptr,
                     &destRect);
      x += Width;
    }
  }

  ~ParallaxLayer() {
    SDL_DestroyTexture(Texture);
  }

private:
  SDL_Texture* Texture;
  int Width, Height;
  float ScrollSpeed;
  float Offset;
};

Main Implementation

Now, let's use this class to create a parallax effect:

#include <SDL.h>

#include <chrono>
#include <vector>

int main(int argc, char* argv[]) {
  SDL_Init(SDL_INIT_VIDEO);
  SDL_Window* window =
    SDL_CreateWindow("Parallax Scrolling",
                     SDL_WINDOWPOS_UNDEFINED,
                     SDL_WINDOWPOS_UNDEFINED,
                     800, 600, 0);
  SDL_Renderer* renderer =
    SDL_CreateRenderer(window, -1,
                       SDL_RENDERER_ACCELERATED);

  std::vector<ParallaxLayer> layers;
  layers.emplace_back(renderer,
                      "background.bmp", 10);
  layers.emplace_back(renderer, "midground.bmp",
                      30);
  layers.emplace_back(renderer,
                      "foreground.bmp", 60);

  bool quit = false;
  SDL_Event e;
  auto lastTime =
    std::chrono::high_resolution_clock::now();

  while (!quit) {
    while (SDL_PollEvent(&e) != 0) {
      if (e.type == SDL_QUIT) quit = true;
    }

    auto currentTime =
      std::chrono::high_resolution_clock::now();
    float deltaTime =
      std::chrono::duration<float>(
        currentTime - lastTime).count();
    lastTime = currentTime;

    for (auto& layer : layers) {
      layer.Update(deltaTime);
    }

    SDL_SetRenderDrawColor(renderer, 0, 0, 0,
                           255);
    SDL_RenderClear(renderer);

    for (auto& layer : layers) {
      layer.Render(renderer, 800, 600);
    }

    SDL_RenderPresent(renderer);
  }

  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(window);
  SDL_Quit();
  return 0;
}

This implementation is efficient because:

  1. It uses SDL's hardware-accelerated rendering with SDL_Renderer and SDL_Texture.
  2. Each layer is rendered only twice at most per frame, regardless of scroll speed.
  3. The Update() method uses time-based movement, ensuring smooth scrolling on different devices.

To further optimize:

  • Use spritesheets to reduce texture switches.
  • Implement view culling to skip rendering off-screen layers.
  • For very large backgrounds, consider using tiled maps instead of large images.

Remember, the key to efficient parallax scrolling is minimizing draw calls and texture switches while maintaining the illusion of depth and movement.

Loading and Displaying Images

Learn how to load, display, and optimize image rendering in your applications

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Implementing Scrolling Backgrounds
How do I implement scrolling backgrounds using image blitting?
Efficient Rendering of Multiple Images
What's the most efficient way to render multiple copies of the same image?
Image Tiling for Game Maps
How can I implement image tiling for creating large game maps?
Handling Different Image Resolutions
How do I handle different image resolutions for various screen sizes?
Implementing Image Zoom
How can I implement zooming functionality for images?
Or Ask your Own Question
Purchase the course to ask your own questions