Pong SDL

Started by
6 comments, last by pulpfist 18 years, 5 months ago
Ok, so I've got my pong game setup, but want to add some finishing touches on it like sound FX, and opening screen, and a scoreboard. Right now when you open the .exe it goes straight into the game and the ball starts moving right away and play commences. Im wondering how to add a screen before the game starts to have the user press spacebar to continue and start playing the game.

#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>

using namespace std;

const int WINDOW_WIDTH = 720;
const int WINDOW_HEIGHT = 480;
const char* WINDOW_TITLE = "Pong";
float ballXVel = 1;
float ballYVel = 1;
int main(int argc, char *argv[])
{
	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER );
	SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 0, 
      SDL_HWSURFACE | SDL_DOUBLEBUF );
	SDL_WM_SetCaption(WINDOW_TITLE, 0);
	SDL_Surface* paddle1 = SDL_LoadBMP("paddle1.bmp");
	SDL_Surface* paddle2 = SDL_LoadBMP("paddle2.bmp");
	SDL_Surface* ball = SDL_LoadBMP("ball.bmp");
    SDL_SetColorKey(ball, SDL_SRCCOLORKEY, SDL_MapRGB(ball->format, 
      255, 0, 0)); 
	
    SDL_Rect paddle1_source;
	paddle1_source.x = 0;
	paddle1_source.y = 0;
	paddle1_source.w = 20;
	paddle1_source.h = 100;
	
	SDL_Rect paddle1_destination;
    paddle1_destination.x = 75;
    paddle1_destination.y = 240;
    paddle1_destination.w = 20;
    paddle1_destination.h = 100;
    
    SDL_Rect paddle2_source;
    paddle2_source.x = 0;
    paddle2_source.y = 0;
    paddle2_source.w = 20;
    paddle2_source.h = 100;
    
    SDL_Rect paddle2_destination;
    paddle2_destination.x = 645;
    paddle2_destination.y = 240;
    paddle2_destination.w = 20;
    paddle2_destination.h = 100;
    
    SDL_Rect ball_source;
    ball_source.x = 0;
    ball_source.y = 0;
    ball_source.w = 25;
    ball_source.h = 25;
    
    SDL_Rect ball_position;
    ball_position.x = WINDOW_WIDTH/2;
    ball_position.y = WINDOW_HEIGHT/2;
    ball_position.w = 25;
    ball_position.h = 25;
    
SDL_Event event;

	bool gameRunning = true;
	bool keysHeld[323] ={false};
	while (gameRunning)
	{
		
        
        if (SDL_PollEvent(&event))
		{
			if (event.type == SDL_QUIT)
			{
				gameRunning = false;
			}
			if (event.type == SDL_KEYDOWN)
			{
				keysHeld[event.key.keysym.sym] = true;
			}
			if (event.type == SDL_KEYUP)
			{
				keysHeld[event.key.keysym.sym] = false;
			}	
		}
		
		
        if (keysHeld[SDLK_ESCAPE])
		{
			gameRunning = false;
		}
        if (keysHeld[SDLK_UP])
        {
            paddle1_destination.y -= 2;
        }
        if (keysHeld[SDLK_DOWN])
        {
            paddle1_destination.y += 2;
            if (paddle1_destination.y + paddle1_destination.h > WINDOW_HEIGHT)
            {
                paddle1_destination.y = 480 - paddle1_destination.h;
            }
        }
        if (keysHeld[SDLK_KP2])
        {
            paddle2_destination.y += 2;
            if (paddle2_destination.y + paddle2_destination.h > WINDOW_HEIGHT)
            {
                paddle2_destination.y = 480 - paddle2_destination.h;
            }
        }
        if (keysHeld[SDLK_KP8])
        {
            paddle2_destination.y -= 2;
        }
        
        
        ball_position.x += ballXVel;
        ball_position.y += ballYVel;


        
        if (ball_position.x  + ball_position.w >  WINDOW_WIDTH)
        {
             gameRunning = false;
        }
        if (ball_position.x  < 0)
        {
             gameRunning = false;
        }
        if (ball_position.y  + ball_position.h >  WINDOW_HEIGHT)
        {
             ballYVel *= -1;
        }
        if (ball_position.y  <0  )
        {
             ballYVel *= -1;
        }
        if (ball_position.x   == paddle1_destination.x + paddle1_destination.w && ball_position.y + ball_position.h >= paddle1_destination.y )
        {
             ballXVel *= -1.0;  
        }
        if (ball_position.x +ball_position.w  == paddle2_destination.x  && ball_position.y + ball_position.h  >= paddle2_destination.y && ball_position.y <= paddle2_destination.y + paddle2_destination.h)
        {
             ballXVel *= -1.0;
        }
        SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 0));
        SDL_BlitSurface(paddle1, &paddle1_source, screen, &paddle1_destination);
        SDL_BlitSurface(paddle2, &paddle2_source, screen, &paddle2_destination);
        SDL_BlitSurface(ball, &ball_source, screen, &ball_position);
        
        SDL_Flip(screen);
	    
    }
    SDL_FreeSurface(paddle1); 
    SDL_FreeSurface(paddle2);
    SDL_FreeSurface(ball);
    
    SDL_Quit();
	return 0;
}

Advertisement
you could define different game states:

#define GAME_STATE_INTRO 0#define GAME_STATE_RUN 1#define GAME_STATE_SCOREBOARD 2int game_state = GAME_STATE_INTRO;while (game_state < 3){  if(KEYDOWN(ESCAPE))    game_state++;  ...  switch(game_state)  {    case GAME_STATE_INTRO:      // fill backbuffer with intro image or whatever...      break;    case GAME_STATE_RUN:      // fill backbuffer with next game frame (ofcourse)      break;    case GAME_STATE_SCOREBOARD:      // fill backbuffer with scores and stuff...      break;  }  // render screen (flip)}


Maybe use the ESCAPE key to exit the intro and start running,
and ESCAPE again to quit the game and go to the score board :p
Just an idea
Hmmmm, im kinda confused, where would i put my collision detection stuff, and my event, and all of my SDL_Rects?

everything should only be used under GAME_STATE_RUN ^^

intro and scoreboard only need to show a image and some text.

ohh the event stuff must go outside the switch i guess
Hmmm, i think i understand now. So, i just blit my intro scree under case GAME_STATE_INTRO and put the rest of the code under case GAME_STATE_RUN:? In that case, im inclined to ask, where do i put the main () function?
Everything stays as it is as I see it.

Only set up a switch right after the key event stuff, and
put all the game render and collision stuff under GAME_STATE_RUN
(basically all the stuff you have there now)
Except
SDL_Flip(screen);

that must be after the switch
What I typically do is have the main program run a program manager class. Within that class is a subclass manager for each game state. Something like this:

-----------------------

MAIN LOOP:

{
programManager.Run(); //called every frame
}

-----------------------

PROGRAM MANAGER:

int gameState;

.
.
.

bool CProgramManager::Run()
{

.
.
.
//runs the submanager for the appropriate game state.
switch(gameState)
{
case GAMEPLAY :
gameplayManager.Run();
break;
case SPLASH :
splashScreenManager.Run();
break;
case SCORE :
scoreScreenManager.Run();
break;

}
.
.
.

}

-----------------------

The program manager class works as sort of a facade. As your games get bigger, you'll be glad to have the code for each state ecapsulated separately.
Yes, and also when using different game states, you have full control of each state.
If you want you could give the keys on the keyboard different meaning based on the current game state, which can come in very handy, say if you need the user to type in an ip address in the init state, while in run state the same keys would write text to a game chat or something.

This topic is closed to new replies.

Advertisement