• Advertisement


  • Content count

  • Joined

  • Last visited

Community Reputation

850 Good

About SpeedRun

  • Rank

Personal Information

  1. Breakout Clone v1.0

    Looking forward to hear your comments on the game, although currently it has very basic gameplay. You are right  - once I have all the elements in I need to look at either buying art or finding an artist to collaborate with.
  2. Breakout Clone v1.0

    The first release of the Breakout clone is finally here. The Installer will install directx and the visual studio 2010 re-distributable. If you would prefer to run the game through a zip file, you can download it from here. You will have to make sure that you have the visual studio 2010 re-distributables as well as the latest DirectX installed on your machine. Try it out . Incase, you face any problems while installing or running the game, let me know and I will try to come up with a solution. Looking forward to hearing your comments on the game Crossposted here [size=7]Screenshots [sharedmedia=gallery:images:5149] [sharedmedia=gallery:images:5150] [sharedmedia=gallery:images:5152] [sharedmedia=gallery:images:5151]
  3. BreakOut Progress

  4. Thanks for the feedback Dave and CornStalks   Since the popular consensus seems to be that the article is very complex for beginners, I intend to break it down in parts and explain the basics. I will also try to remove the framework dependencies as far as possible.
  5. Do you have DirectX and the visual studio 2010 run-times installed?    
  6. Thanks for the feedback rip-off and Dan @rip-off : The whole point of this article is that it does not depend on any specific engine, but concentrates more on the gameplay. Even if i explained the rendering concepts, they would differ from the API(DIrectX vs OpenGL wars anyone) let alone a specific engine. I felt it would be better to let the reader substitute the framework for any other engine that they might like to use.  I have updated the article to make the handling of null elements consistent   @Dan: Most readers would be using a 3rd party engine. Even if they used DirectX or OpenGL, they would still need to be aware of how to incorporate third party code, They are already lots of collision detection/ rendering tutorials which are articles in their own right. Teaching how to implement a rendering framework is beyond the scope of this article and would take away from actually building the game. The article also mentions that it assumes the reader has a basic knowledge of the game loop and a rendering engine. I have updated the article to highlight the scope
  7. Pong is one of the earliest video games to gain popularity. It is a good project to start out with as it has the most basic gameplay. However, it introduces some fundamental concepts which are common to all games. Who is this article for You should be familiar with the C++ programming language. You should also know how to integrate third party code. You should also have a basic understanding of a rendering engeine and how the game loop works. This article will cover the gameplay, It will NOT cover the concepts that can be abstracted away by Third party tools/engines. Requirements to compile the code C++ compiler (I am using Visual Studio 10, but can use an IDE of your choice) Directx X SDK (June 2010) Objectives Allow player to move the paddle Check for ball collisions with the paddles and walls Basic AI While this project utilizes my custom engine(built on C++ and DirectX), it is possible to extend the logic to other platforms. This project uses 3D models, but you can easily use sprites instead (as long as the engine you are using supports it) Making the Game Game Elements Pong has the following game elements Ball, Left Paddle Right Paddle Top Wall, Bottom Wall, All the above elements will be represented with the following Initial Position Current Position Model associated with this game element We will create an array of GameElements that will store the data for each of our game elements Game.h class cGame { enum PONGGAMEELEMENTS { PGE_UNKNOWN = -1, PGE_BALL, PGE_PADDLE_LEFT, PGE_PADDLE_RIGHT, PGE_WALL_UP, PGE_WALL_DOWN, PGE_TOTAL } public: // functions and extraneous variables omitted private: cPongGameElement ** m_ppGameElements; // ptr to the gameelements }; In this project (0,0) lies at the center of the screen. I will be using a cGameElementDef structure which will be populated to create the game elements. This will be passed into the Initialize function of the game element and will setup the model and the initial position void VOnInitialization() { //For the paddles cGameElementDef paddleDef; paddleDef.strModelName= "cube"; paddleDef.vPosition= cVector3(m_vScreenTopLeftPos.x, 0.0f, 0.0f); m_ppGameElements[PGE_PADDLE_LEFT] = DEBUG_NEW cPaddle(); m_ppGameElements[PGE_PADDLE_LEFT]->VInitialize(paddleDef); paddleDef.vPosition= cVector3(m_vScreenBottomRightPos.x, 0.0f, 0.0f); m_ppGameElements[PGE_PADDLE_RIGHT] = DEBUG_NEW cPaddle(); m_ppGameElements[PGE_PADDLE_RIGHT]->VInitialize(paddleDef); // for the walls cGameElementDef wallDef; wallDef.strModelName = "cube"; wallDef.vPosition= cVector3(0, m_vScreenTopLeftPos.y, 0.0f); m_ppGameElements[PGE_WALL_UP] = DEBUG_NEW cWall(); m_ppGameElements[PGE_WALL_UP]->VInitialize(wallDef); wallDef.vPosition= cVector3(0, m_vScreenBottomRightPos.y, 0.0f); m_ppGameElements[PGE_WALL_DOWN] = DEBUG_NEW cWall(); m_ppGameElements[PGE_WALL_DOWN]->VInitialize(wallDef); cGameElementDef ballDef; ballDef.strModelName = "sphere"; ballDef.vScale = cVector3(0.5f, 0.5f, 0.5f); pGame->m_ppGameElements[pGame->PGE_BALL] = DEBUG_NEW cBall(); pGame->m_ppGameElements[pGame->PGE_BALL]->VInitialize(ballDef); } void VOnUpdate() { for(int i=0; iOnUpdate(m_pGameTimer->VGetDeltaTime()); } } } void Render() { for (int i=0; iPGE_TOTAL; i++) { if(m_ppGameElements && m_ppGameElements) { // Render the game elements model at the current position m_ppGameElements->Render(); } } } void Cleanup() { if(m_ppGameElements) { for (int i=0; i Handling Keyboard Input For taking player input through the keyboard we will be using the WindowProc callback function. In the code below we use a class function VOnMsgProc to handle the window messages. All we need to do here is check if the appropriate key is pressed and perform the required action. We move the left paddle up/down when W/S is pressed. bool VOnMsgProc(const AppMsg & msg ) { if(!cHumanView::VOnMsgProc(msg)) { if(msg.m_uMsg == WM_KEYDOWN) { if (msg.m_wParam == VK_ESCAPE && !IsKeyLocked(VK_ESCAPE)) { // lock the ESC key LockKey(VK_ESCAPE); PostQuitMessage(-1); } if (msg.m_wParam == 'S') { m_pGame->MoveLeftPaddle(true); } if (msg.m_wParam == 'W') { m_pGame->MoveLeftPaddle(false); } } else if (msg.m_uMsg == WM_KEYUP) { if (msg.m_wParam == VK_ESCAPE) { UnlockKey(VK_ESCAPE); } } } return true; } Game.cpp void MoveLeftPaddle(bool bMoveDown) { cPaddle * pPaddle = m_ppGameElements[PGE_PADDLE_LEFT]->CastToPaddle(); if(pPaddle) { if (bMoveDown) { pPaddle->MoveDown(m_pGameTimer->VGetDeltaTime()); } else { pPaddle->MoveUp(m_pGameTimer->VGetDeltaTime()); } } } Paddle.cpp void MoveDown(const float fElapsedTime) { float fDeltaMovement = m_fMoveFactor * fElapsedTime; cVector3 vPredictedPos = GetPosition(); vPredictedPos.y -= fDeltaMovement; SetPosition(vPredictedPos); } void MoveUp(const float fElapsedTime) { float fDeltaMovement = m_fMoveFactor * fElapsedTime; cVector3 vPredictedPos = GetPosition(); vPredictedPos.y += fDeltaMovement; SetPosition(vPredictedPos); } At this point, when you press 'W' the left paddle should move up and when you press 'S' the paddle should move down. But you will notice that if you keep the key pressed, the paddle goes off-screen. This is because we have no collision checks. The next part will constrain the paddle to be on the screen at all times. Keeping the Paddle on Screen For all the game elements add a collider to it. For keeping the paddle on the screen we will check if a collision occurs when moving it. If there is a collision, we don't update the paddle's position. Paddle.cpp void MoveDown(const float fElapsedTime) { cContact contact; float fDeltaMovement = m_fMoveFactor * fElapsedTime; shared_ptr const pAABB = IAABB::DuplicateAABB(GetAABB()); pAABB->VTransalate(cVector3(0, -fDeltaMovement, 0)); if (!(ICollisionChecker::GetInstance()->VCheckForCollisions(pAABB.get(), m_pGame->VGetGameElements()[m_pGame->PGE_WALL_DOWN]->GetAABB(), contact))) { cVector3 vPredictedPos = GetPosition(); vPredictedPos.y -= fDeltaMovement; SetPosition(vPredictedPos); } } void MoveUp(const float fElapsedTime) { cContact contact; float fDeltaMovement = m_fMoveFactor * fElapsedTime; shared_ptr const pAABB = IAABB::DuplicateAABB(GetAABB()); pAABB->VTransalate(cVector3(0, fDeltaMovement, 0)); if (!(ICollisionChecker::GetInstance()->VCheckForCollisions(pAABB.get(), m_pGame->VGetGameElements()[m_pGame->PGE_WALL_UP]->GetAABB(), contact))) { cVector3 vPredictedPos = GetPosition(); vPredictedPos.y += fDeltaMovement; SetPosition(vPredictedPos); } } Moving the Ball To move the ball, we will give it an initial velocity. On each update cycle we will check if it has collided with the wall or paddles and if so then change its direction and/or speed. If the ball goes off screen, we will restart the level. On restarting the level, we give the ball a random velocity. Ball.cpp void VInitialize(const cGameElementDef & def) { cPongGameElement::VInitialize(def); m_pRandomGenerator = IRandomGenerator::CreateRandomGenerator(); m_vSpeed = cVector3(static_cast(m_pRandomGenerator->Random(5,10)), static_cast(m_pRandomGenerator->Random(5,10)), 0.0f); } void OnRestart() { cPongGameElement::OnRestart(); m_vSpeed = cVector3(static_cast(m_pRandomGenerator->Random(5,10)), static_cast(m_pRandomGenerator->Random(5,10)), 0.0f); } void OnUpdate(float fElapsedTime) { cContact contact; cVector3 vDeltaPos = m_vSpeed * fElapsedTime; shared_ptr const pAABB = IAABB::DuplicateAABB(GetAABB()); pAABB->VTransalate(vDeltaPos); cVector3 vPredictedPos = GetPosition(); //check for collision with walls if ((ICollisionChecker::GetInstance()->VCheckForCollisions(pAABB.get(), m_pGame->VGetGameElements()[m_pGame->PGE_WALL_DOWN]->GetAABB(), contact)) || (ICollisionChecker::GetInstance()->VCheckForCollisions(pAABB.get(), m_pGame->VGetGameElements()[m_pGame->PGE_WALL_UP]->GetAABB(), contact))) { float nv = m_vSpeed.Dot(contact.vNormal); m_vSpeed -= contact.vNormal * 2 * nv; } //check for collision with paddles if ((ICollisionChecker::GetInstance()->VCheckForCollisions(pAABB.get(), m_pGame->VGetGameElements()[m_pGame->PGE_PADDLE_LEFT]->GetAABB(), contact)) || (ICollisionChecker::GetInstance()->VCheckForCollisions(pAABB.get(), m_pGame->VGetGameElements()[m_pGame->PGE_PADDLE_RIGHT]->GetAABB(), contact))) { float nv = m_vSpeed.Dot(contact.vNormal); m_vSpeed -= contact.vNormal * 2 * nv; } vPredictedPos = vPredictedPos + vDeltaPos + contact.vDistance; SetPosition(vPredictedPos); // check if ball is off screen if (GetPosition().x VGetScreenTopLeftPos().x) { cGame * pGame = const_cast(m_pGame); pGame->VRoundOver(true); } else if (GetPosition().x > m_pGame->VGetScreenBottomRightPos().x) { cGame * pGame = const_cast(m_pGame); pGame->VRoundOver(false); } cPongGameElement::OnUpdate(fElapsedTime); } Game.cpp void VRoundOver(const bool bPlayer1Won) { if (bPlayer1Won) { // Increment player1 score } else { // Increment player2 score } Restart(); } Paddle AI If you are running the game, you will realize it's no fun. There is no one competing with you. The AI does not move the paddle to beat you. So let's go ahead and add a basic AI to play against. Our AI will wait for the ball to come in its half of the screen and then move in the (vertical) direction of the ball Game.cpp void VOnUpdate() { //extra code ommitted HandlePaddleAI(m_pGameTimer->VGetDeltaTime()); } void HandlePaddleAI(const float fElapsedTime) { cVector3 vBallPos = m_ppGameElements[PGE_BALL]->GetPosition(); // if the ball is in the players half, there is no need to do anything if (vBallPos.x < 0) { return; } cVector3 vPaddlePos = m_ppGameElements[PGE_PADDLE_RIGHT]->GetPosition(); if (vPaddlePos.y - vBallPos.y < 1) { cPaddle * pPaddle = m_ppGameElements[PGE_PADDLE_RIGHT]->CastToPaddle(); if(pPaddle) { pPaddle->MoveUp(fElapsedTime); } return; } else if (vBallPos.y - vPaddlePos.y < 1) { cPaddle * pPaddle = m_ppGameElements[PGE_PADDLE_RIGHT]->CastToPaddle(); if(pPaddle) { pPaddle->MoveDown(fElapsedTime); } return; } } Running the attached executable To run the code, You should have Visual Studio 2010 redistributable and DirectX redistributable installed on your machine Conclusion This concludes "Retro Games: How to Make Pong". The attached game sample has the basic gameplay. I hope you enjoyed this tutorial and it helped you. Article Update Log 1 Apr 2013: Initial release 2 Apr 2013: Updated Formatting. Fixed Grammatical Errors 1 May 2013: Added note to highlight scope of the article 29 May 2013: Added "Who is this article for", "Requirements for compiling the code" and "Running the attached executable" heading
  8. Tic-Tac-Toe would be a good example to start out with. Single player mode would introduce you to basic AI.
  9. New Release : Asteriods v 2.0

    [color=rgb(40,40,40)][font=arial][font=arial]Version 2.0 of Asteroids has been released[/font][/font][/color] Added Redefinable Controls Allowing Toggle FullScreen/Windowed Immediately The setup can be downloaded here
  10. I had written this tutorial a while back to help finding memory leaks. Its still serving me well, so I think it should solve your problem as well   http://www.gamedev.net/blog/1369/entry-2253912-memory-leak-woes/
  11. New Release : Asteriods v 1.1

    [color=rgb(40,40,40)][font=arial]Version 1.1 of Asteroids has been released[/font][/color] Added High Score Screen. Top 10 scores are tracked. Ship is flashed on on invinciblity for the 1st 5 seconds The setup can be downloaded here
  12. Start by making a simple game such as a Tetris or Pong clone. This way you will have a much better understanding of how to go about making a more complex game. For a more detailed account of why making a Pong clone is a good idea as your first game, you can read this post of mine   [entry='2254511']Why Make Pong[/entry]
  • Advertisement