======Project: PONG====== =====Objectives===== the purpose is to learn the SDL libraries and build a pong game =====Prerequisites===== In order to successfully accomplish/perform this project, the listed resources/experiences need to be consulted/achieved: install SDL libraries =====Scope===== I feel that this project will be tough and hope I am able to complete it by the end of the semester =====procedure===== I have commented my procedure in the code itself, see code section, I hope that was ok to do =====Code===== Upon completion of the project, if there is an applicable collection of created code, place a copy of your finished code within blocks here. //The headers #include"SDL/SDL.h" #include"SDL/SDL_image.h" #include"SDL/SDL_ttf.h" #include #include #include //The screen attributes const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; const int SCREEN_BPP = 32; //The frame rate const int FRAMES_PER_SECOND = 20; //The dimensions of the ball const int BALL_WIDTH = 35; const int BALL_HEIGHT = 35; //The dimensions of the paddles const int PADDLE_WIDTH = 15; const int PADDLE_HEIGHT = 85; //The surfaces SDL_Surface *ball = NULL; SDL_Surface *background = NULL; SDL_Surface *screen = NULL; SDL_Surface *paddleL = NULL; SDL_Surface *paddleR = NULL; //The event structure SDL_Event event; //The font TTF_Font *font = NULL; //The color of the font SDL_Color textColor = { 255, 255, 255 }; //The left paddle that will move class PaddleL { private: //The velocity of left paddle int xVel, yVel; public: //Initializes the variables for left paddle PaddleL(); SDL_Rect boxL; //Takes key presses and adjusts left paddle's velocity void handle_input(); //Moves left paddle void move(); //Shows left paddle on the screen void show(); }; //The right paddle that will move class PaddleR { private: //The velocity of right paddle int xVel, yVel; public: //Initializes the variables for right paddle PaddleR(); SDL_Rect boxR; //Takes key presses and adjusts right paddle's velocity void handle_input(); //Moves right paddle void move(); //Shows right paddle on the screen void show(); }; //The ball that will move around the screen class Ball { public: //Initializes the variables Ball(); SDL_Rect collbox; int xVel, yVel; //Resets ball to center of screen void reset(); //Takes key presses and adjusts the ball's velocity void handle_input(); //Moves the ball void move(); //Shows the ball on the screen void show(); }; //The timer class Timer { private: //The clock time when the timer started int startTicks; //The ticks stored when the timer was paused int pausedTicks; //The timer status bool paused; bool started; public: //Initializes variables Timer(); //The various clock actions void start(); void stop(); void pause(); void unpause(); //Gets the timer's time int get_ticks(); //Checks the status of the timer bool is_started(); bool is_paused(); }; SDL_Surface *load_image( std::string filename ) { //The image that's loaded SDL_Surface* loadedImage = NULL; //The optimized surface that will be used SDL_Surface* optimizedImage = NULL; //Load the image loadedImage = IMG_Load(filename.c_str()); //If the image loaded if(loadedImage != NULL) { //Create an optimized surface optimizedImage = SDL_DisplayFormat(loadedImage); //Free the old surface SDL_FreeSurface(loadedImage); //If the surface was optimized if(optimizedImage != NULL) { //Map the color key Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 255, 255, 255); //Set all pixels of color R 255, G 255, B 255 (white) to be transparent SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey ); } } //Return the optimized surface return optimizedImage; } void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL) { //Holds offsets SDL_Rect offset; //Get offsets offset.x = x; offset.y = y; //Blit SDL_BlitSurface(source, clip, destination, &offset); } bool check_collision( SDL_Rect A, SDL_Rect B) { //The sides of the rectangles int leftA, leftB; int rightA, rightB; int topA, topB; int bottomA, bottomB; //Calculate the sides of rect A and rect B leftA = A.x; rightA = A.x + A.w; topA = A.y; bottomA = A.y + A.h; leftB = B.x; rightB = B.x + B.w; topB = B.y; bottomB = B.y + B.h; //If any of the sides from A are outside of B if( bottomA <= topB) { return false; } if( topA >= bottomB ) { return false; } if( rightA<=leftB) { return false; } if( leftA>=rightB) { return false; } //If none of the sides from A are outside B return true; } bool init() { //Initialize all SDL subsystems if(SDL_Init( SDL_INIT_EVERYTHING ) == -1) { return false; } //Set up the screen screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE); //If there was an error in setting up the screen if(screen == NULL) { return false; } //Initialize SDL_ttf if( TTF_Init() == -1 ) { return false; } //Set the window caption SDL_WM_SetCaption("Hit space bar to begin", NULL); //If everything initialized fine return true; } bool load_files() { //Load the images ball = load_image("tennisBall.bmp"); background = load_image("Background.bmp"); paddleL = load_image("paddleRed.bmp"); paddleR = load_image("paddleBlue.bmp"); //Open the font font = TTF_OpenFont("lazy.ttf", 89); //If there was a problem in loading the font if(font == NULL) { return false; } //If there was a problem loading the ball if(ball == NULL) { return false; } //If there was a problem in loading the background if(background == NULL) { return false; } //If there was a problem in loading a paddle if(paddleL == NULL || paddleR == NULL) { return false; } //If everything loaded fine return true; } void clean_up() { //Free the surfaces SDL_FreeSurface(ball); SDL_FreeSurface(background); SDL_FreeSurface(paddleL); SDL_FreeSurface(paddleR); //Close the font TTF_CloseFont(font); //Quit SDL_ttf TTF_Quit(); //Quit SDL SDL_Quit(); } PaddleL::PaddleL() { //Initialize the offsets boxL.x = 0; boxL.y = SCREEN_HEIGHT/2 - PADDLE_HEIGHT/2; //Set the collision box's dimensions boxL.w = PADDLE_WIDTH; boxL.h = PADDLE_HEIGHT; //Initialize the velocity xVel = 0; yVel = 0; } PaddleR::PaddleR() { //Initialize the offsets boxR.x = 625; boxR.y = SCREEN_HEIGHT/2 - PADDLE_HEIGHT/2; //Set the collision box's dimensions boxR.w = PADDLE_WIDTH; boxR.h = PADDLE_HEIGHT; //Initialize the velocity xVel = 0; yVel = 0; } void PaddleL::handle_input() { //If a key was pressed if( event.type == SDL_KEYDOWN ) { //Adjust the velocity switch( event.key.keysym.sym ) { case SDLK_a: yVel -= PADDLE_HEIGHT/9; break; case SDLK_z: yVel += PADDLE_HEIGHT/9; break; } } //If a key was released else if( event.type == SDL_KEYUP ) { //Adjust the velocity switch( event.key.keysym.sym ) { case SDLK_a: yVel += PADDLE_HEIGHT/9; break; case SDLK_z: yVel -= PADDLE_HEIGHT/9; break; } } } void PaddleR::handle_input() { //If a key was pressed if( event.type == SDL_KEYDOWN ) { //Adjust the velocity switch( event.key.keysym.sym ) { case SDLK_UP: yVel -= PADDLE_HEIGHT/9; break; case SDLK_DOWN: yVel += PADDLE_HEIGHT/9; break; } } //If a key was released else if( event.type == SDL_KEYUP ) { //Adjust the velocity switch( event.key.keysym.sym ) { case SDLK_UP: yVel += PADDLE_HEIGHT/9; break; case SDLK_DOWN: yVel -= PADDLE_HEIGHT/9; break; } } } void PaddleL::move() { //Move the paddle up or down boxL.y += 2*yVel; //If the paddle went to far up or down if( (boxL.y<0) || (boxL.y + PADDLE_HEIGHT > SCREEN_HEIGHT) ) { //Move back boxL.y -= 2*yVel; } } void PaddleR::move() { //Move the paddle up or down boxR.y += 2*yVel; //If the paddle went to far up or down if( (boxR.y<0) || (boxR.y + PADDLE_HEIGHT > SCREEN_HEIGHT) ) { //Move back boxR.y -= 2*yVel; } } void PaddleL::show() { //Show the Paddle apply_surface(boxL.x, boxL.y, paddleL, screen); } void PaddleR::show() { //Show the Paddle apply_surface(boxR.x, boxR.y, paddleR, screen); } Ball::Ball() { //Initialize the offsets collbox.x = SCREEN_WIDTH/2 - BALL_WIDTH/2; collbox.y = SCREEN_HEIGHT/2 - BALL_HEIGHT/2; //Set the square's dimensions collbox.w = BALL_WIDTH - 5; collbox.h = BALL_HEIGHT - 5; //Initialize the velocity xVel = 0; yVel = 0; } void Ball::reset() { //Reset the offsets collbox.x = SCREEN_WIDTH/2 - BALL_WIDTH/2; collbox.y = SCREEN_HEIGHT/2 - BALL_HEIGHT/2; //Reset the velocity xVel = 0; yVel = 0; } void Ball::handle_input() { int lORr; //To determine if the ball starts going left or right //If a key was pressed if( event.type == SDL_KEYDOWN ) { //Assign random initial velocity if( event.key.keysym.sym == SDLK_SPACE ) { lORr = rand()%2; if(lORr == 0){ xVel = rand()%5+10; yVel = rand()%15; } if(lORr == 1){ xVel = (rand()%5+10*-1); yVel = (rand()%15)*-1; } } } } void Ball::move() { //Move the ball left or right collbox.x += xVel; //Move the ball up or down collbox.y += yVel; //If the ball went to far up or down if( (collbox.y<0) || (collbox.y + BALL_HEIGHT > SCREEN_HEIGHT) ) { //Move back yVel = -1*yVel; } } void Ball::show() { //Show the ball apply_surface(collbox.x, collbox.y, ball, screen); } Timer::Timer() { //Initialize the variables startTicks = 0; pausedTicks = 0; paused = false; started = false; } void Timer::start() { //Start the timer started = true; //Unpause the timer paused = false; //Get the current clock time startTicks = SDL_GetTicks(); } void Timer::stop() { //Stop the timer started = false; //Unpause the timer paused = false; } void Timer::pause() { //If the timer is running and isn't already paused if( (started == true) && (paused == false) ) { //Pause the timer paused == true; //Calculate the paused ticks pausedTicks = SDL_GetTicks() - startTicks; } } void Timer::unpause() { //If the timer is paused if(paused == true) { //Unpause the timer paused = false; //Reset the starting ticks startTicks = SDL_GetTicks() - pausedTicks; //Reset the paused ticks pausedTicks = 0; } } int Timer::get_ticks() { //If the timer is running if(started == true) { //If the timer is paused if(paused == true) { //Return the number of ticks when the timer was paused return pausedTicks; } else { //Return the current time minus the start time return SDL_GetTicks() - startTicks; } } //If the timer isn't running return 0; } bool Timer::is_started() { return started; } bool Timer::is_paused() { return paused; } int main( int argc, char* args[] ) { //The surface for the winning message SDL_Surface *message = NULL; //Quit flag bool quit = false; //The ball that will be used Ball myBall; //The paddles that will be used PaddleL paddleL; PaddleR paddleR; //The frame rate regulator Timer fps; //Initialize if(init() == false) { return 1; } //Load the files if(load_files() == false) { return 1; } //While the user hasn't quit while( quit == false ) { //Start the frame timer fps.start(); //While there's events to handle while( SDL_PollEvent(&event) ) { //Handle events for the ball myBall.handle_input(); //Handle events for the paddles paddleL.handle_input(); paddleR.handle_input(); //If the user has Xed the window if (event.type == SDL_QUIT) { //Quit the program quit = true; } } //Move the ball myBall.move(); //If the ball hits left paddle if(check_collision(myBall.collbox, paddleL.boxL) == true ) { //Bounce ball back myBall.xVel = rand()%30+15; //Bounce ball back if( myBall.yVel == 0 ) { myBall.yVel = 1 ; } myBall.yVel = (myBall.yVel/(abs(myBall.yVel)?myBall.yVel:1) )*rand()%20; } //If the ball hits right paddle if((check_collision(myBall.collbox, paddleR.boxR) == true) ) { //Bounce ball back myBall.xVel = (rand()%30+15)*-1; if( myBall.yVel == 0 ) { myBall.yVel = 1 ; } myBall.yVel = (myBall.yVel/(abs(myBall.yVel)?myBall.yVel:1) )*rand()%20; } //Move the paddles paddleL.move(); paddleR.move(); //Apply the background to the screen apply_surface(0, 0, background, screen); //Show the ball on the screen myBall.show(); //If the ball goes off the left side of the screen if( (myBall.collbox.x + BALL_WIDTH) < 0) { //Print a message saying left paddle wins message = TTF_RenderText_Solid(font, "SCORE BITCH!!", textColor); //If a message needs to be displayed if( message != NULL ) { //Apply the background to the screen apply_surface( 0, 0, background, screen ); //Apply the message centered on the screen apply_surface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen ); //Null the surface pointer message = NULL; } //If space bar is hit then reset the ball if( event.key.keysym.sym == SDLK_SPACE ) { myBall.reset(); } } //If the ball goes off the right side of the screen if( myBall.collbox.x > SCREEN_WIDTH) { //Print a message saying left paddle wins message = TTF_RenderText_Solid(font, "SCORE BITCH!!", textColor); //If a message needs to be displayed if( message != NULL ) { //Apply the background to the screen apply_surface( 0, 0, background, screen ); //Apply the message centered on the screen apply_surface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen ); //Null the surface pointer message = NULL; } //If space bar is hit then reset the ball if( event.key.keysym.sym == SDLK_SPACE ) { myBall.reset(); } } //Show the paddles on the screen paddleL.show(); paddleR.show(); //Update the screen if( SDL_Flip( screen ) == -1 ) { return 1; } //Cap the frame rate if(fps.get_ticks() < 1000 / FRAMES_PER_SECOND) { SDL_Delay( (1000/ FRAMES_PER_SECOND) - fps.get_ticks() ); } } //Clean up clean_up(); return 0; } =====Execution===== Again, if there is associated code with the project, and you haven't already indicated how to run it, provide a sample run of your code: lab46:~/src/$ g++ -o pong cong2.cpp -lSDL -lSDL_image -lSDL_ttf lab46:~/src/$ ./pong =====Reflection===== This project was really stressing and frustrating at first but after a while I really started to catch on and it was pretty fun! =====References===== In performing this project, the following resources were referenced: * http://www.lazyfoo.net/SDL_tutorials/ * http://www.cplusplus.com/forum/ * http://www.dreamincode.net/forums/forum/15-c-and-c/ * lair help from matt and other, thanks!!!