Advertisement
alien_fx_fiend

Snake-Game-Win32 *FiNAL RELEASE !*

Oct 22nd, 2024 (edited)
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.86 KB | Source Code | 0 0
  1. ==++"2D-Snake-Game.cpp File 1/1 SourceCode::++==
  2. #include <windows.h>
  3. #include <vector>
  4. #include <ctime>
  5. #include <cstdlib>
  6. #include "resource.h"  // Add this with your other includes
  7.  
  8. #define WINDOW_WIDTH 800
  9. #define WINDOW_HEIGHT 600
  10. #define GRID_SIZE 20
  11. #define SNAKE_INITIAL_LENGTH 5
  12. #define MOVE_INTERVAL 100
  13.  
  14. enum Direction { UP, DOWN, LEFT, RIGHT };
  15.  
  16. struct Point {
  17.    int x, y;
  18.    Point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
  19. };
  20.  
  21. class Snake {
  22. private:
  23.    std::vector<Point> body;
  24.    Direction currentDirection;
  25.    Direction nextDirection;
  26.    bool growing;
  27.  
  28. public:
  29.    Snake() : currentDirection(RIGHT), nextDirection(RIGHT), growing(false) {
  30.        for (int i = 0; i < SNAKE_INITIAL_LENGTH; ++i) {
  31.            body.push_back(Point(5 - i, 5));
  32.        }
  33.    }
  34.  
  35.    void move() {
  36.        currentDirection = nextDirection;
  37.        Point newHead = body.front();
  38.        switch (currentDirection) {
  39.        case UP: newHead.y--; break;
  40.        case DOWN: newHead.y++; break;
  41.        case LEFT: newHead.x--; break;
  42.        case RIGHT: newHead.x++; break;
  43.        }
  44.  
  45.        // Ensure the snake wraps around the window area
  46.        newHead.x = (newHead.x + (WINDOW_WIDTH / GRID_SIZE)) % (WINDOW_WIDTH / GRID_SIZE);
  47.        newHead.y = (newHead.y + (WINDOW_HEIGHT / GRID_SIZE)) % (WINDOW_HEIGHT / GRID_SIZE);
  48.  
  49.        body.insert(body.begin(), newHead);
  50.        if (!growing) {
  51.            body.pop_back();
  52.        }
  53.        growing = false;
  54.    }
  55.  
  56.  
  57.  
  58.    void grow() { growing = true; }
  59.  
  60.    void setDirection(Direction dir) {
  61.        if ((dir == UP || dir == DOWN) && (currentDirection == LEFT || currentDirection == RIGHT)) {
  62.            nextDirection = dir;
  63.        }
  64.        else if ((dir == LEFT || dir == RIGHT) && (currentDirection == UP || currentDirection == DOWN)) {
  65.            nextDirection = dir;
  66.        }
  67.    }
  68.  
  69.    bool checkCollision() const {
  70.        for (size_t i = 1; i < body.size(); ++i) {
  71.            if (body[0].x == body[i].x && body[0].y == body[i].y) {
  72.                return true;
  73.            }
  74.        }
  75.        return false;
  76.    }
  77.  
  78.    const std::vector<Point>& getBody() const { return body; }
  79.  
  80.    Direction getCurrentDirection() const {
  81.        return currentDirection;
  82.    }
  83. };
  84.  
  85. class Game {
  86. private:
  87.    Snake snake;
  88.    Point food;
  89.    bool gameOver;
  90.    bool paused;
  91.    int score;
  92.  
  93.    HWND hwnd;
  94.    HDC hdc, memDC;
  95.    HBITMAP memBitmap;
  96.    HBRUSH snakeBrush, foodBrush, backgroundBrush;
  97.  
  98. public:
  99.    Game(HWND hWnd) : hwnd(hWnd), gameOver(false), paused(true), score(0) {
  100.        srand(static_cast<unsigned>(time(nullptr)));
  101.        spawnFood();
  102.  
  103.        hdc = GetDC(hwnd);
  104.        memDC = CreateCompatibleDC(hdc);
  105.        memBitmap = CreateCompatibleBitmap(hdc, WINDOW_WIDTH, WINDOW_HEIGHT);
  106.        SelectObject(memDC, memBitmap);
  107.  
  108.        snakeBrush = CreateSolidBrush(RGB(0, 255, 0)); // Red (255, 0, 0)
  109.        foodBrush = CreateSolidBrush(RGB(255, 0, 0)); // Red (255, 0, 0)
  110.        backgroundBrush = CreateSolidBrush(RGB(0, 0, 0)); //khaki 196, 178, 137 // black 0,0,0
  111.    }
  112.  
  113.    ~Game() {
  114.        DeleteObject(snakeBrush);
  115.        DeleteObject(foodBrush);
  116.        DeleteObject(backgroundBrush);
  117.        DeleteObject(memBitmap);
  118.        DeleteDC(memDC);
  119.        ReleaseDC(hwnd, hdc);
  120.    }
  121.  
  122.    void spawnFood() {
  123.        int gridWidth = WINDOW_WIDTH / GRID_SIZE;
  124.        int gridHeight = WINDOW_HEIGHT / GRID_SIZE;
  125.        do {
  126.            food.x = rand() % gridWidth;
  127.            food.y = rand() % gridHeight;
  128.        } while (isSnakeOnPoint(food));
  129.    }
  130.  
  131.  
  132.    bool isSnakeOnPoint(const Point& p) const {
  133.        for (const auto& segment : snake.getBody()) {
  134.            if (segment.x == p.x && segment.y == p.y) {
  135.                return true;
  136.            }
  137.        }
  138.        return false;
  139.    }
  140.  
  141.    void update() {
  142.        if (gameOver || paused) return;
  143.  
  144.        snake.move();
  145.  
  146.        if (snake.checkCollision()) {
  147.            gameOver = true;
  148.            return;
  149.        }
  150.  
  151.        if (snake.getBody().front().x == food.x && snake.getBody().front().y == food.y) {
  152.            snake.grow();
  153.            do {
  154.                spawnFood();
  155.            } while (isSnakeOnPoint(food));
  156.            score++;
  157.        }
  158.    }
  159.  
  160.    void render() {
  161.        RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
  162.        FillRect(memDC, &rect, backgroundBrush);
  163.  
  164.        // Draw snake body
  165.        for (const auto& segment : snake.getBody()) {
  166.            RECT snakeRect = {
  167.                segment.x * GRID_SIZE,
  168.                segment.y * GRID_SIZE,
  169.                (segment.x + 1) * GRID_SIZE,
  170.                (segment.y + 1) * GRID_SIZE
  171.            };
  172.            FillRect(memDC, &snakeRect, snakeBrush);
  173.        }
  174.  
  175.        // Draw snake eyes
  176.        if (!snake.getBody().empty()) {
  177.            const Point& head = snake.getBody().front();
  178.            int eyeSize = 4; // 3 pixel radius for each eye
  179.            int eyeOffset = GRID_SIZE / 9; // 5->7 Offset from the edge of the head
  180.  
  181.            // Calculate eye positions based on snake's direction
  182.            int leftEyeX, leftEyeY, rightEyeX, rightEyeY;
  183.            switch (snake.getCurrentDirection()) {
  184.            case UP:
  185.                leftEyeX = head.x * GRID_SIZE + eyeOffset;
  186.                rightEyeX = (head.x + 1) * GRID_SIZE - eyeOffset - eyeSize * 2;
  187.                leftEyeY = rightEyeY = head.y * GRID_SIZE + eyeOffset;
  188.                break;
  189.            case DOWN:
  190.                leftEyeX = head.x * GRID_SIZE + eyeOffset;
  191.                rightEyeX = (head.x + 1) * GRID_SIZE - eyeOffset - eyeSize * 2;
  192.                leftEyeY = rightEyeY = (head.y + 1) * GRID_SIZE - eyeOffset - eyeSize * 2;
  193.                break;
  194.            case LEFT:
  195.                leftEyeX = rightEyeX = head.x * GRID_SIZE + eyeOffset;
  196.                leftEyeY = head.y * GRID_SIZE + eyeOffset;
  197.                rightEyeY = (head.y + 1) * GRID_SIZE - eyeOffset - eyeSize * 2;
  198.                break;
  199.            case RIGHT:
  200.                leftEyeX = rightEyeX = (head.x + 1) * GRID_SIZE - eyeOffset - eyeSize * 2;
  201.                leftEyeY = head.y * GRID_SIZE + eyeOffset;
  202.                rightEyeY = (head.y + 1) * GRID_SIZE - eyeOffset - eyeSize * 2;
  203.                break;
  204.            }
  205.  
  206.            // Draw the eyes
  207.            HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255)); // yellow 255, 255, 0 darkpurple 128, 0, 128 purple 157, 0, 255 white 255,255,255
  208.            SelectObject(memDC, whiteBrush);
  209.            Ellipse(memDC, leftEyeX, leftEyeY, leftEyeX + eyeSize * 2, leftEyeY + eyeSize * 2);
  210.            Ellipse(memDC, rightEyeX, rightEyeY, rightEyeX + eyeSize * 2, rightEyeY + eyeSize * 2);
  211.            DeleteObject(whiteBrush);
  212.        }
  213.  
  214.        // Draw food
  215.        if (food.x >= 0 && food.y >= 0) {
  216.            RECT foodRect = {
  217.                food.x * GRID_SIZE,
  218.                food.y * GRID_SIZE,
  219.                (food.x + 1) * GRID_SIZE,
  220.                (food.y + 1) * GRID_SIZE
  221.            };
  222.            FillRect(memDC, &foodRect, foodBrush);
  223.        }
  224.  
  225.        WCHAR scoreText[32];
  226.        swprintf_s(scoreText, L"Score: %d", score);
  227.        SetBkMode(memDC, TRANSPARENT);
  228.        SetTextColor(memDC, RGB(255, 255, 255));
  229.        TextOut(memDC, 10, 10, scoreText, wcslen(scoreText));
  230.  
  231.        if (gameOver) {
  232.            const WCHAR* gameOverText = L"Game Over! Press any arrow key to restart.";
  233.            TextOut(memDC, WINDOW_WIDTH / 2 - 150, WINDOW_HEIGHT / 2, gameOverText, wcslen(gameOverText));
  234.        }
  235.        else if (paused) {
  236.            const WCHAR* pausedText = L"Paused. Press any arrow key to start.";
  237.            TextOut(memDC, WINDOW_WIDTH / 2 - 120, WINDOW_HEIGHT / 2, pausedText, wcslen(pausedText));
  238.        }
  239.  
  240.        BitBlt(hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, memDC, 0, 0, SRCCOPY);
  241.    }
  242.  
  243.    void togglePause() {
  244.        paused = !paused;
  245.    }
  246.  
  247.    void reset() {
  248.        snake = Snake();
  249.        do {
  250.            spawnFood();
  251.        } while (isSnakeOnPoint(food));
  252.        score = 0;
  253.        gameOver = false;
  254.        paused = true;
  255.    }
  256.  
  257.    void handleKeyPress(WPARAM wParam) {
  258.        switch (wParam) {
  259.        case VK_UP:
  260.        case VK_DOWN:
  261.        case VK_LEFT:
  262.        case VK_RIGHT:
  263.            if (gameOver) {
  264.                reset();
  265.            }
  266.            else {
  267.                Direction newDir;
  268.                switch (wParam) {
  269.                case VK_UP: newDir = UP; break;
  270.                case VK_DOWN: newDir = DOWN; break;
  271.                case VK_LEFT: newDir = LEFT; break;
  272.                case VK_RIGHT: newDir = RIGHT; break;
  273.                }
  274.                snake.setDirection(newDir);
  275.                if (paused) paused = false;
  276.            }
  277.            break;
  278.        case VK_SPACE:
  279.            togglePause();
  280.            break;
  281.        case VK_ESCAPE:
  282.            reset();
  283.            break;
  284.        case VK_F1:  // Add this case for F1 key
  285.            MessageBoxW(hwnd, L"Snake Game 1.3 Programmed in C++ Win32 API (383 lines of code) by Entisoft Software (c) Evans Thorpemorton", L"About", MB_OK | MB_ICONINFORMATION);
  286.            break;
  287.        }
  288.    }
  289.  
  290.    static void AdjustWindowSize(HWND hwnd) {
  291.        RECT rcClient, rcWindow;
  292.        GetClientRect(hwnd, &rcClient);
  293.        GetWindowRect(hwnd, &rcWindow);
  294.        int width = (rcWindow.right - rcWindow.left) - (rcClient.right - rcClient.left) + WINDOW_WIDTH;
  295.        int height = (rcWindow.bottom - rcWindow.top) - (rcClient.bottom - rcClient.top) + WINDOW_HEIGHT;
  296.        SetWindowPos(hwnd, NULL, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER);
  297.    }
  298. }; // Add this closing brace to end the Game class
  299.  
  300. Game* game = nullptr;
  301.  
  302. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  303.    switch (uMsg) {
  304.    case WM_CREATE:
  305.        game = new Game(hwnd);
  306.        SetTimer(hwnd, 1, MOVE_INTERVAL, nullptr);
  307.        return 0;
  308.  
  309.    case WM_DESTROY:
  310.        KillTimer(hwnd, 1);
  311.        delete game;
  312.        PostQuitMessage(0);
  313.        return 0;
  314.  
  315.    case WM_TIMER:
  316.        game->update();
  317.        InvalidateRect(hwnd, nullptr, FALSE);
  318.        return 0;
  319.  
  320.    case WM_PAINT:
  321.    {
  322.        PAINTSTRUCT ps;
  323.        HDC hdc = BeginPaint(hwnd, &ps);
  324.        game->render();
  325.        EndPaint(hwnd, &ps);
  326.    }
  327.    return 0;
  328.  
  329.    case WM_KEYDOWN:
  330.        game->handleKeyPress(wParam);
  331.        return 0;
  332.    }
  333.  
  334.    return DefWindowProc(hwnd, uMsg, wParam, lParam);
  335. }
  336.  
  337. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  338.    const wchar_t CLASS_NAME[] = L"SnakeGameWindow";
  339.  
  340.    WNDCLASS wc = {};
  341.    wc.lpfnWndProc = WindowProc;
  342.    wc.hInstance = hInstance;
  343.    wc.lpszClassName = CLASS_NAME;
  344.    wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));     // Add this line
  345.    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
  346.  
  347.    RegisterClass(&wc);
  348.  
  349.    // Get the screen dimensions
  350.    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
  351.    int screenHeight = GetSystemMetrics(SM_CYSCREEN);
  352.  
  353.    // Calculate the window position to center it
  354.    int windowWidth = WINDOW_WIDTH + 16;
  355.    int windowHeight = WINDOW_HEIGHT + 39;
  356.    int posX = (screenWidth - windowWidth) / 2;
  357.    int posY = (screenHeight - windowHeight) / 2;
  358.  
  359.    HWND hwnd = CreateWindowEx(
  360.        0,
  361.        CLASS_NAME,
  362.        L"Snake Game (ArrowKeys=Move Space=Pause Escape=Reset)",
  363.        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
  364.        posX, posY, WINDOW_WIDTH + 16, WINDOW_HEIGHT + 39,
  365.        nullptr,
  366.        nullptr,
  367.        hInstance,
  368.        nullptr
  369.    );
  370.  
  371.    if (hwnd == nullptr) {
  372.        return 0;
  373.    }
  374.  
  375.    Game::AdjustWindowSize(hwnd);
  376.  
  377.    ShowWindow(hwnd, nCmdShow);
  378.  
  379.    MSG msg = {};
  380.    while (GetMessage(&msg, nullptr, 0, 0)) {
  381.        TranslateMessage(&msg);
  382.        DispatchMessage(&msg);
  383.    }
  384.  
  385.    return 0;
  386. }
  387.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement