Porting Pong From Flash To C++ And SDL 2.0

The Pong Tutorial explained how to create a Pong game by using C++ pseudocode, but the implementation was done using Flash ActionScript 3. I have decided to create an actual C++ implementation using SDL 2.0. This tutorial shows some of the steps that are necessary to port the original Flash game to C++. Porting the code from ActionScript 3 to C++ is surprisingly easy.

Porting Pong From Flash To C++ And SDL 2.0

Porting Pong From Flash To C++ And SDL 2.0

Choosing A Library

Flash includes a lot of standard libraries that enable you to quickly make a game by bundling functions that deal with graphics, audio and input. C++ is a lot more bare bones. It does not automatically have support for all the necessary features on its own, but there are a lot of external libraries that we can choose that do provide these features.

I have chosen to use the library SDL 2.0. It provides all of the features that are required and allows the game to be compiled for multiple platforms.

The Porting Process

For this tutorial I have decided to create a slimmed-down version of the original Pong game. The game implements all of the interactions, collisions and AI, but does not include a menu system, a scoring system or the sound effects. These features can easily be added or ported from the original game.

Most of the code is simply copied from my original tutorial with some minor syntactical changes. We do need to implement a basic framework using SDL that allows the code to run in the new environment of a desktop application.

Setting Up The Window

We need to initialize SDL and the video subsystem, so we can use the graphics functions to draw stuff on the screen. We need to create a window that contains everything and a renderer that actually draws the things. Next, we initialize some timing variables that are used to update the game-state and calculate the frames per second.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
bool Game::Init() {
    // Initialize SDL and the video subsystem
    SDL_Init(SDL_INIT_VIDEO);
 
    // Create window
    window = SDL_CreateWindow("Pong Example - Rembound.com",
                              SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                              800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
    if (!window) {
        // Error creating window
        return false;
    }
 
    // Create renderer
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer) {
        // Error creating renderer
        return false;
    }
 
    // Initialize timing
    lasttick = SDL_GetTicks();
    fpstick = lasttick;
    fps = 0;
    framecount = 0;
 
    return true;
}

Drawing Stuff

SDL provides us functions to draw stuff on the screen. Before we draw anything ourselves, we must first clear the screen. We can now draw anything we want to the screen, but we can’t see our drawings yet. If we are done with drawing, the screen must be updated by SDL and it will present us our new image.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Game::Render(float delta) {
    // Clear the screen to black
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);
 
    // Render board and ball
    board->Render(delta);
    ball->Render(delta);
 
    // Render paddles
    for (unsigned int i=0; i<paddle.size(); i++) {
        paddle[i]->Render(delta);
    }
 
    // Update the screen
    SDL_RenderPresent(renderer);
}

Loading And Drawing Textures

In our Render function we want to draw our game-objects. SDL provides features to load textures by using an additional library: SDL_image. Here is an example of loading a PNG image file into a texture.

1
2
3
    SDL_Surface* surface = IMG_Load("ball.png");
    texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_FreeSurface(surface);

The texture can be rendered to the screen on integer positions. We define a rectangle that indicates the destination of our texture on the screen. Our Ball class uses floating point numbers for its position, so we round them to the nearest integer to smooth the motion of the ball.

1
2
3
4
5
6
7
8
void Ball::Render(float delta) {
    SDL_Rect rect;
    rect.x = (int)(x + 0.5f); // Round the float to the nearest integer
    rect.y = (int)(y + 0.5f); // Round the float to the nearest integer
    rect.w = width;
    rect.h = height;
    SDL_RenderCopy(renderer, texture, 0, &rect);
}

When the game exits, the texture needs to be cleaned.

1
    SDL_DestroyTexture(texture);

Input And Events

This is a summary of our game loop. The game gets updated and system events are handled.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    // Main loop
    while (1) {
        // Handler events
        SDL_Event e;
        if (SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT) {
                break;
            }
        }
 
        // (...)
 
        // Update and render the game
        Update(delta);
        Render(delta);
    }

The mouse position is retrieved to allow interactions.

1
2
3
    // Get the mouse position
    int mx, my;
    SDL_GetMouseState(&mx, &my);

Cleaning Up

When the game is about to exit, we need to do some cleaning up. We have to destroy the renderer and the window that we created earlier when initializing the game, to avoid memory leaks.

1
2
3
4
5
void Game::Clean() {
    // Clean renderer and window
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
}

Clean the rest of SDL.

1
    SDL_Quit();

Evaluation

The previous chapter explains all of the SDL features that are necessary to create a framework for our game. The actual game logic, the interactions between objects, the game world and the player, is mostly untouched from the original ActionScript 3 code. An explanation of the game logic can be found in The Pong Tutorial.

Download

The full source code and a Windows executable of this tutorial can be downloaded here. Included is a project file for the Code Blocks IDE. To compile the project, you need to install a compiler like MinGW and define the sdl2 global variable in the Code Blocks global variable editor. Alternatively, you can use Visual Studio Express and import the source files into a new project, followed by linking to the SDL2 and SDL2_image libraries. Details on how to compile the source code is out of the scope of this tutorial.