Advertisement
alien_fx_fiend

Snake-Game-Win32 *FiNAL RELEASE !*

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