Game.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. #include <algorithm>
  10. #include "Renderer.h"
  11. #include "AudioSystem.h"
  12. #include "Actor.h"
  13. #include "SpriteComponent.h"
  14. #include "MeshComponent.h"
  15. #include "CameraActor.h"
  16. #include "PlaneActor.h"
  17. #include "AudioComponent.h"
  18. Game::Game()
  19. :mRenderer(nullptr)
  20. ,mIsRunning(true)
  21. ,mUpdatingActors(false)
  22. {
  23. }
  24. bool Game::Initialize()
  25. {
  26. if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0)
  27. {
  28. SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
  29. return false;
  30. }
  31. // Create the renderer
  32. mRenderer = new Renderer(this);
  33. if (!mRenderer->Initialize(1024.0f, 768.0f))
  34. {
  35. SDL_Log("Failed to initialize renderer");
  36. delete mRenderer;
  37. mRenderer = nullptr;
  38. return false;
  39. }
  40. // Create the audio system
  41. mAudioSystem = new AudioSystem(this);
  42. if (!mAudioSystem->Initialize())
  43. {
  44. SDL_Log("Failed to initialize audio system");
  45. mAudioSystem->Shutdown();
  46. delete mAudioSystem;
  47. mAudioSystem = nullptr;
  48. return false;
  49. }
  50. LoadData();
  51. mTicksCount = SDL_GetTicks();
  52. return true;
  53. }
  54. void Game::RunLoop()
  55. {
  56. while (mIsRunning)
  57. {
  58. ProcessInput();
  59. UpdateGame();
  60. GenerateOutput();
  61. }
  62. }
  63. void Game::ProcessInput()
  64. {
  65. SDL_Event event;
  66. while (SDL_PollEvent(&event))
  67. {
  68. switch (event.type)
  69. {
  70. case SDL_QUIT:
  71. mIsRunning = false;
  72. break;
  73. // This fires when a key's initially pressed
  74. case SDL_KEYDOWN:
  75. if (!event.key.repeat)
  76. {
  77. HandleKeyPress(event.key.keysym.sym);
  78. }
  79. break;
  80. default:
  81. break;
  82. }
  83. }
  84. const Uint8* state = SDL_GetKeyboardState(NULL);
  85. if (state[SDL_SCANCODE_ESCAPE])
  86. {
  87. mIsRunning = false;
  88. }
  89. for (auto actor : mActors)
  90. {
  91. actor->ProcessInput(state);
  92. }
  93. }
  94. void Game::HandleKeyPress(int key)
  95. {
  96. switch (key)
  97. {
  98. case '-':
  99. {
  100. // Reduce master volume
  101. float volume = mAudioSystem->GetBusVolume("bus:/");
  102. volume = Math::Max(0.0f, volume - 0.1f);
  103. mAudioSystem->SetBusVolume("bus:/", volume);
  104. break;
  105. }
  106. case '=':
  107. {
  108. // Increase master volume
  109. float volume = mAudioSystem->GetBusVolume("bus:/");
  110. volume = Math::Min(1.0f, volume + 0.1f);
  111. mAudioSystem->SetBusVolume("bus:/", volume);
  112. break;
  113. }
  114. case 'e':
  115. // Play explosion
  116. mAudioSystem->PlayEvent("event:/Explosion2D");
  117. break;
  118. case 'm':
  119. // Toggle music pause state
  120. mMusicEvent.SetPaused(!mMusicEvent.GetPaused());
  121. break;
  122. case 'r':
  123. // Stop or start reverb snapshot
  124. if (!mReverbSnap.IsValid())
  125. {
  126. mReverbSnap = mAudioSystem->PlayEvent("snapshot:/WithReverb");
  127. }
  128. else
  129. {
  130. mReverbSnap.Stop();
  131. }
  132. break;
  133. case '1':
  134. // Set default footstep surface
  135. mCameraActor->SetFootstepSurface(0.0f);
  136. break;
  137. case '2':
  138. // Set grass footstep surface
  139. mCameraActor->SetFootstepSurface(0.5f);
  140. break;
  141. default:
  142. break;
  143. }
  144. }
  145. void Game::UpdateGame()
  146. {
  147. // Compute delta time
  148. // Wait until 16ms has elapsed since last frame
  149. while (!SDL_TICKS_PASSED(SDL_GetTicks(), mTicksCount + 16))
  150. ;
  151. float deltaTime = (SDL_GetTicks() - mTicksCount) / 1000.0f;
  152. if (deltaTime > 0.05f)
  153. {
  154. deltaTime = 0.05f;
  155. }
  156. mTicksCount = SDL_GetTicks();
  157. // Update all actors
  158. mUpdatingActors = true;
  159. for (auto actor : mActors)
  160. {
  161. actor->Update(deltaTime);
  162. }
  163. mUpdatingActors = false;
  164. // Move any pending actors to mActors
  165. for (auto pending : mPendingActors)
  166. {
  167. pending->ComputeWorldTransform();
  168. mActors.emplace_back(pending);
  169. }
  170. mPendingActors.clear();
  171. // Add any dead actors to a temp vector
  172. std::vector<Actor*> deadActors;
  173. for (auto actor : mActors)
  174. {
  175. if (actor->GetState() == Actor::EDead)
  176. {
  177. deadActors.emplace_back(actor);
  178. }
  179. }
  180. // Delete dead actors (which removes them from mActors)
  181. for (auto actor : deadActors)
  182. {
  183. delete actor;
  184. }
  185. // Update audio system
  186. mAudioSystem->Update(deltaTime);
  187. }
  188. void Game::GenerateOutput()
  189. {
  190. mRenderer->Draw();
  191. }
  192. void Game::LoadData()
  193. {
  194. // Create actors
  195. Actor* a = new Actor(this);
  196. a->SetPosition(Vector3(200.0f, 75.0f, 0.0f));
  197. a->SetScale(100.0f);
  198. Quaternion q(Vector3::UnitY, -Math::PiOver2);
  199. q = Quaternion::Concatenate(q, Quaternion(Vector3::UnitZ, Math::Pi + Math::Pi / 4.0f));
  200. a->SetRotation(q);
  201. MeshComponent* mc = new MeshComponent(a);
  202. mc->SetMesh(mRenderer->GetMesh("Assets/Cube.gpmesh"));
  203. a = new Actor(this);
  204. a->SetPosition(Vector3(200.0f, -75.0f, 0.0f));
  205. a->SetScale(3.0f);
  206. mc = new MeshComponent(a);
  207. mc->SetMesh(mRenderer->GetMesh("Assets/Sphere.gpmesh"));
  208. // Setup floor
  209. const float start = -1250.0f;
  210. const float size = 250.0f;
  211. for (int i = 0; i < 10; i++)
  212. {
  213. for (int j = 0; j < 10; j++)
  214. {
  215. a = new PlaneActor(this);
  216. a->SetPosition(Vector3(start + i * size, start + j * size, -100.0f));
  217. }
  218. }
  219. // Left/right walls
  220. q = Quaternion(Vector3::UnitX, Math::PiOver2);
  221. for (int i = 0; i < 10; i++)
  222. {
  223. a = new PlaneActor(this);
  224. a->SetPosition(Vector3(start + i * size, start - size, 0.0f));
  225. a->SetRotation(q);
  226. a = new PlaneActor(this);
  227. a->SetPosition(Vector3(start + i * size, -start + size, 0.0f));
  228. a->SetRotation(q);
  229. }
  230. q = Quaternion::Concatenate(q, Quaternion(Vector3::UnitZ, Math::PiOver2));
  231. // Forward/back walls
  232. for (int i = 0; i < 10; i++)
  233. {
  234. a = new PlaneActor(this);
  235. a->SetPosition(Vector3(start - size, start + i * size, 0.0f));
  236. a->SetRotation(q);
  237. a = new PlaneActor(this);
  238. a->SetPosition(Vector3(-start + size, start + i * size, 0.0f));
  239. a->SetRotation(q);
  240. }
  241. // Setup lights
  242. mRenderer->SetAmbientLight(Vector3(0.2f, 0.2f, 0.2f));
  243. DirectionalLight& dir = mRenderer->GetDirectionalLight();
  244. dir.mDirection = Vector3(0.0f, -0.707f, -0.707f);
  245. dir.mDiffuseColor = Vector3(0.78f, 0.88f, 1.0f);
  246. dir.mSpecColor = Vector3(0.8f, 0.8f, 0.8f);
  247. // Camera actor
  248. mCameraActor = new CameraActor(this);
  249. // UI elements
  250. a = new Actor(this);
  251. a->SetPosition(Vector3(-350.0f, -350.0f, 0.0f));
  252. SpriteComponent* sc = new SpriteComponent(a);
  253. sc->SetTexture(mRenderer->GetTexture("Assets/HealthBar.png"));
  254. a = new Actor(this);
  255. a->SetPosition(Vector3(375.0f, -275.0f, 0.0f));
  256. a->SetScale(0.75f);
  257. sc = new SpriteComponent(a);
  258. sc->SetTexture(mRenderer->GetTexture("Assets/Radar.png"));
  259. // Create spheres with audio components playing different sounds
  260. a = new Actor(this);
  261. a->SetPosition(Vector3(500.0f, -75.0f, 0.0f));
  262. a->SetScale(1.0f);
  263. mc = new MeshComponent(a);
  264. mc->SetMesh(mRenderer->GetMesh("Assets/Sphere.gpmesh"));
  265. AudioComponent* ac = new AudioComponent(a);
  266. ac->PlayEvent("event:/FireLoop");
  267. // Start music
  268. mMusicEvent = mAudioSystem->PlayEvent("event:/Music");
  269. }
  270. void Game::UnloadData()
  271. {
  272. // Delete actors
  273. // Because ~Actor calls RemoveActor, have to use a different style loop
  274. while (!mActors.empty())
  275. {
  276. delete mActors.back();
  277. }
  278. if (mRenderer)
  279. {
  280. mRenderer->UnloadData();
  281. }
  282. }
  283. void Game::Shutdown()
  284. {
  285. UnloadData();
  286. if (mRenderer)
  287. {
  288. mRenderer->Shutdown();
  289. }
  290. if (mAudioSystem)
  291. {
  292. mAudioSystem->Shutdown();
  293. }
  294. SDL_Quit();
  295. }
  296. void Game::AddActor(Actor* actor)
  297. {
  298. // If we're updating actors, need to add to pending
  299. if (mUpdatingActors)
  300. {
  301. mPendingActors.emplace_back(actor);
  302. }
  303. else
  304. {
  305. mActors.emplace_back(actor);
  306. }
  307. }
  308. void Game::RemoveActor(Actor* actor)
  309. {
  310. // Is it in pending actors?
  311. auto iter = std::find(mPendingActors.begin(), mPendingActors.end(), actor);
  312. if (iter != mPendingActors.end())
  313. {
  314. // Swap to end of vector and pop off (avoid erase copies)
  315. std::iter_swap(iter, mPendingActors.end() - 1);
  316. mPendingActors.pop_back();
  317. }
  318. // Is it in actors?
  319. iter = std::find(mActors.begin(), mActors.end(), actor);
  320. if (iter != mActors.end())
  321. {
  322. // Swap to end of vector and pop off (avoid erase copies)
  323. std::iter_swap(iter, mActors.end() - 1);
  324. mActors.pop_back();
  325. }
  326. }