2
0

Game.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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 intersect with the paddle?
  136. float diff = mPaddlePos.y - mBallPos.y;
  137. // Take absolute value of difference
  138. diff = (diff > 0.0f) ? diff : -diff;
  139. if (
  140. // Our y-difference is small enough
  141. diff <= paddleH / 2.0f &&
  142. // We are in the correct x-position
  143. mBallPos.x <= 25.0f && mBallPos.x >= 20.0f &&
  144. // The ball is moving to the left
  145. mBallVel.x < 0.0f)
  146. {
  147. mBallVel.x *= -1.0f;
  148. }
  149. // Did the ball go off the screen? (if so, end game)
  150. else if (mBallPos.x <= 0.0f)
  151. {
  152. mIsRunning = false;
  153. }
  154. // Did the ball collide with the right wall?
  155. else if (mBallPos.x >= (1024.0f - thickness) && mBallVel.x > 0.0f)
  156. {
  157. mBallVel.x *= -1.0f;
  158. }
  159. // Did the ball collide with the top wall?
  160. if (mBallPos.y <= thickness && mBallVel.y < 0.0f)
  161. {
  162. mBallVel.y *= -1;
  163. }
  164. // Did the ball collide with the bottom wall?
  165. else if (mBallPos.y >= (768 - thickness) &&
  166. mBallVel.y > 0.0f)
  167. {
  168. mBallVel.y *= -1;
  169. }
  170. }
  171. void Game::GenerateOutput()
  172. {
  173. // Set draw color to blue
  174. SDL_SetRenderDrawColor(
  175. mRenderer,
  176. 0, // R
  177. 0, // G
  178. 255, // B
  179. 255 // A
  180. );
  181. // Clear back buffer
  182. SDL_RenderClear(mRenderer);
  183. // Draw walls
  184. SDL_SetRenderDrawColor(mRenderer, 255, 255, 255, 255);
  185. // Draw top wall
  186. SDL_Rect wall{
  187. 0, // Top left x
  188. 0, // Top left y
  189. 1024, // Width
  190. thickness // Height
  191. };
  192. SDL_RenderFillRect(mRenderer, &wall);
  193. // Draw bottom wall
  194. wall.y = 768 - thickness;
  195. SDL_RenderFillRect(mRenderer, &wall);
  196. // Draw right wall
  197. wall.x = 1024 - thickness;
  198. wall.y = 0;
  199. wall.w = thickness;
  200. wall.h = 1024;
  201. SDL_RenderFillRect(mRenderer, &wall);
  202. // Draw paddle
  203. SDL_Rect paddle{
  204. static_cast<int>(mPaddlePos.x),
  205. static_cast<int>(mPaddlePos.y - paddleH/2),
  206. thickness,
  207. static_cast<int>(paddleH)
  208. };
  209. SDL_RenderFillRect(mRenderer, &paddle);
  210. // Draw ball
  211. SDL_Rect ball{
  212. static_cast<int>(mBallPos.x - thickness/2),
  213. static_cast<int>(mBallPos.y - thickness/2),
  214. thickness,
  215. thickness
  216. };
  217. SDL_RenderFillRect(mRenderer, &ball);
  218. // Swap front buffer and back buffer
  219. SDL_RenderPresent(mRenderer);
  220. }
  221. void Game::Shutdown()
  222. {
  223. SDL_DestroyRenderer(mRenderer);
  224. SDL_DestroyWindow(mWindow);
  225. SDL_Quit();
  226. }