Glusoft

How to Create a 2D Camera System in SDL3

2D Camera System in SDL3

The basic structs

In this tutorial we will use helper structs for the camera and the player:

struct Vec2 {
    float x, y;
};

struct Camera {
    Vec2 position;
    int width, height;
};

struct Player {
    SDL_FRect rect;
    float speed;
};

Initilizations

Window resizable

We can also make the windows resizable with SDL_WINDOW_RESIZABLE :

SDL_Window* window = SDL_CreateWindow("SDL3 Camera Demo", 800, 600, SDL_WINDOW_RESIZABLE);
if (!window) {
    SDL_Log("Failed to create window: %s", SDL_GetError());
    SDL_Quit();
    return 1;
}

Load the background

SDL_Surface *bg = IMG_Load("bg.png");
SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, bg);
SDL_DestroySurface(bg);

For this example I will use the background of the pokemon world: bg.png

The world constants

const int WORLD_WIDTH = tex->w;
const int WORLD_HEIGHT = tex->h;

The player

Player player = { {100, 100, 32, 32}, 300.0f };

The camera

Camera camera = { {0, 0}, 800, 600 };

The main loop

The frame delta time

Uint64 currentTime = SDL_GetTicks();
float delta = (currentTime - lastTime) / 1000.0f;
lastTime = currentTime;

The event loop

while (SDL_PollEvent(&e)) {
    if (e.type == SDL_EVENT_QUIT)
        running = false;
    if (e.type == SDL_EVENT_WINDOW_RESIZED) {
        SDL_GetWindowSize(window, &camera.width, &camera.height);
    }
}

Player

Move the player

We also need to use the keyboard for the player movement:

const bool* keys = SDL_GetKeyboardState(NULL);
if (keys[SDL_SCANCODE_W]) player.rect.y -= player.speed * delta;
if (keys[SDL_SCANCODE_S]) player.rect.y += player.speed * delta;
if (keys[SDL_SCANCODE_A]) player.rect.x -= player.speed * delta;
if (keys[SDL_SCANCODE_D]) player.rect.x += player.speed * delta;

World bound

The player cannot move outside the world:

if (player.rect.x < 0) player.rect.x = 0;
if (player.rect.y < 0) player.rect.y = 0;
if (player.rect.x + player.rect.w > WORLD_WIDTH) player.rect.x = WORLD_WIDTH - player.rect.w;
if (player.rect.y + player.rect.h > WORLD_HEIGHT) player.rect.y = WORLD_HEIGHT - player.rect.h;

The Camera

We update the camera position to the center of the player:

camera.position.x = player.rect.x + player.rect.w / 2 - camera.width / 2;
camera.position.y = player.rect.y + player.rect.h / 2 - camera.height / 2;

World bound

if (camera.position.x < 0) camera.position.x = 0;
if (camera.position.y < 0) camera.position.y = 0;
if (camera.position.x + camera.width > WORLD_WIDTH)
    camera.position.x = WORLD_WIDTH - camera.width;
if (camera.position.y + camera.height > WORLD_HEIGHT)
    camera.position.y = WORLD_HEIGHT - camera.height;

The rendering

The world

SDL_FRect worldBounds = {
    -camera.position.x,
    -camera.position.y,
    (float)WORLD_WIDTH,
    (float)WORLD_HEIGHT
};
SDL_RenderTexture(renderer, tex, NULL, &worldBounds);

The player

SDL_FRect screenPlayer = {
    player.rect.x - camera.position.x,
    player.rect.y - camera.position.y,
    player.rect.w,
    player.rect.h
};
SDL_SetRenderDrawColor(renderer, 200, 50, 50, 255);
SDL_RenderFillRect(renderer, &screenPlayer);

Full project : How to Create a 2D Camera System in SDL3

You can download the full project:

Need another OS ? => Windows, Mac, Linux