/SDL2.cpp

https://bitbucket.org/sasiedu/nibbler · C++ · 181 lines · 146 code · 35 blank · 0 comment · 20 complexity · 54526070feaf975a5ff70204efc1855f MD5 · raw file

  1. #include "SDL2.hpp"
  2. SDL2::Colour SDL2::Colours::WHITE = { 0xFF, 0xFF, 0xFF, 0xFF };
  3. SDL2::Colour SDL2::Colours::BLACK = { 0x00, 0x00, 0x00, 0xFF };
  4. SDL2::Colour SDL2::Colours::RED = { 0xFF, 0x00, 0x00, 0xFF };
  5. SDL2::Colour SDL2::Colours::BLUE = { 0x00, 0x00, 0xFF, 0xFF };
  6. SDL2::Colour SDL2::Colours::YELLOW = { 0xFF, 0xFF, 0x00, 0xFF };
  7. SDL2::Colour SDL2::Colours::MAGENTA = { 0x8B, 0x00, 0x8B, 0xFF };
  8. SDL2::SDL2(Env &env) {
  9. this->_env = env;
  10. this->_env.switches.window.width *= SDL2::PIXEL_MULTIPLIER;
  11. this->_env.switches.window.height *= SDL2::PIXEL_MULTIPLIER;
  12. if (SDL_Init(SDL_INIT_VIDEO)) {
  13. throw std::runtime_error("Could not init video");
  14. }
  15. if (TTF_Init()) {
  16. throw std::runtime_error("Could not init font");
  17. }
  18. this->_window = SDL_CreateWindow("Snek", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
  19. this->_env.switches.window.width + SDL2::PIXEL_MULTIPLIER, this->_env.switches.window.height + SDL2::PIXEL_MULTIPLIER, SDL_WINDOW_SHOWN);
  20. if (this->_window == nullptr) {
  21. throw std::runtime_error("Could not create SDL2 window");
  22. }
  23. this->_renderer = SDL_CreateRenderer(this->_window, -1, SDL_RENDERER_ACCELERATED);
  24. if (this->_renderer == nullptr) {
  25. throw std::runtime_error("Could not create renderer");
  26. }
  27. this->_font = TTF_OpenFont("/System/Library/Fonts/Monaco.dfont", SDL2::PIXEL_MULTIPLIER);
  28. if (this->_font == nullptr) {
  29. throw std::runtime_error("Could not open font");
  30. }
  31. }
  32. SDL2::~SDL2() {
  33. SDL_DestroyRenderer(this->_renderer);
  34. SDL_DestroyWindow(this->_window);
  35. TTF_CloseFont(this->_font);
  36. this->_renderer = nullptr;
  37. this->_window = nullptr;
  38. this->_font = nullptr;
  39. }
  40. void SDL2::draw() {
  41. this->_drawWalls(); //No clear because drawWalls clears the screen
  42. this->_drawSnake();
  43. this->_drawFood();
  44. this->_drawScore();
  45. SDL_RenderPresent(this->_renderer);
  46. }
  47. Display::Key SDL2::getKey() {
  48. SDL_Event event;
  49. while (SDL_PollEvent(&event)) {
  50. if (event.type == SDL_QUIT) {
  51. return Display::Key::QUIT;
  52. } else if (event.type == SDL_KEYDOWN && event.key.repeat == 0) {
  53. switch(event.key.keysym.sym) {
  54. case SDLK_SPACE:
  55. return Display::Key::SPACE;
  56. case SDLK_p:
  57. return Display::Key::P;
  58. case SDLK_q:
  59. return Display::Key::Q;
  60. case SDLK_x:
  61. return Display::Key::X;
  62. case SDLK_UP:
  63. this->_keyBuff.push(Display::Key::UP);
  64. return Display::Key::UP;
  65. case SDLK_LEFT:
  66. this->_keyBuff.push(Display::Key::LEFT);
  67. return Display::Key::LEFT;
  68. case SDLK_DOWN:
  69. this->_keyBuff.push(Display::Key::DOWN);
  70. return Display::Key::DOWN;
  71. case SDLK_RIGHT:
  72. this->_keyBuff.push(Display::Key::RIGHT);
  73. return Display::Key::RIGHT;
  74. case SDLK_1:
  75. return Display::Key::ONE;
  76. case SDLK_2:
  77. return Display::Key::TWO;
  78. case SDLK_3:
  79. return Display::Key::THREE;
  80. default:
  81. return Display::Key::NONE;
  82. }
  83. }
  84. }
  85. return Display::Key::NONE;
  86. }
  87. SDL_Rect createPixel(unsigned x, unsigned y) {
  88. return {
  89. static_cast<int>(x * SDL2::PIXEL_MULTIPLIER),
  90. static_cast<int>(y * SDL2::PIXEL_MULTIPLIER),
  91. static_cast<int>(SDL2::PIXEL_MULTIPLIER),
  92. static_cast<int>(SDL2::PIXEL_MULTIPLIER)
  93. };
  94. }
  95. void SDL2::_drawSnake() {
  96. auto pieces = this->_env.snake->getPieces();
  97. auto it = pieces.begin();
  98. auto length = pieces.size() - 1;
  99. SDL_Rect body[length];
  100. SDL2::SDL_SetRenderDrawColor(SDL2::Colours::RED);
  101. SDL_Rect head = createPixel(it->x, it->y);
  102. SDL_RenderFillRect(this->_renderer, &head);
  103. it++;
  104. for (unsigned i = 0; i < length; i++) {
  105. SDL2::SDL_SetRenderDrawColor(SDL2::Colours::YELLOW);
  106. body[i] = createPixel(it->x, it->y);
  107. it++;
  108. }
  109. SDL_RenderFillRects(this->_renderer, body, static_cast<int>(length));
  110. }
  111. void SDL2::_drawWalls() {
  112. SDL2::SDL_SetRenderDrawColor(SDL2::Colours::BLUE);
  113. SDL_RenderClear(this->_renderer);
  114. SDL2::SDL_SetRenderDrawColor(SDL2::Colours::BLACK);
  115. SDL_Rect background = {SDL2::PIXEL_MULTIPLIER, SDL2::PIXEL_MULTIPLIER,
  116. static_cast<int>(this->_env.switches.window.width - SDL2::PIXEL_MULTIPLIER),
  117. static_cast<int>(this->_env.switches.window.height - SDL2::PIXEL_MULTIPLIER)};
  118. SDL_RenderFillRect(this->_renderer, &background);
  119. }
  120. void SDL2::_drawFood() {
  121. SDL2::SDL_SetRenderDrawColor(SDL2::Colours::MAGENTA);
  122. SDL_Rect food = createPixel(this->_env.food->pos.x, this->_env.food->pos.y);
  123. SDL_RenderFillRect(this->_renderer, &food);
  124. }
  125. void SDL2::_drawScore() {
  126. SDL2::SDL_SetRenderDrawColor(SDL2::Colours::WHITE);
  127. std::string score = "Score: " + std::to_string(this->score());
  128. SDL_Surface *scoreText = TTF_RenderText_Blended(this->_font, score.c_str(), { 0xFF, 0xFF, 0xFF });
  129. SDL_Texture *scoreTexture = SDL_CreateTextureFromSurface(this->_renderer, scoreText);
  130. SDL_Rect position = { 0, 0, scoreText->w, scoreText->h };
  131. SDL_RenderCopy(this->_renderer, scoreTexture, NULL, &position);
  132. SDL_FreeSurface(scoreText);
  133. SDL_DestroyTexture(scoreTexture);
  134. }
  135. int SDL2::SDL_SetRenderDrawColor(struct SDL2::Colour colour) {
  136. return ::SDL_SetRenderDrawColor(this->_renderer, colour.R, colour.G, colour.B, colour.A);
  137. }
  138. Display *createDisplay(Env &env) {
  139. Display *newDisplay = new SDL2(env);
  140. newDisplay->draw();
  141. return newDisplay;
  142. }
  143. void destroyDisplay(Display *display) {
  144. if (display != nullptr)
  145. delete display;
  146. }