Advertisement
alien_fx_fiend

2D Snake Game Win32

Jul 26th, 2024
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.32 KB | None | 0 0
  1. #include <windows.h>
  2. #include <vector>
  3. #include <ctime>
  4. #include <cstdlib>
  5.  
  6. #define WINDOW_WIDTH 800
  7. #define WINDOW_HEIGHT 600
  8. #define GRID_SIZE 20
  9. #define SNAKE_INITIAL_LENGTH 5
  10. #define MOVE_INTERVAL 100
  11.  
  12. enum Direction { UP, DOWN, LEFT, RIGHT };
  13.  
  14. struct Point {
  15.     int x, y;
  16.     Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
  17. };
  18.  
  19. class Snake {
  20. private:
  21.     std::vector<Point> body;
  22.     Direction currentDirection;
  23.     Direction nextDirection;
  24.     bool growing;
  25.  
  26. public:
  27.     Snake() : currentDirection(RIGHT), nextDirection(RIGHT), growing(false) {
  28.         for (int i = 0; i < SNAKE_INITIAL_LENGTH; ++i) {
  29.             body.push_back(Point(5 - i, 5));
  30.         }
  31.     }
  32.  
  33.     void move() {
  34.         currentDirection = nextDirection;
  35.         Point newHead = body.front();
  36.         switch (currentDirection) {
  37.         case UP: newHead.y--; break;
  38.         case DOWN: newHead.y++; break;
  39.         case LEFT: newHead.x--; break;
  40.         case RIGHT: newHead.x++; break;
  41.         }
  42.  
  43.         // Ensure the snake wraps around the window area
  44.         newHead.x = (newHead.x + (WINDOW_WIDTH / GRID_SIZE)) % (WINDOW_WIDTH / GRID_SIZE);
  45.         newHead.y = (newHead.y + (WINDOW_HEIGHT / GRID_SIZE)) % (WINDOW_HEIGHT / GRID_SIZE);
  46.  
  47.         body.insert(body.begin(), newHead);
  48.         if (!growing) {
  49.             body.pop_back();
  50.         }
  51.         growing = false;
  52.     }
  53.  
  54.  
  55.  
  56.     void grow() { growing = true; }
  57.  
  58.     void setDirection(Direction dir) {
  59.         if ((dir == UP || dir == DOWN) && (currentDirection == LEFT || currentDirection == RIGHT)) {
  60.             nextDirection = dir;
  61.         }
  62.         else if ((dir == LEFT || dir == RIGHT) && (currentDirection == UP || currentDirection == DOWN)) {
  63.             nextDirection = dir;
  64.         }
  65.     }
  66.  
  67.     bool checkCollision() const {
  68.         for (size_t i = 1; i < body.size(); ++i) {
  69.             if (body[0].x == body[i].x && body[0].y == body[i].y) {
  70.                 return true;
  71.             }
  72.         }
  73.         return false;
  74.     }
  75.  
  76.     const std::vector<Point>& getBody() const { return body; }
  77. };
  78.  
  79. class Game {
  80. private:
  81.     Snake snake;
  82.     Point food;
  83.     bool gameOver;
  84.     bool paused;
  85.     int score;
  86.  
  87.     HWND hwnd;
  88.     HDC hdc, memDC;
  89.     HBITMAP memBitmap;
  90.     HBRUSH snakeBrush, foodBrush, backgroundBrush;
  91.  
  92. public:
  93.     Game(HWND hWnd) : hwnd(hWnd), gameOver(false), paused(true), score(0) {
  94.         srand(static_cast<unsigned>(time(nullptr)));
  95.         spawnFood();
  96.  
  97.         hdc = GetDC(hwnd);
  98.         memDC = CreateCompatibleDC(hdc);
  99.         memBitmap = CreateCompatibleBitmap(hdc, WINDOW_WIDTH, WINDOW_HEIGHT);
  100.         SelectObject(memDC, memBitmap);
  101.  
  102.         snakeBrush = CreateSolidBrush(RGB(255, 0, 0));
  103.         foodBrush = CreateSolidBrush(RGB(255, 0, 0));
  104.         backgroundBrush = CreateSolidBrush(RGB(0, 0, 0));
  105.     }
  106.  
  107.     ~Game() {
  108.         DeleteObject(snakeBrush);
  109.         DeleteObject(foodBrush);
  110.         DeleteObject(backgroundBrush);
  111.         DeleteObject(memBitmap);
  112.         DeleteDC(memDC);
  113.         ReleaseDC(hwnd, hdc);
  114.     }
  115.  
  116.     void spawnFood() {
  117.         int gridWidth = WINDOW_WIDTH / GRID_SIZE;
  118.         int gridHeight = WINDOW_HEIGHT / GRID_SIZE;
  119.         do {
  120.             food.x = rand() % gridWidth;
  121.             food.y = rand() % gridHeight;
  122.         } while (isSnakeOnPoint(food));
  123.     }
  124.  
  125.  
  126.     bool isSnakeOnPoint(const Point& p) const {
  127.         for (const auto& segment : snake.getBody()) {
  128.             if (segment.x == p.x && segment.y == p.y) {
  129.                 return true;
  130.             }
  131.         }
  132.         return false;
  133.     }
  134.  
  135.     void update() {
  136.         if (gameOver || paused) return;
  137.  
  138.         snake.move();
  139.  
  140.         if (snake.checkCollision()) {
  141.             gameOver = true;
  142.             return;
  143.         }
  144.  
  145.         if (snake.getBody().front().x == food.x && snake.getBody().front().y == food.y) {
  146.             snake.grow();
  147.             do {
  148.                 spawnFood();
  149.             } while (isSnakeOnPoint(food));
  150.             score++;
  151.         }
  152.     }
  153.  
  154.     void render() {
  155.         RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
  156.         FillRect(memDC, &rect, backgroundBrush);
  157.  
  158.         for (const auto& segment : snake.getBody()) {
  159.             RECT snakeRect = {
  160.                 segment.x * GRID_SIZE,
  161.                 segment.y * GRID_SIZE,
  162.                 (segment.x + 1) * GRID_SIZE,
  163.                 (segment.y + 1) * GRID_SIZE
  164.             };
  165.             FillRect(memDC, &snakeRect, snakeBrush);
  166.         }
  167.  
  168.         if (food.x >= 0 && food.y >= 0) { // Check for valid food position
  169.             RECT foodRect = {
  170.                 food.x * GRID_SIZE,
  171.                 food.y * GRID_SIZE,
  172.                 (food.x + 1) * GRID_SIZE,
  173.                 (food.y + 1) * GRID_SIZE
  174.             };
  175.             FillRect(memDC, &foodRect, foodBrush);
  176.         }
  177.  
  178.         WCHAR scoreText[32];
  179.         swprintf_s(scoreText, L"Score: %d", score);
  180.         SetBkMode(memDC, TRANSPARENT);
  181.         SetTextColor(memDC, RGB(255, 255, 255));
  182.         TextOut(memDC, 10, 10, scoreText, wcslen(scoreText));
  183.  
  184.         if (gameOver) {
  185.             const WCHAR* gameOverText = L"Game Over! Press any arrow key to restart.";
  186.             TextOut(memDC, WINDOW_WIDTH / 2 - 150, WINDOW_HEIGHT / 2, gameOverText, wcslen(gameOverText));
  187.         }
  188.         else if (paused) {
  189.             const WCHAR* pausedText = L"Paused. Press any arrow key to start.";
  190.             TextOut(memDC, WINDOW_WIDTH / 2 - 120, WINDOW_HEIGHT / 2, pausedText, wcslen(pausedText));
  191.         }
  192.  
  193.         BitBlt(hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, memDC, 0, 0, SRCCOPY);
  194.     }
  195.  
  196.     void togglePause() {
  197.         paused = !paused;
  198.     }
  199.  
  200.     void reset() {
  201.         snake = Snake();
  202.         do {
  203.             spawnFood();
  204.         } while (isSnakeOnPoint(food));
  205.         score = 0;
  206.         gameOver = false;
  207.         paused = true;
  208.     }
  209.  
  210.     void handleKeyPress(WPARAM wParam) {
  211.         switch (wParam) {
  212.         case VK_UP:
  213.         case VK_DOWN:
  214.         case VK_LEFT:
  215.         case VK_RIGHT:
  216.             if (gameOver) {
  217.                 reset();
  218.             }
  219.             else {
  220.                 Direction newDir;
  221.                 switch (wParam) {
  222.                 case VK_UP: newDir = UP; break;
  223.                 case VK_DOWN: newDir = DOWN; break;
  224.                 case VK_LEFT: newDir = LEFT; break;
  225.                 case VK_RIGHT: newDir = RIGHT; break;
  226.                 }
  227.                 snake.setDirection(newDir);
  228.                 if (paused) paused = false;
  229.             }
  230.             break;
  231.         case VK_SPACE:
  232.             togglePause();
  233.             break;
  234.         case VK_ESCAPE:
  235.             reset();
  236.             break;
  237.         }
  238.     }
  239. }; // Add this closing brace to end the Game class
  240.  
  241. Game* game = nullptr;
  242.  
  243. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  244.     switch (uMsg) {
  245.     case WM_CREATE:
  246.         game = new Game(hwnd);
  247.         SetTimer(hwnd, 1, MOVE_INTERVAL, nullptr);
  248.         return 0;
  249.  
  250.     case WM_DESTROY:
  251.         KillTimer(hwnd, 1);
  252.         delete game;
  253.         PostQuitMessage(0);
  254.         return 0;
  255.  
  256.     case WM_TIMER:
  257.         game->update();
  258.         InvalidateRect(hwnd, nullptr, FALSE);
  259.         return 0;
  260.  
  261.     case WM_PAINT:
  262.     {
  263.         PAINTSTRUCT ps;
  264.         HDC hdc = BeginPaint(hwnd, &ps);
  265.         game->render();
  266.         EndPaint(hwnd, &ps);
  267.     }
  268.     return 0;
  269.  
  270.     case WM_KEYDOWN:
  271.         game->handleKeyPress(wParam);
  272.         return 0;
  273.     }
  274.  
  275.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  276. }
  277.  
  278. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  279.     const wchar_t CLASS_NAME[] = L"SnakeGameWindow";
  280.  
  281.     WNDCLASS wc = {};
  282.     wc.lpfnWndProc = WindowProc;
  283.     wc.hInstance = hInstance;
  284.     wc.lpszClassName = CLASS_NAME;
  285.     wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
  286.  
  287.     RegisterClass(&wc);
  288.  
  289.     HWND hwnd = CreateWindowEx(
  290.         0,
  291.         CLASS_NAME,
  292.         L"Snake Game",
  293.         WS_OVERLAPPEDWINDOW,
  294.         CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT,
  295.         nullptr,
  296.         nullptr,
  297.         hInstance,
  298.         nullptr
  299.     );
  300.  
  301.     if (hwnd == nullptr) {
  302.         return 0;
  303.     }
  304.  
  305.     ShowWindow(hwnd, nCmdShow);
  306.  
  307.     MSG msg = {};
  308.     while (GetMessage(&msg, nullptr, 0, 0)) {
  309.         TranslateMessage(&msg);
  310.         DispatchMessage(&msg);
  311.     }
  312.  
  313.     return 0;
  314. }
  315.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement