When I started game programming I had all the enthusiasm but lacked quality information on how to go about actually making a complete game. There is a definite lack of complete game programming tutorials. Much of my time was spent flicking from one webpage to another not finding anything particularly useful. So I’ve decided to write a tutorial for your benefit so by the end you will be able to have a complete game under your belt. A perfect game to start off with, in my opinion, is Pong. This project will use VC++ and OpenGL for the examples. _ The main game loop The main game loop of most games basically goes like this: Handle input Update movements Check for collisions Check game conditions Render Pong is no different. With these in mind we shall structure our Game_Main function around this. Game States The game will be in various states while running. We need to take care of these so we will have a global named gameState and define these at the beginning of our code. These are: PLAYING GAMEOVER GETREADY The GETREADY state will be a state when the player's have a chance to get ready when the ball is reset after a goal or a new game is started. Game Objects We will make use of the OO technology we should look at what objects the game will use. The advantages of using OO to encapsulate the objects will makes things a great deal more organised. Practicing these methods now will pay off when you have a large project, you wont have to wade through so much code to make modifications. For a game such as Pong there aren't too many:- Paddle Ball Wall Goal Board Each of these we will create a class for and fill in as we progress. Where do we start? With most of my projects I like to get something happening on the screen so I can test things as I go. For this project I think a good place to start would be to get the board drawn on the screen. Just a simple rectangle will do for now. We can modify and add to it as we go. We’ll create a new class CBoard to do this. This class will need to have attributes and functions added to operate in our game world. Our class diagram for the board will be like this:- CBoard width height color[3] Draw() Pretty simple. The color array is just an RGB (red, green, blue) set for the board. We may add some attributes later, such as a texture for the board. We’ll set the width/height and color attributes in the class constructor. The class definition and implementation will look like this Cboard.h Code: // CBoard.h // // Author: william palmer=me // // Forgotten Realms // #include #include // For OpenGL calls class CBoard { public: CBoard(); // Constructor ~CBoard(); // Destructor float width, height; // Actual playing field size float color[3]; // RGB color set Draw(); // Draw to opengl screen }; Code: #include "CBoard.h" // Class declaration //////////////////////////////////////////////////////////////////// // Constructor CBoard::CBoard(): width(13.0f), // Initialize width and height height(10.0f) { color[0] = 0; // Set the board color to blue color[1] = 0; color[2] = 1; } //////////////////////////////////////////////////////////////////// // Destructor CBoard::~CBoard() { } //////////////////////////////////////////////////////////////////// // Draw to opengl screen CBoard::Draw() { glColor3fv(color); // Set the color using the rgb color set glBegin(GL_QUADS); // Draw the board with center at (0,0) glVertex3f(-width/2, -height/2, 0.0f); glVertex3f(-width/2, height/2, 0.0f); glVertex3f( width/2, height/2, 0.0f); glVertex3f( width/2, -height/2, 0.0f); glEnd(); } We need to include the class definition in main.cpp, and for such a simple game we will declare the objects as globals and refer to them in our main.cpp functions. Adding a couple of lines to the Game_Main() function to call the board class' Draw() function and we get something happening. THE BALL The ball is probally the most complex object we will have in our game, it is also the most interesting! Our ball will need a few attributes. We need to keep track of it's position which we'll use x,y,z for. It also has a radius and a color similar to the board. The ball has a speed vector [xi, yi, zi] which represents the relative movement of the ball. It will be used to update the ball position and direction. We shall talk more about this later. To draw the ball in OpenGL we’ll get tricky and use a quadric. It sounds pretty in depth but it's just an easy way to draw a 3D sphere. The line attribute GLUquadricObj *sphere is a pointer to the quadric that we'll use to create and draw it. It’s pretty simple to use, check out the NeHe tut on quadrics if you want to know more. We also have a function Reset() for when we want to return the ball to the start position whenever a goal is scored or a new game starts. The Update() function will use the speed vector to update the ball position every game cycle. We will implement this later, and for now just get the ball to appear on screen. The Draw() function will need to set the color a little differently for the ball since it is a 3D object. A simple call to set the material attributes in OpenGL does this. Our class diagram for the ball: CBall x, y, z (Center of the ball) xi, yi, zi (This is our speed vector) radius color[3] GLUquadricObj *sphere Draw() Reset() Update() We implement this in CBall.h and CBall.cpp and add a couple of lines to the rendering section and see the result: Cball.cpp Code: #include "CBall.h" // Class declaration //////////////////////////////////////////////////////////////////// // Constructor CBall::CBall(): x(0.0f), y(0.0f), z(0.0f), xi(0.5f), yi(0.5f), zi(0.0f), radius(0.5f) { color[0] = 1; // Set the ball color color[1] = 1; color[2] = 0; sphere = gluNewQuadric(); // Create a pointer to a quadric object gluQuadricNormals(sphere, GLU_SMOOTH); // Create smooth normals gluQuadricTexture(sphere, GL_TRUE); // Create texture coords } //////////////////////////////////////////////////////////////////// // Destructor CBall::~CBall() { gluDeleteQuadric(sphere); // Remove the quadric from memory } //////////////////////////////////////////////////////////////////// // Draw to opengl screen CBall::Draw() { float mat_diff[] = { color[0], color[1], color[2], 1.0 }; // We have to set material properties when dealing with quadrics glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diff); glPushMatrix(); // Save current matrix, so translation doesnt affect rest of program glTranslatef(x+radius/2, y-radius/2, z+radius/2); // Translate sphere so it is centered around x,y,z gluSphere(sphere, radius/2, 10, 10); // Draw sphere glPopMatrix(); // Restore matrix } //////////////////////////////////////////////////////////////////// // Reset the ball position and vector CBall::Reset() { x = y = z = 0; xi = 0.5f; yi = 0.5f; zi = 0; } //////////////////////////////////////////////////////////////////// CBall::Update() { // Implement this later } CBall.h Code: #include <windows.h> #include <gl\gl.h> // Header File For The OpenGL32 Library #include <gl\glu.h> // Glu32 header for quadrics class CBall { public: float x, y, z; // Top-left position on screen float xi, yi, zi; // Movement vector float radius; float color[3]; CBall(); // constructor ~CBall(); // destructor Draw(); // Draw to opengl screen Reset(); // Reset ball position and vector Update(); // Update ball's position with vector private: GLUquadricObj *sphere; // Storage for quadratic object }; The other objects The Walls The class diagram: CWall x, y (Top left coordinates) width height color[3] Draw() * We’ll assume the width runs along X-axis and height along the Y-axis. These are just rectangles that we can position at the top and bottom of the board. We will use these to bounce the ball off when we do some collision detection. We add lines to the Game_Init() function that position the walls and as with the other objects we need to draw we add a Draw() command to the rendering section. Here is the code:- CWall.h Code: // CWall.h #include <windows.h> #include <gl/gl.h> // For OpenGL calls class CWall { public: float x, y; // Top left coordinates float width, height; // Actual playing field size float color[3]; // RGB color set CWall(); // Constructor ~CWall(); // Destructor Draw(); // Draw to opengl screen }; CWall.cpp Code: // CWall implementation #include "CWall.h" // Class declaration //////////////////////////////////////////////////////////////////// // Constructor CWall::CWall(): width(13.0f), // Initialize width and height height(0.5f) { color[0] = 1; // Set the wall color color[1] = 0; color[2] = 0; } //////////////////////////////////////////////////////////////////// // Destructor CWall::~CWall() { } //////////////////////////////////////////////////////////////////// // Draw to opengl screen CWall::Draw() { glColor3fv(color); // Set the color using the rgb color set glPushMatrix(); // Store the matrix so we can do the translation glTranslatef(x, y, 0); // Position wall at x,y glBegin(GL_QUADS); // Draw the board with center at (0,0) glVertex3f(0, 0, 0); glVertex3f(0, -height, 0); glVertex3f(width, -height, 0); glVertex3f(width, 0, 0); glEnd(); glPopMatrix(); // Restore previous matrix } The paddles Class diagram: CPaddle x, y (Top left coordinates) width height speed color[3] score Draw() Reset() :Paddles aren’t much different from wall, except we will give them a movement speed and a player score. We also initialise their positions in Game_Init(). The Reset() function will be called when a new game starts, it will just reset the player's score back to zero. CPaddle.h Code: // CPaddle.h #include <windows.h> #include <gl\gl.h> // Header File For The OpenGL32 Library class CPaddle { public: float width, height; // Paddle dimensions float x, y; // Top-left position on screen float speed; // Movement speed float color[3]; // RGB color of the paddle int score; // Player's score CPaddle(); // Constructor ~CPaddle(); // Destructor Draw(); // Draw to opengl screen Reset(); }; CPaddle.cpp Code: // CPaddle implementation #include "CPaddle.h" // Class declaration //////////////////////////////////////////////////////////////////// // Constructor CPaddle::CPaddle(): x(0.0f), y(0.0f), width(0.5f), height(3.0f), speed(0.3f), score(0) { color[0] = 0; color[1] = 1; color[2] = 0; } //////////////////////////////////////////////////////////////////// // Destructor CPaddle::~CPaddle() { } //////////////////////////////////////////////////////////////////// // Draw to opengl screen CPaddle::Draw() { glColor3fv(color); glBegin(GL_QUADS); glVertex3f(x, y , 0.0f); glVertex3f(x, y - height, 0.0f); glVertex3f(x + width, y - height, 0.0f); glVertex3f(x + width, y , 0.0f); glEnd(); } //////////////////////////////////////////////////////////////////// // Reset paddle for new game CPaddle::Reset() { score = 0; } The goal Since the wall and goal are so similar, we can use a wall object to represent the goal. We don't need to see the goal so we'll just leave out the command for drawing it. When checking we have positioned the goal in the right spot we can just do a call to the Draw() function and see it on screen. Note: The objects share a lot of attributes which we could use to make an abstract base class to derive them from, but since this is a beginners project and there’s not too many objects we shall leave it be. If you don’t know what I mean, don’t worry it’s just a more advanced OO technique that can be learnt later. clicke game2 for picture Paddle movement Looks like we have all the basic bits and pieces on the screen. I hope you don’t think it was very hard, the next section will get the game actually doing something. Moving the paddle The paddle movement is going to require input from the keyboard. We will use the keys ‘A’ and ‘Z’ for player 1 and the up and down cursors for player 2. To check if a key is pressed with this code framework is pretty easy. We just need to check each key using the function KEY_DOWN() in the Game_Main() loop. For the ‘A’ key we just check KEY_DOWN(DIK_A). Our code will be: if (KEY_DOWN(DIK_A)) move player 1 paddle up Too easy, the others work exactly the same. To move the player’s paddle we just update their position according to the paddle speed attribute of the class: player1.y += speed; does the trick. Paddle/wall collisions Okay, it's not too good if the paddles can fly off the screen so we'll be adding some collision detection with the walls to stop that. To detect the collision we check if the edge of the paddle will move past the edge of the wall. When this happens we'll have to let the computer know what we'll want to happen, which in this case, the paddle stops next to the wall. click collision Diagram to see the picture By looking at the diagram we can see the edges we need to check. For the top wall we check: if (Paddle.y > (topWall.y - topWall.height)) and the bottom wall: if ((Paddle.y - Paddle.height) < bottomWall.y) When the collision occurs, we set the Paddle.y position to that edge of the wall. This is done every game loop for both player1 and 2 in the collision section of Game_Main(). Ball movement The most complex object of the game is the ball. As we mentioned before, the ball has a vector which tells us direction the ball is travelling. If you don't know about vectors, a basic physics/science book will go into depth explaining it. The vector contains information describing how far to move on each axis. For example: A vector where xi = 1 and yi = -2, would mean we would move 1 unit right on the x-axis and 2 units down on the y-axis. So having a vector for a ball, we can easily make the ball go whatever direction we want just by changing the values of each component. I have decided to add another attribute to the ball class. It will have a speed attribute which will allow us to alter the ball speed easily as the game progresses making it faster so there's a challenge. Again change it's value in the constructor if it is too slow/fast for your system. In combination with the ball vector we can write the Update() function: x += xi * speed; y += yi * speed; z += zi * speed; We will update the ball's current position every game loop in Game_Main() by calling the Update() function in the ball class. Making these changes to the code we can now see the ball fly straight off the screen. Looks like we'll need to add some collision detection, that's next! cball update Code: // CBall implementation #include "CBall.h" // Class declaration //////////////////////////////////////////////////////////////////// // Constructor CBall::CBall(): x(0.0f), y(0.0f), z(0.0f), xi(0.5f), yi(0.5f), zi(0.0f), radius(0.25f), speed(0.15f) { color[0] = 1; // Set the ball color color[1] = 1; color[2] = 0; sphere = gluNewQuadric(); // Create a pointer to a quadric object gluQuadricNormals(sphere, GLU_SMOOTH); // Create smooth normals gluQuadricTexture(sphere, GL_TRUE); // Create texture coords } //////////////////////////////////////////////////////////////////// // Destructor CBall::~CBall() { gluDeleteQuadric(sphere); // Remove the quadric from memory } //////////////////////////////////////////////////////////////////// // Draw to opengl screen CBall::Draw() { float mat_diff[] = { color[0], color[1], color[2], 1.0 }; // We have to set material properties when dealing with quadrics glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diff); glPushMatrix(); // Save current matrix, so translation doesnt affect rest of program glTranslatef(x, y, z); // Translate ball position gluSphere(sphere, radius, 10, 10); // Draw sphere glPopMatrix(); // Restore matrix } //////////////////////////////////////////////////////////////////// // Reset the ball position and vector CBall::Reset() { x = y = z = 0; xi = 0.5f; yi = 0.5f; zi = 0; speed = 0.15f; } //////////////////////////////////////////////////////////////////// CBall::Update() { x += xi * speed; // Update ball position according to vector y += yi * speed; z += zi * speed; } Ball/Wall collisions Testing for this type of collision is exactly the same as we did for the paddles. The only difference is when the collision occurs we want the ball to bounce off and go the other direction. To make the ball go in the opposite direction the y vector component is just inverted. Therefore if we are travelling towards the top wall yi is positive, to go down we make it negative. The bottom wall is the same. ball.yi = -ball.yi This line acheives it for both scenarios. Check out that collision test doing it's wonders: Ball/paddle collisions More collisions! If you mastered the last section this collision isn't much different. Instead of working with ball.yi we work on ball.xi. We only need to check the front edge of the paddle (we can do the side edges of the paddle but it's not crucial). We have to have an extra check in this collision. First we have the same as the wall only on the x-axis, then we have to check ball's y position is in position to hit the paddle. Code: if ((ball.x - ball.radius < player1.x + player1.width) && (ball.y < player1.y) && (ball.y > player1.y - player1.height)) ball.xi = -ball.xi; if ((ball.x + ball.radius > player2.x) && (ball.y < player2.y) && (ball.y > player2.y - player1.height)) ball.xi = -ball.xi; It looks tough, but it is just the same as the other collisions with an extra check. click game 3 to look at it Scoring goals Checking if a goal is scored should be easy if you've been following. The question is what do we do when a goal is scored? First the player who scored needs to gain a point, we just add 1 to their score attribute. player.score++ Secondly the ball needs to be reset and the player's should be given a little time to get ready. This is where our gameState variable will come in handy. We'll set it to GETREADY that was defined earlier for this purpose. So we can test when to change from GETREADY back to PLAYING we need to use a timer which will be handled with a new global name gameStateTimer. The system function timeGetTime() is used to set it to the current time in milliseconds and add a delay for the time when we change states. 2000 milliseconds (2 seconds) for the delay should be fine. When the game state is GETREADY I've displayed some text so the player's know what's going on. In Game_Main() we check for the game state being GETREADY and test whether it is time to change back to PLAYING by comparing the timer with the current time. One more thing is make sure the ball only moves when the game state is PLAYING click game4 to view it Nearly done! Okay this is the home stretch. You will have a complete game after this! There are a few loose ends that need to be tidied up. First, we'll display the player's score in the top corners, a few lines in the text output section of Game_Main() and we're in buisness. We will also check if the GAMEOVER condition occurs. When either of the player's score 7 points we'll end it. Then, we'll make the game state start with GAMEOVER when we initialize the game and display "GAME OVER" the same as was done for "GET READY!". Also we'll allow a new game to be started when we are in the GAMEOVER state and the space bar is pressed. We need to reset the player scores here, and change the game state to GETREADY. Letting the players know the keys is a good idea when the game is in GAMEOVER state.
This is the end of the tutorial i hoped you all like it below is the full source code and game. I hope u like it if you our anyone else needs help with this please dont hesitate to ask me thankyou all for reading this tutorial. This tutorial was brought to you by XXxxImmortalxxXX game download+source code Game Download
also i put a glitch in the game the first one to figure it out and send me the files will win a free copy of FPS CREATOR this is not a lie its the truth hope to see you all try and figure it out.
do we have to tell you where the glitch is in the source code or is it visible from game play? :smug:
Done that. You had one code block in a single line and probably that could be. By the way very nice article.
Yes you must send me a valid game back to me with the updated code files in the section to where you updated the code at the following //name //time //date //what did you do and how did you change it // if it is correct do you want the FPS CREATOR sent to you via mail or do you want a serial key and you just download the program at the site and enter in the serial key when you boot up the game also the glitch is when you start up the game the pong instantly shoots to the top right hand corner slow its speed down and make it to where it goes <------- and ---------> instead of oblique also thankyou very much for the compliment i really appreciate that alot. More Tutorials coming soon on game programing next article will be related to Visual Basic RPG programing in 2-D one of the best ways to start off with rpg programing is in a 2-d based way
np mate i also posted another game programing article to teach you a simple RPG combat attack script made in VB
Hey, I heard about iPhone Game Programming – Tutorial, it helps to cover basics of taking an OpenGL ES Application template available in Xcode and making the changes necessary so that we can use it for writing out game.
Dear XXxxImmortalxxXX, I can't download your full source code and game I hope u will help me to download this game.
Good looking tutorial, btw. game programming this way is pain in *** If you want to programm some efficient game, you should use some preprogrammed libraries and functions