Game.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // ----------------------------------------------------------------
  2. // From Game Programming in C++ by Sanjay Madhav
  3. // Copyright (C) 2017 Sanjay Madhav. All rights reserved.
  4. //
  5. // Released under the BSD License
  6. // See LICENSE in root directory for full details.
  7. // ----------------------------------------------------------------
  8. #include "Game.h"
  9. const int thickness = 15;
  10. const float paddleH = 100.0f;
  11. Game::Game()
  12. :mWindow(nullptr)
  13. ,mRenderer(nullptr)
  14. ,mTicksCount(0)
  15. ,mIsRunning(true)
  16. ,mPaddleDir(0)
  17. {
  18. }
  19. bool Game::Initialize()
  20. {
  21. // Initialize SDL
  22. int sdlResult = SDL_Init(SDL_INIT_VIDEO);
  23. if (sdlResult != 0)
  24. {
  25. SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
  26. return false;
  27. }
  28. // Create an SDL Window
  29. mWindow = SDL_CreateWindow(
  30. "Game Programming in C++ (Chapter 1)", // Window title
  31. 100, // Top left x-coordinate of window
  32. 100, // Top left y-coordinate of window
  33. 1024, // Width of window
  34. 768, // Height of window
  35. 0 // Flags (0 for no flags set)
  36. );
  37. if (!mWindow)
  38. {
  39. SDL_Log("Failed to create window: %s", SDL_GetError());
  40. return false;
  41. }
  42. //// Create SDL renderer
  43. mRenderer = SDL_CreateRenderer(
  44. mWindow, // Window to create renderer for
  45. -1, // Usually -1
  46. SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
  47. );
  48. if (!mRenderer)
  49. {
  50. SDL_Log("Failed to create renderer: %s", SDL_GetError());
  51. return false;
  52. }
  53. //
  54. mPaddlePos.x = 10.0f;
  55. mPaddlePos.y = 768.0f/2.0f;
  56. mBallPos.x = 1024.0f/2.0f;
  57. mBallPos.y = 768.0f/2.0f;
  58. mBallVel.x = -200.0f;
  59. mBallVel.y = 235.0f;
  60. return true;
  61. }
  62. void Game::RunLoop()
  63. {
  64. while (mIsRunning)
  65. {
  66. ProcessInput();
  67. UpdateGame();
  68. GenerateOutput();
  69. }
  70. }
  71. void Game::ProcessInput()
  72. {
  73. SDL_Event event;
  74. while (SDL_PollEvent(&event))
  75. {
  76. switch (event.type)
  77. {
  78. // If we get an SDL_QUIT event, end loop
  79. case SDL_QUIT:
  80. mIsRunning = false;
  81. break;
  82. }
  83. }
  84. // Get state of keyboard
  85. const Uint8* state = SDL_GetKeyboardState(NULL);
  86. // If escape is pressed, also end loop
  87. if (state[SDL_SCANCODE_ESCAPE])
  88. {
  89. mIsRunning = false;
  90. }
  91. // Update paddle direction based on W/S keys
  92. mPaddleDir = 0;
  93. if (state[SDL_SCANCODE_W])
  94. {
  95. mPaddleDir -= 1;
  96. }
  97. if (state[SDL_SCANCODE_S])
  98. {
  99. mPaddleDir += 1;
  100. }
  101. }
  102. void Game::UpdateGame()
  103. {
  104. // Wait until 16ms has elapsed since last frame
  105. while (!SDL_TICKS_PASSED(SDL_GetTicks(), mTicksCount + 16))
  106. ;
  107. // Delta time is the difference in ticks from last frame
  108. // (converted to seconds)
  109. float deltaTime = (SDL_GetTicks() - mTicksCount) / 1000.0f;
  110. // Clamp maximum delta time value
  111. if (deltaTime > 0.05f)
  112. {
  113. deltaTime = 0.05f;
  114. }
  115. // Update tick counts (for next frame)
  116. mTicksCount = SDL_GetTicks();
  117. // Update paddle position based on direction
  118. if (mPaddleDir != 0)
  119. {
  120. mPaddlePos.y += mPaddleDir * 300.0f * deltaTime;
  121. // Make sure paddle doesn't move off screen!
  122. if (mPaddlePos.y < (paddleH/2.0f + thickness))
  123. {
  124. mPaddlePos.y = paddleH/2.0f + thickness;
  125. }
  126. else if (mPaddlePos.y > (768.0f - paddleH/2.0f - thickness))
  127. {
  128. mPaddlePos.y = 768.0f - paddleH/2.0f - thickness;
  129. }
  130. }
  131. // Update ball position based on ball velocity
  132. mBallPos.x += mBallVel.x * deltaTime;
  133. mBallPos.y += mBallVel.y * deltaTime;
  134. // Bounce if needed
  135. // Did we intrsect with the paddle?
  136. float diff = mPaddlePos.y - mBallPos.y;
  137. diff = (diff > 0.0f) ? diff : -diff;
  138. if (mBallPos.x <= 25.0f && mBallPos.x >= 20.0f && diff <= paddleH/2.0f
  139. && mBallVel.x < 0.0f)
  140. {
  141. mBallVel.x *= -1.0f;
  142. }
  143. // Did the ball go off the screen? (if so, end game)
  144. else if (mBallPos.x <= 0.0f)
  145. {
  146. mIsRunning = false;
  147. }
  148. // Did the ball collide with the right wall?
  149. else if (mBallPos.x >= (1024.0f - thickness) && mBallVel.x > 0.0f)
  150. {
  151. mBallVel.x *= -1.0f;
  152. }
  153. // Did the ball collide with the top wall?
  154. if (mBallPos.y <= thickness && mBallVel.y < 0.0f)
  155. {
  156. mBallVel.y *= -1;
  157. }
  158. // Did the ball collide with the bottom wall?
  159. else if (mBallPos.y >= (768 - thickness) &&
  160. mBallVel.y > 0.0f)
  161. {
  162. mBallVel.y *= -1;
  163. }
  164. }
  165. void Game::GenerateOutput()
  166. {
  167. // Set draw color to blue
  168. SDL_SetRenderDrawColor(
  169. mRenderer,
  170. 0, // R
  171. 0, // G
  172. 255, // B
  173. 255 // A
  174. );
  175. // Clear back buffer
  176. SDL_RenderClear(mRenderer);
  177. // Draw walls
  178. SDL_SetRenderDrawColor(mRenderer, 255, 255, 255, 255);
  179. // Draw top wall
  180. SDL_Rect wall{
  181. 0, // Top left x
  182. 0, // Top left y
  183. 1024, // Width
  184. thickness // Height
  185. };
  186. SDL_RenderFillRect(mRenderer, &wall);
  187. // Draw bottom wall
  188. wall.y = 768 - thickness;
  189. SDL_RenderFillRect(mRenderer, &wall);
  190. // Draw right wall
  191. wall.x = 1024 - thickness;
  192. wall.y = 0;
  193. wall.w = thickness;
  194. wall.h = 1024;
  195. SDL_RenderFillRect(mRenderer, &wall);
  196. // Draw paddle
  197. SDL_Rect paddle{
  198. static_cast<int>(mPaddlePos.x),
  199. static_cast<int>(mPaddlePos.y - paddleH/2),
  200. thickness,
  201. static_cast<int>(paddleH)
  202. };
  203. SDL_RenderFillRect(mRenderer, &paddle);
  204. // Draw ball
  205. SDL_Rect ball{
  206. static_cast<int>(mBallPos.x - thickness/2),
  207. static_cast<int>(mBallPos.y - thickness/2),
  208. thickness,
  209. thickness
  210. };
  211. SDL_RenderFillRect(mRenderer, &ball);
  212. // Swap front buffer and back buffer
  213. SDL_RenderPresent(mRenderer);
  214. }
  215. void Game::Shutdown()
  216. {
  217. SDL_DestroyRenderer(mRenderer);
  218. SDL_DestroyWindow(mWindow);
  219. SDL_Quit();
  220. }