Subscribe to gabehabe's on-topic ramblings        RSS Feed
-----

Getting the code written: Pong

Icon 2 Comments
Rather than adding stupid and pointless explanations about things that don't need explaining, I'm gonna ask you all for comments. Anything that needs clarification, I'll reply :)

I'm going to split the game across several files:
classes.h & classes.cpp
functions.h & functions.cpp
modes.h & modes.cpp
and of course, main.cpp

Writing the classes
The header file, used to declare our classes:
#ifndef CLASSES_INCLUDED_H
#define CLASSES_INCLUDED_H

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

const int SCREEN_WIDTH  = 640; /* Variable to store the screen width */
const int SCREEN_HEIGHT = 480; /* Variable to store the screen height */
const int SCREEN_DEPTH  =  32; /* Variable to store the screen depth */

class CPaddle
{
    public:
        SDL_Event event; /* This is how we will handle our key events */
        SDL_Surface *surface; /* The left paddle */
        SDL_Rect offset; /* The target area for the left paddle */

        CPaddle (int x);
};

class CBall
{
    public:
        SDL_Rect offset; /* Target area for the ball */
        SDL_Surface *surface; /* The surface on which we will load our ball */
        int xVel, yVel; /* The direction of which our ball will move (this is implemented later) */
        CBall ();
};

#endif

The cpp file, used to implement our classes:
#include "classes.h"
#include "functions.h"
#include <ctime> // time ()
#include <cstdlib> // rand ()

CPaddle::CPaddle (int x) /* Our constructor, we need to initialise all our paddle here */
{ /* We pass x so that we know whether to create our paddle on the left or right of the screen */
    /* Load the image file for the paddle (jpg format) */
    this->surface  = load_image ("img/paddle.jpg");
    /* Set where we want our rectangle to be */
    this->offset.x = x; /* Position on the x axis */
    this->offset.y = 190; /* Position on the y axis (start in the middle) */
    this->offset.w = 10;
    this->offset.h = 100;
}

CBall::CBall () /* Constructor, used to set various values, like start position and the surface image */
{
    srand (time(NULL)); /* this will only be seeded once, since we only need one ball anyway */
    this->offset.x = rand () % (SCREEN_WIDTH - (SCREEN_WIDTH / 2));
    this->offset.y = rand () % SCREEN_HEIGHT;
    this->offset.w = 10;
    this->offset.h = 10;
    this->surface = load_image ("img/ball.jpg");
    this->xVel = 1;
    this->yVel = rand () % 2;
    if (this->yVel == 0)
        this->yVel = -1;
}


Writing the functions
The header file, used to declare our functions:
#ifndef FUNCTIONS_INCLUDED_H
#define FUNCTIONS_INCLUDED_H

#include <SDL/SDL.h>
#include "classes.h"

SDL_Surface *load_image (char* filename);

void apply_surface (int x, int y, SDL_Surface *source, SDL_Surface *destination);

void update (SDL_Surface *screen, CPaddle p, CPaddle p2, CBall ball);

void move (CPaddle &p, CPaddle &p2, CBall &ball);

void Quit_Game (SDL_Surface *screen);

#endif

The cpp file, used to implement our functions:
#include "functions.h"
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

SDL_Surface *load_image (char* filename)
{
    SDL_Surface *loaded    = NULL; /* Create a basic surface */
    SDL_Surface *optimised = NULL; /* Create an optimised surface */
    loaded = IMG_Load (filename); /* Load the basic surface */
    if (loaded != NULL) /* If it was loaded successfully */
    {
        optimised = SDL_DisplayFormat (loaded); /* Optimise it */
        SDL_FreeSurface (loaded); /* Free the temp one */
    }
    return optimised; /* Return the optimised surface */
}

void apply_surface (int x, int y, SDL_Surface *source, SDL_Surface *destination)
{
    SDL_Rect offset; /* The target area to update */
    offset.x = x;
    offset.y = y;
    /* Blit the surfaces (make it appear correctly */
    SDL_BlitSurface (source, NULL, destination, &offset);
}

void update (SDL_Surface *screen, CPaddle p, CPaddle p2, CBall ball)
{
    /* Fill the screen with a black rectangle (prevents having loads of crap everywhere */
    SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0x00, 0x00, 0x00));
    /* Apply the surfaces to the screen */
    apply_surface(p.offset.x, p.offset.y, p.surface, screen);
    apply_surface(p2.offset.x, p2.offset.y, p2.surface, screen);
    apply_surface(ball.offset.x, ball.offset.y, ball.surface, screen);
    /* Flip the screen (aka double buffering */
    SDL_Flip (screen);
}

void move (CPaddle &p, CPaddle &p2, CBall &ball)
{
    /// now we need to move the ball
    ball.offset.x += ball.xVel; /* Move the ball */
    ball.offset.y += ball.yVel;
    /* If the ball has collided with the bottom of the screen */
    if ((ball.offset.y+ball.offset.h) == SCREEN_HEIGHT)
        ball.yVel = -1; /* Reverse the y velocity (move up instead of down) */
    if (ball.offset.y == 0) /* If the ball has collided with the top of the screen */
        ball.yVel = 1; /* Reverse the y velocity (move down) */

    if ((ball.offset.x+ball.offset.w) == p2.offset.x /* If the ball has collided with the right paddle */
        && (ball.offset.y < p2.offset.y+p2.offset.h)
        && (ball.offset.y > p2.offset.y)) /* Checks to see if it collided between the y coordinates of the paddle */
        ball.xVel = -1; /* Reverse x */

    if ((ball.offset.x == (p.offset.x+p.offset.w)) /* Similar checks, used to check if */
        && (ball.offset.y < p.offset.y+p.offset.h) /* The ball has collided with the */
        && (ball.offset.y > p.offset.y)) /* Paddle on the left of the screen */
        ball.xVel = 1; /* Reverse x */

    SDL_Delay (2); /* Delay the movement a little (slows down the ball) */

}

void Quit_Game (SDL_Surface *screen)
{
    SDL_Surface *bg = NULL;
    SDL_Event e;
    bg = load_image ("img/game_over.jpg");
    /* Apply the image */
    apply_surface (0, 0, bg, screen);
    /* Update the screen */
    SDL_Flip (screen);
    while (true) /* Check for an event */
        if (SDL_PollEvent (&e)){
            if (e.type == SDL_QUIT)
                return; /* If the cross has been pressed, quit */
            if (e.type == SDL_KEYDOWN)
                switch (e.key.keysym.sym)
                    default:
                        return;

        }
}


Writing the modes
The header file, used to declare our modes:
#ifndef MODES_H_INCLUDED
#define MODES_H_INCLUDED

#include "classes.h"
#include "functions.h"

void _1p (SDL_Surface *screen);

void p1vai (SDL_Surface *screen);

#endif // MODES_H_INCLUDED

The cpp file, in which our modes are implemented:
#include "modes.h"
#include "classes.h"
#include <SDL/SDL.h>

void _1p (SDL_Surface *screen)
{
    Uint8 startclock = SDL_GetTicks ();
    CPaddle p1_1 (20); /* The player's paddles */
    CPaddle p1_2 (SCREEN_WIDTH - 30);
    CBall ball; /* The ball */

    while (true)
    {
        if ((SDL_GetTicks() - startclock) % 2 == 0)
        {
            /* Update the screen */
            update (screen, p1_1, p1_2, ball);
            /* game loop, code for moving the paddle goes here: */
            /* While there is an event to be handled */
            if (SDL_PollEvent (&p1_1.event))
            {
                if (p1_1.event.type == SDL_QUIT)
                    SDL_Quit (); /* Quit if the cross is clicked */
                if (p1_1.event.type == SDL_KEYDOWN)
                { /* If a key has been pressed */
                    switch (p1_1.event.key.keysym.sym)
                    {
                        case SDLK_UP: /* Alter the coordinates if up is pressed */
                            p1_1.offset.y -= 10;
                            if (p1_1.offset.y < 0)
                                p1_1.offset.y = 0;

                            p1_2.offset.y += 10;
                            if (p1_2.offset.y > 380)
                                p1_2.offset.y = 380;
                            break;
                        case SDLK_DOWN: /* Alter the coordinates if down is pressed */
                            p1_1.offset.y += 10;
                            if (p1_1.offset.y > 380)
                                p1_1.offset.y = 380;

                            p1_2.offset.y -= 10;
                            if (p1_2.offset.y < 0)
                                p1_2.offset.y = 0;
                            break;
                        case SDLK_ESCAPE:
                            return;
                        default: /* Prevents warnings (don't have a case for all keys */
                            break;
                    }
                }
            }
        } /// end of player movement process
    move (p1_1, p1_2, ball);
    if ((ball.offset.x < 0) | (ball.offset.x+ball.offset.w > SCREEN_WIDTH))
        break; /* If the ball has reached the left/right hand side of the screen, the game is over */
    }

    return; /* Return from the function, game is over */
}

void p1vai (SDL_Surface *screen)
{
    Uint8 startclock = SDL_GetTicks ();
    CPaddle p1 (20); /* The player's paddles */
    CPaddle ai (SCREEN_WIDTH - 30);
    CBall ball; /* The ball */
    update (screen, p1, ai, ball);

    while (true)
    {
        if ((SDL_GetTicks() - startclock) % 2 == 0)
        {
            /* Update the screen */
            update (screen, p1, ai, ball);
            /* game loop, code for moving the paddle goes here: */
            /* While there is an event to be handled */
            if (SDL_PollEvent (&p1.event))
            {
                if (p1.event.type == SDL_QUIT)
                    SDL_Quit (); /* Quit if the cross is clicked */
                if (p1.event.type == SDL_KEYDOWN)
                { /* If a key has been pressed */
                    switch (p1.event.key.keysym.sym)
                    {
                        case SDLK_UP: /* Alter the coordinates if up is pressed */
                            p1.offset.y -= 10;
                            if (p1.offset.y < 0)
                                p1.offset.y = 0;
                            break;
                        case SDLK_DOWN: /* Alter the coordinates if down is pressed */
                            p1.offset.y += 10;
                            if (p1.offset.y > 380)
                                p1.offset.y = 380;
                            break;
                        case SDLK_ESCAPE:
                            return;
                        default: /* Prevents warnings (don't have a case for all keys */
                            break;
                    }
                }
            }
        } /// end of player movement process
    /// move AI player
    if ((SDL_GetTicks() - startclock) % 2 == 0
        && (ball.xVel == 1 | (ball.xVel == -1 && ball.xVel < SCREEN_WIDTH / 2)))
    {
        if (ai.offset.y < 380 && ai.offset.y+5 < ball.offset.y)
            ai.offset.y += 5;
        if (ai.offset.y > 0 && ai.offset.y+95 > ball.offset.y)
            ai.offset.y -= 5;
    }

    move (p1, ai, ball);
    if ((ball.offset.x < 0) | (ball.offset.x+ball.offset.w > SCREEN_WIDTH))
        break; /* If the ball has reached the left/right hand side of the screen, the game is over */
    }

    return; /* Return from the function, game is over */
}

Writing our main menu
There's only a cpp file here.
#include <SDL/SDL.h>       /* Standard SDL header file */
#include <SDL/SDL_image.h> /* Used to load images such as jpg, png, etc */

#include "functions.h"
#include "modes.h"
#include "classes.h"

int main(int argc, char *argv[])
{
    SDL_Surface *screen = NULL; /* The screen surface */
    screen = SDL_SetVideoMode (SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, SDL_SWSURFACE);
    SDL_Rect scr; /* The screen area (used for collision detection */
    scr.x = 0;
    scr.y = 0;
    scr.w = SCREEN_WIDTH;
    scr.h = SCREEN_HEIGHT;
    SDL_Surface *bg = NULL; /* Background surface (used for the splash screen and game over image */
    /* Initialise the video for our program */
    if (SDL_Init (SDL_INIT_VIDEO))
        return EXIT_FAILURE;

    /* Create an event to poll (press any key to begin) */
    SDL_Event e;
    while (true)
    {
        /* Load and display the splash screen */
        bg = load_image ("img/splash.jpg");
        /* Apply the surface */
        apply_surface (0, 0, bg, screen);
        /* Update the appearance */
        SDL_Flip (screen);

        if (SDL_PollEvent (&e)){
            if (e.type == SDL_QUIT)
                SDL_Quit (); /* If the cross has been pressed, quit */
            if (e.type == SDL_KEYDOWN)
                switch (e.key.keysym.sym)
                {
                    case SDLK_1:
                        /* The simplest way to enable key repeats (basically, while the key is being held down */
                        SDL_EnableKeyRepeat(20,20);
                        _1p (screen);
                        Quit_Game (screen);
                        return EXIT_SUCCESS;
                    case SDLK_2:
                        /* The simplest way to enable key repeats (basically, while the key is being held down */
                        SDL_EnableKeyRepeat(20,20);
                        p1vai (screen);
                        Quit_Game (screen);
                        return EXIT_SUCCESS;
                    case SDLK_3:
                        bg = load_image ("img/help.jpg");
                        apply_surface (0,0,bg,screen);
                        SDL_Flip (screen);
                        while (true)
                            if (SDL_PollEvent (&e))
                                if (e.type == SDL_KEYDOWN)
                                    break;
                        break;
                    case SDLK_4:
                        bg = load_image ("img/about.jpg");
                        apply_surface (0,0,bg,screen);
                        SDL_Flip (screen);
                        while (true)
                            if (SDL_PollEvent (&e))
                                if (e.type == SDL_KEYDOWN)
                                    break;
                    default: break;
                }
        }
    }

    /* Program execution was successful */
    return EXIT_SUCCESS;
}

And there we have it! It was a long process, but we got there in the end, and it's worth it!

2 Comments On This Entry

Page 1 of 1

captainhampton Icon

18 July 2008 - 11:35 AM
Damn dude I must say, very nice! I don't think I've ever seen a more straightforward and concise way of transcribing the idea of generating a pong style game. Thinking about submitting to the Tutorial section here?
0

gabehabe Icon

18 July 2008 - 11:37 AM
Probably not...

It's here for people to learn from anyway :)

When I get further into this game programming stuff, I might make a tutorial on a side-scroller engine though :)

Thanks for the feedback though ^_^
0
Page 1 of 1

December 2017

S M T W T F S
     12
3456789
10111213141516
17 181920212223
24252627282930
31      

Request A Topic!

Want me to blog about something? Perhaps a language? A piece of software? A specific topic? Let me know! Even guests can post here on my blog!

If you would like to request a topic, please post a comment here and I'll get on it right away! smile.gif

Search My Blog

0 user(s) viewing

0 Guests
0 member(s)
0 anonymous member(s)

gabehabe's off-topic ramblings

Follow me on Twitter!
lol, my other blog died a horrible lonely death. Ah well.

Smiley of the [however often I change it]

IPB Image

Contact Me

e-mail: [email protected]

Google Talk: [email protected]
MSN: [email protected]
Yahoo: gabehabe (rarely used)
AIM: gabehabe (rarely used)

Skype: gabehabe

Want me to work for you? [click]