Other than that you have a few errors in your code. Here is my take on it. These are only suggestions.
#include "game.h"int main( int argc, char* argv[] ) { Game pong; if( pong.mainMenu() ) { // you declared Game::play to return an integer // either use the return value, or don't return a value return pong.play(); } return 0;}
#ifndef GAME_H#define GAME_H// The preferred way to include SDL is like this// This allows games to be source portable among systems where SDL is not// in a subdirectory called SDL. Instead, set your additional include path// to include /path/to/your/include/SDL#include "SDL.h"#include "graphics.h"#include "ball.h"struct Gamestate{public: Gamestate(const Ball &ball) : ball(ball) { } void process(double t, double dt); // anticipating future need void draw(Gfx &gfx);private: Ball ball;};const int SCREEN_W = 600;const int SCREEN_H = 400;class Game{public: // don't write empty constructors or destructors Game() : gfx(SCREEN_W,SCREEN_H) { } // ~Game(); bool mainMenu(); int play();private: // these can be local to play // SDL_Event event; // Gamestate* current_state; // Gamestate* previous_state; // at the moment, this could be made a local too. // it is kept as a member because your mainMenu function is likely to // make use of it. Gfx gfx;};// these can be made part of the ball class// extern Ball newBall( int x, int y, float velocity, float angle, float rad );// extern void updateBall( Ball* b, double dt );#endif
#include "game.h"#include "timer.h"// these are included in "game.h"// include "ball.h"// include "SDL.h"void Gamestate::process(double t, double dt ){ // Move ball ball.update( dt ); // Todo: Rest of processing, eg. collision detection}bool Game::mainMenu(){ return true; // Placeholder for a future main menu}int Game::play(){ Timer timer; const float DELTA = 0.01; // prefer values to pointers // previous_state = new Gamestate; // current_state = new Gamestate; // I have removed the "previous" state, as it doesn't appear // to be used in any meaningful way Gamestate current(Ball( 100, 100, 0.1, 0.0, 5.0 )); bool loop = true; SDL_Event event; while( loop ) { timer.fillAccu(); while( timer.pinchAccu( DELTA ) ) { current.process( timer.getTimePassed(), DELTA ); } while( SDL_PollEvent( &event ) ) { if( event.type == SDL_QUIT ) loop = false; } current.draw( gfx ); } return 0;}
#ifndef GFX_H#define GFX_H#include "SDL.h"class Gfx{public: // by taking the screen dimensions as arguments, this class // is easier to re-use in future projects Gfx(int width, int height); ~Gfx(); // do "init" work in constructor // note: you used the return value to signal success or failure // however, your game class never checked the result! // int init(); // the graphics objects shouldn't really care what they are drawing // they shouldn't access the game state // instead, other objects should tell it what to draw // and where // void draw( Gamestate* state );private: SDL_Surface* screen; void drawPixel( int x, int y );};#endif
#include "graphics.h"// include "game.h"// C++ standard headers have no extension#include <cmath>// we include this so we can use// the standard C++ exception types#include <stdexcept>// exceptions are the easiest way to signal such errors// this is a fatal error usually.Gfx::Gfx(int width, int height){ screen = 0; if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { throw std::runtime_error(SDL_GetError()); } SDL_WM_SetCaption( "PongSDL", NULL ); screen = SDL_SetVideoMode( width, height, 32, SDL_SWSURFACE ); if( !screen ) { // we need to ensure SDL_Quit is called on all code paths // if the graphics object is successfully constructed, its // constructor will call it. If this error occurs though // we must call it here SDL_Quit(); throw std::runtime_error(SDL_GetError()); }}Gfx::~Gfx(){ // SDL says you shouldn't free the screen surface // SDL_Quit does this for you SDL_Quit();}void Gfx::drawPixel( int x, int y ){ SDL_Rect rect; rect.x = x; rect.y = y; rect.w = 1; rect.h = 1; SDL_FillRect( screen, &rect, SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ) );}
#ifndef BALL_H#define BALL_H// balls are now smart objects// they can set themselves up, and can update themselvesstruct Ball{public: Ball(float x, float y, float velocity, float angle, float radius ); void update(float dt);private: float x; float y; float velx; float vely; float radius;};#endif
#include "ball.h"#include <cmath>// use helper functions to increase code clarityfloat to_radians(float degrees){ return degrees / 180.0f * 3.14f;}float cos_degrees(float angle){ return cos(to_radians(angle));}float sin_degrees(float angle){ return sin(to_radians(angle));}Ball::Ball( float x, float y, float velocity, float angle, float radius ): x(x), y(y), velx(cos_degrees(angle)), vely(sin_degrees(angle)), radius(radius){}void Ball::update( float dt ){ x += dt * velx; y += dt * vely;}