Written by: Andy Odle
Date: Mar 3, 2011
This tutorial utilizes v1.03 please download and use this version to prevent
problems that are present in previous versions. This tutorial also builds upon
skills learned in the 2D Sprite, Input Handling and Collision Detection tutorials.
This tutorial covers:
Moving ball specific code into its own class.
Adding in player code from previous tutorials.
Adding a start game mechanism.
Reorganizing Ball Source Code:
1.) Add the ball and paddle images to the ./Debug/images/ folder.
Note: If you don't have the images you can download them here.
2.) Open GOC.h in CodeLite.
3.) Add the Ball class declaration before the GOC class.
Ball Class
class Ball { public: // Create the game balls // // Input: // Balls to create, game window width, and game window height Ball(int numberOfBalls_p, int windowWidth_p, int windowHeight_p); ~Ball(); // Add a new ball to the game. void CreateBall(); void UpdateBalls(Sprite *playerOne_p, Sprite *playerTwo_p); private: int ballCount_m; // Current number of balls in play. int numberOfBalls_m; // Total number of balls to play. int maxBallX_m; int maxBallY_m; float *ballVelocityX_m; float *ballVelocityY_m; int ballSpeed_m; float ballAngle_m; Sprite *balls_m; // Game balls. };
4.) Add a Ball pointer, called ball_m to the GOC class's private variables section.
5.) Open main.cpp.
6.) Add the Ball constructor below the GOC.h include statement.
Ball Constructor Definition
#include "./source/inc/GOC.h"isrelo/admin/EditArticles.php Ball::Ball(int numberOfBalls_p, int windowWidth_p, int windowHeight_p) { }
In the Ball's constructor:
a.) Set numberOfBalls_m to the same value as numberOfBalls_p.
b.) Initialize ballCount_m to zero.
c.) Set maxBallX_m to be the windowWidth_p minus 24.
d.) Set maxBally_m to be the windowHeight_p minus 24.
e.) Set ballSpeed_m to 10.
f.) Set ballAngle_m to 60.
g.) Set ballVelocityX_m and ballVelocityY_m to a new float array to hold the same
number of elements as numberOfBalls_m.
h.) Set balls_m to a new array of Sprites to hold the same number of elements as
numberOfBalls_m.
i.) Loop from zero to the numberOfBalls_m.
In the Loop from zero to the numberOfBalls_m:
I.) Set ballVelocityX_m[count] to the ballSpeed_m times the cos of the
ballAngle_m pluss the current count.
II.) Set ballVelocityY_m[count] to the ballSpeed_m times the sin of the
ballAngle_m pluss the current count.
III.) Create a PointGOC called ballPosition_l and initialize the xCor_m to the
windowWidth_p divided by 2, yCor_m to the windowHeight_p divided by 2
and zCor_m to 0.0f.
IV.) Set balls_m[count]'s starting position to ballPosition_l, width to 24 and heigh
to 24.
V.) Set balls_m[count]'s texture to "./images/Ball.png".
VI.) Set balls_m[count]'s visibility to false.
Ball::Ball()
Ball::Ball(int numberOfBalls_p, int windowWidth_p, int windowHeight_p) { numberOfBalls_m = numberOfBalls_p; ballCount_m = 0; // Max ball x and y cordinate. maxBallX_m = windowWidth_p - 24; maxBallY_m = windowHeight_p - 24; ballSpeed_m = 10; ballAngle_m = 60; ballVelocityX_m = new float[numberOfBalls_m]; ballVelocityY_m = new float[numberOfBalls_m]; // Create all the balls for the game. balls_m = new Sprite[numberOfBalls_m]; for(int count = 0; count < numberOfBalls_m; count++) { // Give each ball a different direction. ballVelocityX_m[count] = ballSpeed_m * cos(ballAngle_m + count); ballVelocityY_m[count] = ballSpeed_m * sin(ballAngle_m + count); // New balls start center screen. PointGOC ballPosition_l = {windowWidth_p / 2, windowHeight_p / 2, 0.0f}; balls_m[count].Set2DPosition(ballPosition_l, 24, 24); balls_m[count].GetTexture()->LoadTexture( "./images/Ball.png" ); balls_m[count].SetVisible(false); } }
7.) Add the Ball's CreateBall() just after the Ball's constructor.
Ball CreateBall Definition
void Ball::CreateBall() { }
In the Ball's CreateBall function:
a.) Set balls_m[ballCount_m]'s visibility to true, if the ballCount_m is less than the
numberOfBalls_m.
b.) Increment ballCount_m.
Ball::CreateBall()
void Ball::CreateBall() { // Add a new ball into the game. if(ballCount_m < numberOfBalls_m) { balls_m[ballCount_m].SetVisible(true); ballCount_m++; } }
8.) Add the Ball's UpdateBalls(...), passing in a playerOne_p and playerTwo_p
pointer just after the CreateBall().
Ball UpdateBalls Definition
void Ball::UpdateBalls( Sprite *playerOne_p, Sprite *playerTwo_p ) { }
In the Ball's UpdateBalls function:
a.) Loop from zero upto the current ballCount_m.
In the Loop from zero to the ballCount_m:
If the current balls_m[count] is visible:
I.) Set the balls_m[count] xCor to the balls_m[count] xCor pluss the
ballVelocityX_m[count].
II.) Set the balls_m[count] yCor to the balls_m[count] yCor pluss the
ballVelocityY_m[count].
If the current balls_m[count]'s yCor is less than or equal to zero:
III.) Set the ballVelocityY_m[count] to the negative ballVelocityY_m[count].
IV.) Set the balls_m[count]'s yCor to zero.
If the current balls_m[count]'s yCor is greater than or equal to maxBallY_m:
V.) Set the ballVelocityY_m[count] to the negative ballVelocityY_m[count].
VI.) Set the balls_m[count]'s yCor to maxBallY_m.
If the current balls_m[count]'s yCor is less than or equal to zero:
VII.) Set balls_m[count]'s visibility to false.
If the current balls_m[count]'s yCor is greater than or equal to maxBallX_m:
VIII.) Set balls_m[count]'s visibility to false.
IX.) Check to see if the ball has collided with playerOne_m's or playerTwo's paddle.
Note: The code for checking ball and paddle collisions comes from the collision detection tutorial.
Ball::UpdateBalls(...)
void Ball::UpdateBalls(Sprite *playerOne_p, Sprite *playerTwo_p) { for(int count = 0 ; count < ballCount_m; count++) { if(balls_m[count].IsVisible()) { // Move the ball a little bit each frame. balls_m[count].SetXCor( balls_m[count].GetXcor() + ballVelocityX_m[count] ); balls_m[count].SetYCor( balls_m[count].GetYcor() + ballVelocityY_m[count] ); // Top Screen Edge Has been reached. if(balls_m[count].GetYcor() <= 0) { ballVelocityY_m[count] = -ballVelocityY_m[count]; balls_m[count].SetYCor(0); } // Bottom Screen Edge Has been reached. if(balls_m[count].GetYcor() >= maxBallY_m) { ballVelocityY_m[count] = -ballVelocityY_m[count]; balls_m[count].SetYCor(maxBallY_m); } // Right Screen Edge Has been reached. if(balls_m[count].GetXcor() >= maxBallX_m) { // Player One Scored remove ball from game. balls_m[count].SetVisible(false); } // Left Screen Edge Has been reached. if(balls_m[count].GetXcor() <= 0) { // Player Two Scored remove ball from game. balls_m[count].SetVisible(false); } // Ball collied with PlayerOne's paddle. if(playerOne_p->HasCollidedRight( &balls_m[count]) == CollidedSide::RIGHT_COLLISION ) { ballVelocityX_m[count] = -ballVelocityX_m[count]; balls_m[count].SetXCor(31); } // Ball collied with PlayerTwo's paddle. if(playerTwo_p->HasCollidedLeft( &balls_m[count]) == CollidedSide::LEFT_COLLISIOIN ) { ballVelocityX_m[count] = -ballVelocityX_m[count]; balls_m[count].SetXCor(maxBallX_m - 31); } } } }
9.) Add the Ball's ~Ball() just after the UpdateBalls(...).
Ball::~Ball()
Ball::~Ball() { delete[] ballVelocityX_m; delete[] ballVelocityY_m; delete[] balls_m; }
10.) Create a new instance of the Ball class in the GOC::Initialize().
Initialize Ball Class
void GOC::Initialize() { /* Initialize your game scene, and game variables here. */ // Initialize all the game balls. ball_m = new Ball(6000, GetWindowWidth(), GetWindowHeight()); }
In the GOC::Update(...) if gameStarted_m is true:
11.) Update all of the balls.
Update Balls After Game Starts
void GOC::Update(TimeGOC *timeGOC_p, InputEngine *input_p) { /* Update your game scenes, check for collisions, check for input and play sounds here. */ // Only update the balls if the game has begun. if(gameStarted_m) { ball_m->UpdateBalls(playerOne_m, playerTwo_m); } }
12.) Destroy the balls_m instance in the GOC::Destroy().
Destroy Ball Class Instance
void GOC::Destroy() { /* Clean up after your game here. */ delete ball_m; }
Adding Previous Player Code:
1.) Open GOC.h.
2.) Add a Sprite pointer, called playerOne_m to the GOC class's private variables section.
3.) Add a Sprite pointer, called playerTwo_m to the GOC class's private variables section.
4.) Open main.cpp.
5.) Initialize playerOne_m and playerTwo_m in GOC::Initialize().
6.) Update playerOne_m and playerTwo_m in GOC::Update(...).
7.) Destroy playerOne_m and playerTwo_m in GOC::Destroy().
Starting the Game When a Key Has Been Pressed:
1.) Open GOC.h.
2.) Add a boolean called gameStarted_m.
3.) Open main.cpp.
4.) Set gameStarted_m to false in the GOC::Initialize().
Initialize Start Game Variable
void GOC::Initialize() { /* Initialize your game scene, and game variables here. */ // Initialize all the game balls. ball_m = new Ball(6000, GetWindowWidth(), GetWindowHeight()); // Has the game started? gameStarted_m = false; }
5.) Set gameStarted_m to true if the enter key has been pressed in the
GOC::Update(...).
Start The Game On Enter
void GOC::Update(TimeGOC *timeGOC_p, InputEngine *input_p) { /* Update your game scenes, check for collisions, check for input and play sounds here. */ // Only update the balls if the game has begun. if(gameStarted_m) { ball_m->UpdateBalls(playerOne_m, playerTwo_m); } // If enter has been pressed start the game. if(input_p->IsKeyOrButtonPressed( KeysAndButtons::ENTER_KEYBOARD, false )) { gameStarted_m = true; } }
6.) Click Build -> Build and Run Project in CodeLite.
(Back to "Windows® " or "Ubuntu® " Tutorials)
Organizing Previous Code Complete Example:
You can get the complete example source code here.
/* File Name: GOC.h Created By: Andy Odle Date: Mar 2, 2011 */ #ifndef GOC_h #define GOC_h #ifdef _WIN32 #include "./source/PlatformSpecific/inc/WindowManager_WIN.h" #else #include "./source/PlatformSpecific/inc/WindowManager_UBUNTU.h" #endif #include "./source/PlatformSpecific/inc/ErrorReport.h" #include "./source/PlatformSpecific/inc/DeviceInput.h" #include "./source/PlatformSpecific/inc/Sprite.h" #include "./source/inc/TimeGOC.h" #include "./source/inc/TimerGOC.h" #include "./source/inc/InputEngine.h" #include "./source/inc/Render2D.h" #include "./source/inc/UniqueNumber.h" #include "./source/inc/MathGOC.h" /* Add new include files here */ class Ball { public: // Create the game balls // // Input: // Balls to create, game window width, and game window height Ball(int numberOfBalls_p, int windowWidth_p, int windowHeight_p); ~Ball(); // Add a new ball to the game. void CreateBall(); void UpdateBalls(Sprite *playerOne_p, Sprite *playerTwo_p); private: int ballCount_m; // Current number of balls in play. int numberOfBalls_m; // Total number of balls to play. int maxBallX_m; int maxBallY_m; float *ballVelocityX_m; float *ballVelocityY_m; int ballSpeed_m; float ballAngle_m; Sprite *balls_m; // Game balls. }; class GOC { public: // Initialize the developer's game. virtual void Initialize(); // Updates the developer's game state. virtual void Update(TimeGOC *timeGOC_p, InputEngine *input_p); virtual void IndependentUpdate(TimeGOC *timeGOC_p, InputEngine *input_p); // Ceans up the developer's game. virtual void Destroy(); // This is how you interact with the GOC. // // Output: // Returns the Game Object Creator instance pointer. static GOC *goc_i(); // Get the window's width and height. int GetWindowWidth(); int GetWindowHeight(); // Start the setup of the Game Object Creator. #ifdef _WIN32 void LoadGOC(HINSTANCE &hinstance_p); #else void LoadGOC(); #endif // Clean up the Game Object Creator. void UnloadGOC(); ErrorReport *GetErrorReport(); private: GOC(); ~GOC(); GOC(GOC const&){}; GOC &operator=(GOC const&){}; private: ErrorReport *errorReport_m; static GOC *goc_m; /* Add private variables here. */ Ball *ball_m; Sprite *playerOne_m; Sprite *playerTwo_m; int maxPlayerPosition_m; bool gameStarted_m; }; #endif
/* File Name: main.cpp Created By: Andy Odle Date: Mar 2, 2011 */ #include "./source/inc/GOC.h" Ball::Ball(int numberOfBalls_p, int windowWidth_p, int windowHeight_p) { numberOfBalls_m = numberOfBalls_p; ballCount_m = 0; // Max ball x and y cordinate. maxBallX_m = windowWidth_p - 24; maxBallY_m = windowHeight_p - 24; ballSpeed_m = 10; ballAngle_m = 60; ballVelocityX_m = new float[numberOfBalls_m]; ballVelocityY_m = new float[numberOfBalls_m]; // Create all the balls for the game. balls_m = new Sprite[numberOfBalls_m]; for(int count = 0; count < numberOfBalls_m; count++) { // Give each ball a different direction. ballVelocityX_m[count] = ballSpeed_m * cos(ballAngle_m + count); ballVelocityY_m[count] = ballSpeed_m * sin(ballAngle_m + count); // New balls start center screen. PointGOC ballPosition_l = { windowWidth_p / 2, windowHeight_p / 2, 0.0f}; balls_m[count].Set2DPosition(ballPosition_l, 24, 24); balls_m[count].GetTexture()->LoadTexture( "./images/Ball.png" ); balls_m[count].SetVisible(false); } } void Ball::CreateBall() { // Add a new ball into the game. if(ballCount_m < numberOfBalls_m) { balls_m[ballCount_m].SetVisible(true); ballCount_m++; } } void Ball::UpdateBalls(Sprite *playerOne_p, Sprite *playerTwo_p) { for(int count = 0 ; count < ballCount_m; count++) { if(balls_m[count].IsVisible()) { // Move the ball a little bit each frame. balls_m[count].SetXCor( balls_m[count].GetXcor() + ballVelocityX_m[count] ); balls_m[count].SetYCor( balls_m[count].GetYcor() + ballVelocityY_m[count] ); // Top Screen Edge Has been reached. if(balls_m[count].GetYcor() <= 0) { ballVelocityY_m[count] = -ballVelocityY_m[count]; balls_m[count].SetYCor(0); } // Bottom Screen Edge Has been reached. if(balls_m[count].GetYcor() >= maxBallY_m) { ballVelocityY_m[count] = -ballVelocityY_m[count]; balls_m[count].SetYCor(maxBallY_m); } // Right Screen Edge Has been reached. if(balls_m[count].GetXcor() >= maxBallX_m) { // Player One Scored remove ball from game. balls_m[count].SetVisible(false); } // Left Screen Edge Has been reached. if(balls_m[count].GetXcor() <= 0) { // Player Two Scored remove ball from game. balls_m[count].SetVisible(false); } // Ball collied with PlayerOne's paddle. if(playerOne_p->HasCollidedRight( &balls_m[count]) == CollidedSide::RIGHT_COLLISION ) { ballVelocityX_m[count] = -ballVelocityX_m[count]; balls_m[count].SetXCor(31); } // Ball collied with PlayerTwo's paddle. if(playerTwo_p->HasCollidedLeft( &balls_m[count]) == CollidedSide::LEFT_COLLISIOIN ) { ballVelocityX_m[count] = -ballVelocityX_m[count]; balls_m[count].SetXCor(maxBallX_m - 31); } } } } Ball::~Ball() { delete[] ballVelocityX_m; delete[] ballVelocityY_m; delete[] balls_m; } void GOC::Initialize() { /* Initialize your game scene, and game variables here. */ // Initialize all the game balls. ball_m = new Ball(6000, GetWindowWidth(), GetWindowHeight()); // Has the game started? gameStarted_m = false; // Initialize player one. PointGOC playerOnePosition_l = { 15, 15, 0.0f}; playerOne_m = new Sprite(); playerOne_m->Set2DPosition( playerOnePosition_l, 15, 200 ); playerOne_m->GetTexture()->LoadTexture( "./images/Padle.png" ); playerOne_m->SetVisible(true); // Initialize player two. PointGOC playerTwoPosition_l = { GetWindowWidth() - 30, 15, 0.0f }; playerTwo_m = new Sprite(); playerTwo_m->Set2DPosition( playerTwoPosition_l, 15, 200 ); playerTwo_m->GetTexture()->LoadTexture( "./images/Padle.png" ); playerTwo_m->SetVisible(true); maxPlayerPosition_m = GetWindowHeight() - playerOne_m->GetHeight(); } void GOC::Update(TimeGOC *timeGOC_p, InputEngine *input_p) { /* Update your game scenes, check for collisions, check for input and play sounds here. */ // Only update the balls if the game has begun. if(gameStarted_m) { ball_m->UpdateBalls(playerOne_m, playerTwo_m); } // If enter has been pressed start the game. if(input_p->IsKeyOrButtonPressed( KeysAndButtons::ENTER_KEYBOARD, false )) { gameStarted_m = true; } // Update PlayerTwo's position using the mouse. if(input_p->YCordinate() < maxPlayerPosition_m) { playerTwo_m->SetYCor( input_p->YCordinate() ); } else { playerTwo_m->SetYCor(maxPlayerPosition_m); } // Move PlayerOne up. if(input_p->IsKeyOrButtonPressed( KeysAndButtons::UP_KEYBOARD ) && playerOne_m->GetYcor() > 0) { playerOne_m->SetYCor(playerOne_m->GetYcor() - 20); } // Move PlayerOne down. if(input_p->IsKeyOrButtonPressed( KeysAndButtons::DOWN_KEYBOARD ) && playerOne_m->GetYcor() < maxPlayerPosition_m) { playerOne_m->SetYCor(playerOne_m->GetYcor() + 20); } } void GOC::IndependentUpdate(TimeGOC* timeGOC_p, InputEngine* input_p) { /* Update your game scenes, check for collisions, check for input and play sounds here. */ } void GOC::Destroy() { /* Clean up after your game here. */ delete ball_m; delete playerOne_m; delete playerTwo_m; } #ifdef _WIN32 // Define the windows main funciton. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) #else // Define the ubutnu main function. int main(int argc, char **argv) #endif { #ifdef _WIN32 // Start the GOC on windows. GOC::goc_i()->LoadGOC(hInstance); #else // Start the GOC on ubuntu. GOC::goc_i()->LoadGOC(); #endif return 0; }
Legal Info  About GOC  Contact Us