Advertisement
Guest User

Snake Clone

a guest
Sep 15th, 2017
226
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.37 KB | None | 0 0
  1. //main.cpp
  2. #define DEBUG /*Enable debugging*/
  3.  
  4. #include "GameManager.h"
  5.  
  6. #include <ctime> /*For time()*/
  7. const int BLOCK_SIZE = 10;
  8. const int SCREEN_WIDTH = 500;
  9. const int SCREEN_HEIGHT = 500;
  10.  
  11.  
  12. int main( int argc, char** argv )
  13. {
  14.     /*Set seed for random number generation*/
  15.     srand(static_cast<unsigned int>(time(0)));
  16.    
  17.     /*Call rand() once, because the first value isn't actually random*/
  18.     rand();
  19.    
  20.     GameManager game(SCREEN_WIDTH, SCREEN_HEIGHT, BLOCK_SIZE);
  21.    
  22.     game.mainLoop();
  23.  
  24.     return 0;
  25. }
  26. //snake.h
  27. #ifndef SNAKE_H
  28. #define SNAKE_H
  29.  
  30. #include "Coord.h" /*We will need this to store our snake*/
  31. #include "Random.h" /*For RandInt(min, max)*/
  32.  
  33. #include "SDL2\SDL.h" /*For SDL_Rect and rendering functions*/
  34. #undef main /*SDL does some nasty macro stuff to main*/
  35.  
  36. #include <vector> /*To store the entire snake*/
  37. #include <iostream> /*For overloaded output operator*/
  38.  
  39. enum Direction
  40. {
  41.     DIRECTION_UP,
  42.     DIRECTION_RIGHT,
  43.     DIRECTION_DOWN,
  44.     DIRECTION_LEFT,
  45.     DIRECTION_NONE
  46. };
  47.  
  48.  
  49. class Snake
  50. {
  51. private:
  52.     Coord m_head;
  53.     std::vector<Coord> m_snakeCoords;
  54.     static const int HEAD_INDEX = 0;
  55.     int m_size;
  56.    
  57.     int m_blockSize;
  58.    
  59. public:
  60.     Snake(int blockSize, SDL_Rect spawnArea); /*SpawnArea is required because we have no information on how big the grid is*/
  61.     #ifdef DEBUG
  62.     Snake();
  63.     #endif
  64.     friend std::ostream& operator<<(std::ostream &out, Snake &snake);
  65.     /*Access functions*/
  66.     Coord getHead();
  67.     Coord getCoord(int index);
  68.     int getSize();
  69.    
  70.     int getBlockSize();
  71.    
  72.     void move(int boardWidth, int boardHeight, Direction direction);
  73. };
  74.  
  75. #endif /*SNAKE_H defined*/
  76. //snake.cpp
  77. #include "Snake.h"
  78.  
  79. #ifdef DEBUG
  80. Snake::Snake() { }
  81. #endif
  82.  
  83. Snake::Snake(int blockSize, SDL_Rect spawnArea) : m_blockSize(blockSize)
  84. {
  85.     m_snakeCoords.resize(1); /*Make space to store the head of the snake*/
  86.    
  87.     /*We will multiply all coords by blockSize when rendering for simplicity, so now we have to divide by blockSize*/
  88.     int startX = RandInt(spawnArea.x / m_blockSize, spawnArea.x / m_blockSize + spawnArea.w / m_blockSize);
  89.     int startY = RandInt(spawnArea.y / m_blockSize, spawnArea.y / m_blockSize + spawnArea.h / m_blockSize);
  90.    
  91.     /*Create head struct*/
  92.     m_head.x = startX;
  93.     m_head.y = startY;
  94.    
  95.     /*Insert head at starting position of snakeCoords vector*/
  96.     m_snakeCoords.insert(m_snakeCoords.begin(), m_head);
  97.    
  98.     m_size = 1;
  99. }
  100.  
  101. /*Access functions*/
  102. Coord Snake::getHead() { return m_head; }
  103. Coord Snake::getCoord(int index) { return m_snakeCoords.at(index); }
  104. int Snake::getSize() { return m_size; }
  105. int Snake::getBlockSize() { return m_blockSize; }
  106.  
  107. void Snake::move(int boardWidth, int boardHeight, Direction direction)
  108. {
  109.     /*This won't work with the GameManager otherwise*/
  110.     boardWidth /= m_blockSize;
  111.     boardHeight /= m_blockSize;
  112.    
  113.     /*First, we insert a new block at the beginning of the snake, with the same coordinates as the previous head*/
  114.     m_snakeCoords.insert(m_snakeCoords.begin(), {m_head.x, m_head.y});
  115.    
  116.     /*Now, we increment or decrement the coordinates where needed, using the SDL Coordinate system:*/
  117.     /*
  118.     X 0 1 2 3
  119.     0 - - - -
  120.     1 - - - -
  121.     2 - - - -
  122.     3 - - - -
  123.     */
  124.    
  125.     switch(direction)
  126.     {
  127.         case DIRECTION_UP:
  128.             m_snakeCoords[HEAD_INDEX].y--;
  129.             break;
  130.         case DIRECTION_DOWN:
  131.             m_snakeCoords[HEAD_INDEX].y++;
  132.             break;
  133.         case DIRECTION_LEFT:
  134.             m_snakeCoords[HEAD_INDEX].x--;
  135.             break;
  136.         case DIRECTION_RIGHT:
  137.             m_snakeCoords[HEAD_INDEX].x++;
  138.             break;
  139.     }
  140.    
  141.     /*Next, we have to check if we moved out of the board*/
  142.    
  143.     //Up
  144.     if (m_snakeCoords[HEAD_INDEX].y < 0)
  145.     {
  146.         /*Move the head to the bottom of the screen*/
  147.         m_snakeCoords[HEAD_INDEX].y = boardHeight - 1;
  148.     }
  149.     /*Down*/
  150.     if (m_snakeCoords[HEAD_INDEX].y >= boardHeight)
  151.     {
  152.         /*Move the head to the top of the screen*/
  153.         m_snakeCoords[HEAD_INDEX].y = 0;
  154.     }
  155.     /*Left*/
  156.     if (m_snakeCoords[HEAD_INDEX].x < 0)
  157.     {
  158.         /*Move the head to the right of the screen*/
  159.         m_snakeCoords[HEAD_INDEX].x = boardWidth - 1;
  160.     }
  161.     /*Right*/
  162.     if (m_snakeCoords[HEAD_INDEX].x >= boardWidth)
  163.     {
  164.         /*Move the head to the left of the screen*/
  165.         m_snakeCoords[HEAD_INDEX].x = 0;
  166.     }
  167.    
  168.     /*Finally, we can assign m_head and remove the last element in the coord vector*/
  169.    
  170.     m_head = m_snakeCoords[HEAD_INDEX];
  171.     m_snakeCoords.pop_back();
  172.    
  173.     /* TODO (#1#): Collisions */
  174.    
  175. }
  176.  
  177. std::ostream& operator<<(std::ostream &out, Snake &snake)
  178. {
  179.     out << "Snake Info:\n";
  180.     out << "Size: " << snake.m_size << "\n";
  181.     out << "Head:\tx = " << snake.m_head.x << "\n";
  182.     out << "\ty = " << snake.m_head.y << "\n";
  183.    
  184.     return out;
  185. }
  186. //random.h
  187. #ifndef RANDOM_H
  188. #define RANDOM_H
  189.  
  190. #include <cstdlib>
  191. #include <ctime>
  192.  
  193. int RandInt(int min, int max);
  194.  
  195. #endif /*RANDOM_H defined*/
  196. //random.cpp
  197. #include "Random.h"
  198. int RandInt(int min, int max)
  199. {
  200.     static const double fraction = 1.0 / (static_cast<double>(RAND_MAX) + 1.0);  // static used for efficiency, so we only calculate this value once
  201.     // evenly distribute the random number across our range
  202.     return static_cast<int>(rand() * fraction * (max - min + 1) + min);
  203. }
  204. //coord.h
  205. #ifndef COORD_H
  206. #define COORD_H
  207.  
  208. struct Coord
  209. {
  210.     int x;
  211.     int y;
  212. };
  213.  
  214. #endif /*COORD_H defined*/
  215.  
  216. //debug.h
  217. #define DEBUG
  218.  
  219. #ifndef DEBUG_H
  220. #define DEBUG_H
  221.  
  222. #include "Snake.h"
  223.  
  224. #include <iostream>
  225.  
  226. /*Debugging class*/
  227.  
  228. class Debug
  229. {
  230. public:
  231.     void printSnakeInfo(Snake *snake);
  232.  
  233. };
  234.  
  235. #endif /*DEBUG_H defined*/
  236. //debug.cpp
  237. #include "Debug.h"
  238.  
  239.  
  240. void Debug::printSnakeInfo(Snake *snake)
  241. {
  242.     std::cout << *snake;
  243. }
  244.  
  245. //GameManger.h
  246. #ifndef GAMEMANAGER_H
  247. #define GAMEMANAGER_H
  248.  
  249. #include "Snake.h"
  250. #include "Debug.h"
  251. #include "RenderManager.h"
  252.  
  253. #include "SDL2\SDL.h"
  254.  
  255. class GameManager
  256. {
  257. private:
  258.     Snake* m_snake;
  259.     int m_width;
  260.     int m_height;
  261.     int m_blockSize;
  262.    
  263.     RenderManager *m_rendering;
  264.    
  265.     SDL_Window *m_window = nullptr;
  266.    
  267.     SDL_Surface *m_screenSurface = nullptr;
  268.    
  269.     SDL_Renderer *m_renderer;
  270.    
  271.     Direction getMoveDirection();
  272.     void moveSnake(Direction direction);   
  273.        
  274.     bool InitSDL();
  275.     void closeSDL();
  276.    
  277. public:
  278.     GameManager(int width, int height, int blockSize);
  279.     ~GameManager();
  280.     void mainLoop();
  281.     #ifdef DEBUG
  282.     void PrintSnakeInfo();
  283.     Debug d;
  284.     #endif
  285. };
  286.  
  287. #endif /*GAMEMANAGER_H defined*/
  288. //gamemanager.cpp
  289. #include "GameManager.h"
  290.  
  291. GameManager::GameManager(int width, int height, int blockSize) : m_width(width),
  292.                                                                  m_height(height),
  293.                                                                  m_blockSize(blockSize)
  294. {
  295.     /*Initialize Snake*/
  296.     m_snake = new Snake(blockSize, {0, 0, width, height});
  297.    
  298.     m_rendering = new RenderManager();
  299.    
  300.     bool success = InitSDL();
  301.     if (!success)
  302.     {
  303.         std::cerr << "Error while creating window... Shutting down.\n";
  304.         exit(-1);
  305.     }
  306. }
  307.  
  308. GameManager::~GameManager()
  309. {
  310.     closeSDL();
  311.    
  312.     delete m_snake;
  313. }
  314.  
  315. std::istream& operator>>(std::istream &in, Direction &dir)
  316. {
  317.     std::cout << "Enter a direction (Up, Down, Left, Right): ";
  318.     std::string direction;
  319.    
  320.     std::cin >> direction;
  321.     if (direction == "Up")
  322.         dir = DIRECTION_UP;
  323.     else if (direction == "Down")
  324.         dir = DIRECTION_DOWN;
  325.     else if (direction == "Left")
  326.         dir = DIRECTION_LEFT;
  327.     else if (direction == "Right")
  328.         dir = DIRECTION_RIGHT;
  329.     else dir = DIRECTION_NONE;
  330.    
  331.    
  332.     return in;
  333. }
  334.  
  335. Direction GameManager::getMoveDirection()
  336. {
  337.     /*Temporary implementation, this will be using SDL events*/
  338.     Direction direction;
  339.     std::cin >> direction;
  340.    
  341.     return direction;
  342. }
  343.  
  344. void GameManager::moveSnake(Direction direction)
  345. {
  346.     m_snake->move(m_width, m_height, direction);
  347. }
  348.  
  349. #ifdef DEBUG
  350. void GameManager::PrintSnakeInfo()
  351. {
  352.     d.printSnakeInfo(m_snake);
  353. }
  354. #endif
  355.  
  356. bool GameManager::InitSDL()
  357. {
  358.     bool success = true;
  359.  
  360.     if (SDL_Init(SDL_INIT_VIDEO) < 0)
  361.     {
  362.         std::cerr << "Failed to initialize SDL. SDL Error: " << SDL_GetError();
  363.         success = false;
  364.     }
  365.     else
  366.     {
  367.         m_window = SDL_CreateWindow("Snake Game",
  368.                                   SDL_WINDOWPOS_UNDEFINED,
  369.                                   SDL_WINDOWPOS_UNDEFINED,
  370.                                   m_width,
  371.                                   m_height,
  372.                                   SDL_WINDOW_SHOWN);
  373.         if (m_window == nullptr)
  374.         {
  375.             std::cerr << "Failed to create SDL window. SDL Error: " << SDL_GetError();
  376.             success = false;
  377.         }
  378.         else
  379.         {
  380.             m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED);
  381.             if (m_renderer == nullptr)
  382.             {
  383.                 std::cerr << "Failed to create SDL Renderer. SDL Error: " << SDL_GetError();
  384.                 success = false;
  385.             }
  386.             else
  387.             {
  388.                 SDL_SetRenderDrawColor(m_renderer, 0xFF, 0xFF, 0xFF, 0xFF);
  389.                
  390.                 m_screenSurface = SDL_GetWindowSurface(m_window);
  391.             }
  392.         }
  393.  
  394.     }
  395.     return success;
  396. }
  397.  
  398. void GameManager::closeSDL()
  399. {
  400.     SDL_FreeSurface(m_screenSurface);
  401.     m_screenSurface = nullptr;
  402.  
  403.     SDL_DestroyWindow(m_window);
  404.     m_window = nullptr;
  405.  
  406.     SDL_Quit();
  407. }
  408.  
  409. void GameManager::mainLoop()
  410. {
  411.     SDL_Event e;
  412.  
  413.     bool quit = false;
  414.     while (!quit)
  415.     {
  416.         while(SDL_PollEvent(&e))
  417.         {
  418.             if (e.type == SDL_QUIT)
  419.             {
  420.                 quit = true;
  421.             }
  422.         }
  423.        
  424.         Direction dir = getMoveDirection();
  425.         moveSnake(dir);
  426.         #ifdef DEBUG
  427.         PrintSnakeInfo();
  428.         #endif
  429.                
  430.         SDL_RenderClear(m_renderer);
  431.        
  432.         SDL_SetRenderDrawColor(m_renderer, 0xFF, 0xFF, 0xFF, 0xFF);
  433.        
  434.         m_rendering->renderSnake(m_snake, m_renderer);
  435.  
  436.         SDL_RenderPresent(m_renderer);
  437.     }
  438. }
  439. //rendermanager.h
  440. #ifndef RENDERMANAGER_H
  441. #define RENDERMANAGER_H
  442.  
  443. #include "SDL2\SDL.h"
  444. #undef main
  445.  
  446. #include "Snake.h"
  447.  
  448.  
  449. class RenderManager
  450. {
  451. private:
  452. //  SDL_Renderer* m_renderer;
  453. //  SDL_Window *m_window;
  454. public:
  455. //  RenderManager(SDL_Renderer *renderer, SDL_Window *window);
  456.     void renderSquare(int x, int y, int size, SDL_Color color, SDL_Renderer *renderer);
  457.    
  458.     void renderSnake(Snake *snake, SDL_Renderer *renderer);
  459. };
  460.  
  461. #endif /*RENDERMANAGER_H defined*/
  462. //rendermanager.cpp
  463. #include "RenderManager.h"
  464.  
  465. //RenderManager::RenderManager(SDL_Renderer *renderer, SDL_Window *window)
  466. //{
  467. //  m_renderer = renderer;
  468. //  m_window = window;
  469. //}
  470.  
  471. void RenderManager::renderSquare(int x, int y, int size, SDL_Color color, SDL_Renderer *renderer)
  472. {
  473.     SDL_Rect square = {x, y, size, size};
  474.     SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); /*CRASH -> FIXED :)*/
  475.    
  476.     SDL_RenderFillRect(renderer, &square);
  477.    
  478.     SDL_RenderPresent(renderer);
  479. }
  480.  
  481. void RenderManager::renderSnake(Snake *snake, SDL_Renderer *renderer)
  482. {
  483.     for (int i = 0; i < snake->getSize(); ++i)
  484.     {
  485.         renderSquare(snake->getCoord(i).x * snake->getBlockSize() + 1,
  486.                      snake->getCoord(i).y * snake->getBlockSize() + 1,
  487.                      snake->getBlockSize(),
  488.                     {0x00, 0x00, 0xFF, 0xFF},
  489.                     renderer);
  490.     }
  491. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement