Advertisement
alien_fx_fiend

Asteroids Game C++ (Added Shield Effect+Music) *FINAL RELEASE v2*

Nov 4th, 2024 (edited)
40
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 28.28 KB | Source Code | 0 0
  1. ==++ Here's the full source code of (file 1/1) "main.cpp"::++==
  2. #include <windows.h>
  3. #include <vector>
  4. #include <cmath>
  5. #include <ctime>
  6. #include <algorithm>  // Include this header for std::min and std::max
  7. #include <tchar.h>
  8. // Add these global variables
  9. #include <thread>
  10. #include <atomic>
  11. #include "resource.h"
  12.  
  13. #include <mmsystem.h>
  14. #pragma comment(lib, "winmm.lib")
  15.  
  16. #define WIN_WIDTH 800
  17. #define WIN_HEIGHT 600
  18. // Add this to your global variables
  19. #define NUM_STARS 100
  20. // Add with other global variables
  21. bool keyStates[256] = { false };  // Track key states
  22. bool godMode = false; // Track God Mode state
  23. bool paused = false; // Track paused state
  24. bool gameStarted = false;
  25. int countdownTimer = 240; // 4 seconds total (3,2,1,Get Ready!)
  26. int windowWidth;
  27. int windowHeight;
  28. MCIDEVICEID midiDeviceID = 0;
  29. std::atomic<bool> isMusicPlaying(false);
  30. std::thread musicThread;
  31. bool isShielded = false;
  32. int shieldTimer = 0;
  33. const int SHIELD_DURATION = 240; // 4 seconds at 60 FPS
  34.  
  35. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  36. void DrawSpacecraft(HDC hdc, POINT pts[], int x, int y, double angle);
  37. void DrawAsteroid(HDC hdc, POINT pts[], int x, int y, double angle);
  38. bool CheckCollision(POINT player[], POINT asteroid[], int px, int py, int ax, int ay);
  39. void MoveAsteroids();
  40. void ShootBullet();
  41. void DrawBullet(HDC hdc, int x, int y);
  42. bool CheckBulletCollision(int bx, int by);
  43. bool DoLinesIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
  44. int Direction(int x1, int y1, int x2, int y2, int x3, int y3);
  45. bool OnSegment(int x1, int y1, int x2, int y2, int x3, int y3);
  46. bool PointInPolygon(int px, int py, POINT polygon[], int ox, int oy);
  47. void GenerateAsteroids();
  48. void SpawnNewAsteroid();
  49. void UpdatePlayerMovement();
  50. void InitStars();
  51. void DrawStarfield(HDC hdc);
  52.  
  53. struct Asteroid {
  54.    int x, y;
  55.    double angle;
  56.    double speed;
  57.    POINT shape[8];
  58. };
  59.  
  60. struct Bullet {
  61.    int x, y;
  62.    double angle;
  63. };
  64.  
  65. struct Star {
  66.    int x, y;
  67.    int brightness; // 0-255 for varying star brightness
  68. };
  69. Star stars[NUM_STARS];
  70.  
  71. std::vector<Asteroid> asteroids;
  72. std::vector<Bullet> bullets;
  73. // Replace the existing player points definition
  74. // Define more points for a detailed spacecraft
  75. POINT player[15] = {
  76.    {0, -40},    // Nose
  77.    {15, -20},   // Right front
  78.    {20, -10},   // Right body
  79.    {25, 0},     // Right wing
  80.    {30, 20},    // Right thruster
  81.    {20, 25},    // Right back
  82.    {10, 30},    // Right exhaust
  83.    {0, 35},     // Center exhaust
  84.    {-10, 30},   // Left exhaust
  85.    {-20, 25},   // Left back
  86.    {-30, 20},   // Left thruster
  87.    {-25, 0},    // Left wing
  88.    {-20, -10},  // Left body
  89.    {-15, -20},  // Left front
  90.    {0, -40}     // Back to nose
  91. };
  92. int playerX = WIN_WIDTH / 2, playerY = WIN_HEIGHT / 2;
  93. double playerAngle = 0;
  94. int score = 0;
  95. int lives = 3;
  96.  
  97. void PlayMidiInBackground(HWND hwnd, const TCHAR* midiPath) {
  98.    while (isMusicPlaying) {
  99.        MCI_OPEN_PARMS mciOpen = { 0 };
  100.        mciOpen.lpstrDeviceType = TEXT("sequencer");
  101.        mciOpen.lpstrElementName = midiPath;
  102.  
  103.        if (mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD_PTR)&mciOpen) == 0) {
  104.            midiDeviceID = mciOpen.wDeviceID;
  105.  
  106.            MCI_PLAY_PARMS mciPlay = { 0 };
  107.            mciSendCommand(midiDeviceID, MCI_PLAY, 0, (DWORD_PTR)&mciPlay);
  108.  
  109.            // Wait for playback to complete
  110.            MCI_STATUS_PARMS mciStatus = { 0 };
  111.            mciStatus.dwItem = MCI_STATUS_MODE;
  112.  
  113.            do {
  114.                mciSendCommand(midiDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
  115.                Sleep(100); // Reduce CPU usage
  116.            } while (mciStatus.dwReturn == MCI_MODE_PLAY && isMusicPlaying);
  117.  
  118.            mciSendCommand(midiDeviceID, MCI_CLOSE, 0, NULL);
  119.            midiDeviceID = 0;
  120.        }
  121.    }
  122. }
  123.  
  124. void PlayGameMusic(HWND hwnd) {
  125.    // Stop any existing playback
  126.    if (isMusicPlaying) {
  127.        isMusicPlaying = false;
  128.        if (musicThread.joinable()) {
  129.            musicThread.join();
  130.        }
  131.        if (midiDeviceID != 0) {
  132.            mciSendCommand(midiDeviceID, MCI_CLOSE, 0, NULL);
  133.            midiDeviceID = 0;
  134.        }
  135.    }
  136.  
  137.    // Get the path of the executable
  138.    TCHAR exePath[MAX_PATH];
  139.    GetModuleFileName(NULL, exePath, MAX_PATH);
  140.  
  141.    // Extract the directory path
  142.    TCHAR* lastBackslash = _tcsrchr(exePath, '\\');
  143.    if (lastBackslash != NULL) {
  144.        *(lastBackslash + 1) = '\0';
  145.    }
  146.  
  147.    // Construct the full path to the MIDI file
  148.    static TCHAR midiPath[MAX_PATH];
  149.    _tcscpy_s(midiPath, MAX_PATH, exePath);
  150.    _tcscat_s(midiPath, MAX_PATH, TEXT("GAME MUSIC.MID"));
  151.  
  152.    // Start the background playback
  153.    isMusicPlaying = true;
  154.    musicThread = std::thread(PlayMidiInBackground, hwnd, midiPath);
  155. }
  156.  
  157. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  158.    WNDCLASSEX wcex;
  159.    HWND hwnd;
  160.    MSG msg;
  161.  
  162.    wcex.cbSize = sizeof(WNDCLASSEX);
  163.    wcex.style = CS_HREDRAW | CS_VREDRAW;
  164.    wcex.lpfnWndProc = WndProc;
  165.    wcex.cbClsExtra = 0;
  166.    wcex.cbWndExtra = 0;
  167.    wcex.hInstance = hInstance;
  168.    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  169.    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  170.    wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); // Replace NULL with this // Set background brush to NULL
  171.    wcex.lpszMenuName = NULL;
  172.    wcex.lpszClassName = TEXT("Asteroids");
  173.    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON1));
  174.    //wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  175.  
  176.    RegisterClassEx(&wcex);
  177.  
  178.    // Remove WS_MAXIMIZEBOX and WS_THICKFRAME from the window style
  179.    DWORD style = (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX) & ~WS_THICKFRAME;
  180.  
  181.    // Get the screen dimensions
  182.    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
  183.    int screenHeight = GetSystemMetrics(SM_CYSCREEN);
  184.  
  185.    // Calculate the window position to center it
  186.    int windowWidth = WIN_WIDTH + 16;
  187.    int windowHeight = WIN_HEIGHT + 39;
  188.    int posX = (screenWidth - windowWidth) / 2;
  189.    int posY = (screenHeight - windowHeight) / 2;
  190.  
  191.    hwnd = CreateWindow(TEXT("Asteroids"), TEXT("Asteroids ArrowKeys=Controls Space=Shoot F1=GodMode P=Pause F2=About Escape=Quit"), style,
  192.        posX, posY, windowWidth + 16, windowHeight + 39, NULL, NULL, hInstance, NULL);
  193.  
  194.    ShowWindow(hwnd, nCmdShow);
  195.    UpdateWindow(hwnd);
  196.    
  197.    srand(static_cast<unsigned int>(time(0)));
  198.  
  199.    GenerateAsteroids();
  200.  
  201.    // Add this line in WinMain before the main loop:
  202.    InitStars();
  203.    PlayGameMusic(hwnd);
  204.  
  205.    // Main game loop
  206.    while (true) {
  207.        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  208.            if (msg.message == WM_QUIT) break;
  209.            TranslateMessage(&msg);
  210.            DispatchMessage(&msg);
  211.        }
  212.        else {
  213.            if (!gameStarted) {                
  214.                InvalidateRect(hwnd, NULL, FALSE);
  215.                Sleep(16);
  216.                countdownTimer--;
  217.                if (countdownTimer <= 0) {
  218.                    gameStarted = true;                    
  219.                }
  220.                continue;
  221.            }
  222.            if (!paused) {
  223.                if (isShielded) {
  224.                    shieldTimer--;
  225.                    if (shieldTimer <= 0) {
  226.                        isShielded = false;
  227.                    }
  228.                }
  229.  
  230.                UpdatePlayerMovement();
  231.                for (auto& ast : asteroids) {
  232.                    if (!godMode && !isShielded && CheckCollision(player, ast.shape, playerX, playerY, ast.x, ast.y)) {
  233.                        lives--;
  234.                        if (lives <= 0) {
  235.                            if (MessageBox(hwnd, TEXT("Game Over! Play again?"), TEXT("Asteroids"), MB_YESNO) == IDYES) {
  236.                                // Reset game
  237.                                lives = 3;
  238.                                score = 0;
  239.                                playerX = WIN_WIDTH / 2;
  240.                                playerY = WIN_HEIGHT / 2;
  241.                                playerAngle = 0;
  242.                                asteroids.clear();
  243.                                bullets.clear();
  244.                                GenerateAsteroids();
  245.                            }
  246.                            else {
  247.                                PostQuitMessage(0);
  248.                            }
  249.                            continue;
  250.                        }
  251.                        playerX = WIN_WIDTH / 2;
  252.                        playerY = WIN_HEIGHT / 2;
  253.                        playerAngle = 0;
  254.                        isShielded = true;
  255.                        shieldTimer = SHIELD_DURATION;
  256.                        memset(keyStates, 0, sizeof(keyStates));
  257.                    }
  258.                }
  259.  
  260.                if (rand() % 100 < 2) {
  261.                    SpawnNewAsteroid();
  262.                }
  263.  
  264.                MoveAsteroids();
  265.  
  266.                for (auto it = bullets.begin(); it != bullets.end();) {
  267.                    it->x += 10 * cos(it->angle * 3.14159 / 180);
  268.                    it->y += 10 * sin(it->angle * 3.14159 / 180);
  269.  
  270.                    if (CheckBulletCollision(it->x, it->y)) {
  271.                        //Beep(500, 50); // Beep sound when asteroid is destroyed
  272.                        it = bullets.erase(it);
  273.                    }
  274.                    else {
  275.                        ++it;
  276.                    }
  277.                }
  278.            }
  279.            InvalidateRect(hwnd, NULL, FALSE);
  280.            Sleep(16);
  281.        }
  282.    }
  283.  
  284.    return (int)msg.wParam;
  285. }
  286.  
  287.  
  288. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  289.    static HDC hdcMem;
  290.    static HBITMAP hbmMem;
  291.    static HBITMAP hbmOld;
  292.    static HBRUSH hbrBkGnd;
  293.    static RECT rect;
  294.    PAINTSTRUCT ps;
  295.    static TCHAR scoreText[50];
  296.  
  297.    switch (msg) {
  298.    case WM_CREATE:
  299.    {   // Add these braces
  300.        GetClientRect(hwnd, &rect);
  301.        HDC hdcWindow = GetDC(hwnd);
  302.        hdcMem = CreateCompatibleDC(hdcWindow);
  303.        hbmMem = CreateCompatibleBitmap(hdcWindow, rect.right, rect.bottom);
  304.        ReleaseDC(hwnd, hdcWindow);
  305.        hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
  306.        hbrBkGnd = CreateSolidBrush(RGB(0, 0, 0));
  307.    }    // Add these braces
  308.    break;  // Add break statement
  309.  
  310.  
  311.    case WM_PAINT: {
  312.        HDC hdc = BeginPaint(hwnd, &ps);
  313.        FillRect(hdcMem, &rect, hbrBkGnd);
  314.  
  315.        // Draw starfield first (before everything else)
  316.        DrawStarfield(hdcMem);
  317.  
  318.        if (!gameStarted) {
  319.            SetTextColor(hdcMem, RGB(255, 255, 255));
  320.            SetBkMode(hdcMem, TRANSPARENT);
  321.            HFONT hFont = CreateFont(72, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
  322.                ANSI_CHARSET, // Changed from DEFAULT_CHARSET to ANSI_CHARSET
  323.                OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
  324.                CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_SWISS, TEXT("Arial"));
  325.            HFONT hOldFont = (HFONT)SelectObject(hdcMem, hFont);
  326.  
  327.            const TCHAR* countText;  // Changed to const TCHAR*
  328.            int count = (countdownTimer / 60);
  329.  
  330.            // Use direct string assignments instead of wsprintf
  331.            if (count == 4) {
  332.                countText = TEXT("3");
  333.            }
  334.            else if (count == 3) {
  335.                countText = TEXT("2");
  336.            }
  337.            else if (count == 2) {
  338.                countText = TEXT("1");
  339.            }
  340.            else if (count == 1) {
  341.                countText = TEXT("Get Ready!");
  342.            }
  343.            else {
  344.                countText = TEXT("");  // Add default case
  345.            }
  346.  
  347.            RECT textRect;
  348.            GetClientRect(hwnd, &textRect);
  349.            DrawText(hdcMem, countText, -1, &textRect,
  350.                DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  351.  
  352.            SelectObject(hdcMem, hOldFont);
  353.            DeleteObject(hFont);
  354.        }
  355.        else {
  356.            // Your existing drawing code...
  357.            DrawSpacecraft(hdcMem, player, playerX, playerY, playerAngle);
  358.            for (auto& ast : asteroids) {
  359.                DrawAsteroid(hdcMem, ast.shape, ast.x, ast.y, ast.angle);
  360.            }
  361.            for (auto& bullet : bullets) {
  362.                DrawBullet(hdcMem, bullet.x, bullet.y);
  363.            }
  364.  
  365.            SetTextColor(hdcMem, RGB(255, 255, 255));
  366.            SetBkMode(hdcMem, TRANSPARENT);
  367.            wsprintf(scoreText, TEXT("Score: %d  Lives: %d"), score, lives);
  368.            TextOut(hdcMem, 10, 10, scoreText, lstrlen(scoreText));
  369.  
  370.            if (godMode) {
  371.                TextOut(hdcMem, WIN_WIDTH / 2 - 50, 10, TEXT("God Mode"), 8);
  372.            }
  373.            if (paused) {
  374.                TextOut(hdcMem, WIN_WIDTH / 2 - 50, WIN_HEIGHT / 2 - 10, TEXT("Game Paused"), 10);
  375.            }
  376.        }
  377.  
  378.        BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
  379.        EndPaint(hwnd, &ps);
  380.        break;
  381.    }
  382.  
  383.  
  384.  
  385.    case WM_KEYDOWN:
  386.        keyStates[wParam] = true;
  387.        if (wParam == VK_F1) {
  388.            godMode = !godMode; // Toggle God Mode
  389.        }
  390.        else if (wParam == 'P') {
  391.            paused = !paused; // Toggle Pause
  392.        }
  393.        if (wParam == VK_ESCAPE) {
  394.            PostQuitMessage(0);
  395.            return 0;
  396.        }
  397.        // Add this new code block
  398.        else if (wParam == VK_F2) {
  399.            MessageBox(hwnd, TEXT("Asteroids v10.8 Basic GDI-Based C++ Win32 Game (663 lines of code) by Entisoft Software (c) Evans Thorpemorton"), TEXT("About"), MB_OK | MB_ICONINFORMATION);
  400.        }
  401.        break;
  402.  
  403.    case WM_KEYUP:
  404.        keyStates[wParam] = false;
  405.        break;  
  406.  
  407.    case WM_DESTROY:
  408.        SelectObject(hdcMem, hbmOld);  // Restore the original bitmap in the memory DC
  409.        DeleteObject(hbmMem);          // Delete the off-screen bitmap
  410.        DeleteDC(hdcMem);              // Delete the memory DC
  411.        DeleteObject(hbrBkGnd);        // Delete the background brush
  412.        isMusicPlaying = false;
  413.        if (musicThread.joinable()) {
  414.            musicThread.join();
  415.        }
  416.        if (midiDeviceID != 0) {
  417.            mciSendCommand(midiDeviceID, MCI_CLOSE, 0, NULL);
  418.            midiDeviceID = 0;
  419.        }
  420.        PostQuitMessage(0);
  421.        break;
  422.  
  423.    default:
  424.        return DefWindowProc(hwnd, msg, wParam, lParam);
  425.    }
  426.    return 0;
  427. }
  428.  
  429. void DrawSpacecraft(HDC hdc, POINT pts[], int x, int y, double angle) {
  430.    POINT rotated[15];
  431.    for (int i = 0; i < 15; ++i) {
  432.        rotated[i].x = pts[i].x * cos(angle * 3.14159 / 180) -
  433.            pts[i].y * sin(angle * 3.14159 / 180);
  434.        rotated[i].y = pts[i].x * sin(angle * 3.14159 / 180) +
  435.            pts[i].y * cos(angle * 3.14159 / 180);
  436.        rotated[i].x += x;
  437.        rotated[i].y += y;
  438.    }
  439.  
  440.    // Draw shield effect if active
  441.    if (isShielded) {
  442.        // Create shield gradient effect
  443.        int shieldRadius = 60;
  444.        HPEN shieldPen;
  445.  
  446.        // Multiple shield layers with different colors and opacity
  447.        for (int i = 0; i < 3; i++) {
  448.            int alpha = (255 - i * 40) * ((sin(shieldTimer * 0.1) + 1) / 2);
  449.            COLORREF shieldColor;
  450.  
  451.            switch ((shieldTimer / 8 + i) % 3) {
  452.            case 0:
  453.                shieldColor = RGB(0, 255, 255); // Cyan
  454.                break;
  455.            case 1:
  456.                shieldColor = RGB(0, 191, 255); // Deep Sky Blue
  457.                break;
  458.            case 2:
  459.                shieldColor = RGB(30, 144, 255); // Dodger Blue
  460.                break;
  461.            }
  462.  
  463.            shieldPen = CreatePen(PS_SOLID, 2 - i, shieldColor);
  464.            HPEN oldPen = (HPEN)SelectObject(hdc, shieldPen);
  465.  
  466.            // Draw shield circles
  467.            int currentRadius = shieldRadius - (i * 10);
  468.            Arc(hdc, x - currentRadius, y - currentRadius,
  469.                x + currentRadius, y + currentRadius,
  470.                x + currentRadius, y, x + currentRadius, y);
  471.  
  472.            // Draw energy field lines
  473.            for (int j = 0; j < 8; j++) {
  474.                double angleRad = (angle + j * 45) * 3.14159 / 180;
  475.                int startX = x + (currentRadius - 10) * cos(angleRad);
  476.                int startY = y + (currentRadius - 10) * sin(angleRad);
  477.                int endX = x + currentRadius * cos(angleRad);
  478.                int endY = y + currentRadius * sin(angleRad);
  479.                MoveToEx(hdc, startX, startY, NULL);
  480.                LineTo(hdc, endX, endY);
  481.            }
  482.  
  483.            // Draw energy particles
  484.            for (int j = 0; j < 12; j++) {
  485.                double particleAngle = (shieldTimer * 2 + j * 30) * 3.14159 / 180;
  486.                int particleX = x + currentRadius * cos(particleAngle);
  487.                int particleY = y + currentRadius * sin(particleAngle);
  488.                SetPixel(hdc, particleX, particleY, shieldColor);
  489.            }
  490.  
  491.            SelectObject(hdc, oldPen);
  492.            DeleteObject(shieldPen);
  493.        }
  494.  
  495.        // Add shield shimmer effect
  496.        HPEN shimmerPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
  497.        SelectObject(hdc, shimmerPen);
  498.        for (int i = 0; i < 16; i++) {
  499.            double shimmerAngle = (shieldTimer * 3 + i * 22.5) * 3.14159 / 180;
  500.            int shimmerX = x + shieldRadius * cos(shimmerAngle);
  501.            int shimmerY = y + shieldRadius * sin(shimmerAngle);
  502.            Ellipse(hdc, shimmerX - 2, shimmerY - 2, shimmerX + 2, shimmerY + 2);
  503.        }
  504.        DeleteObject(shimmerPen);
  505.    }
  506.  
  507.    // Draw main body
  508.    HPEN hotPinkPen = CreatePen(PS_SOLID, 1, RGB(255, 20, 147));
  509.    HBRUSH hotPinkBrush = CreateSolidBrush(RGB(255, 20, 147));
  510.    SelectObject(hdc, hotPinkPen);
  511.    SelectObject(hdc, hotPinkBrush);
  512.    Polygon(hdc, rotated, 15);
  513.  
  514.    // Draw headlights
  515.    HPEN whitePen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
  516.    SelectObject(hdc, whitePen);
  517.  
  518.    // Left headlight
  519.    int lightX1 = x + 15 * cos((angle - 100) * 3.14159 / 180);
  520.    int lightY1 = y + 15 * sin((angle - 100) * 3.14159 / 180);
  521.    Ellipse(hdc, lightX1 - 3, lightY1 - 3, lightX1 + 3, lightY1 + 3);
  522.  
  523.    // Right headlight
  524.    int lightX2 = x + 15 * cos((angle - 80) * 3.14159 / 180);
  525.    int lightY2 = y + 15 * sin((angle - 80) * 3.14159 / 180);
  526.    Ellipse(hdc, lightX2 - 3, lightY2 - 3, lightX2 + 3, lightY2 + 3);
  527.  
  528.    // Draw engine glow when moving forward
  529.    if (keyStates[VK_UP] || keyStates[VK_DOWN]) {
  530.        HPEN orangePen = CreatePen(PS_SOLID, 1, RGB(255, 165, 0));
  531.        HBRUSH orangeBrush = CreateSolidBrush(RGB(255, 165, 0));
  532.        SelectObject(hdc, orangePen);
  533.        SelectObject(hdc, orangeBrush);
  534.  
  535.        // Draw three exhaust flames
  536.        for (int i = -1; i <= 1; i++) {
  537.            int exhaustX = x - 30 * cos((angle - 90 + i * 15) * 3.14159 / 180);
  538.            int exhaustY = y - 30 * sin((angle - 90 + i * 15) * 3.14159 / 180);
  539.            Ellipse(hdc, exhaustX - 5, exhaustY - 5, exhaustX + 5, exhaustY + 5);
  540.        }
  541.  
  542.        DeleteObject(orangePen);
  543.        DeleteObject(orangeBrush);
  544.    }
  545.  
  546.    DeleteObject(hotPinkPen);
  547.    DeleteObject(hotPinkBrush);
  548.    DeleteObject(whitePen);
  549. }
  550.  
  551. void DrawAsteroid(HDC hdc, POINT pts[], int x, int y, double angle) {
  552.    POINT rotated[8];
  553.    for (int i = 0; i < 8; ++i) {
  554.        rotated[i].x = pts[i].x * cos(angle * 3.14159 / 180) - pts[i].y * sin(angle * 3.14159 / 180);
  555.        rotated[i].y = pts[i].x * sin(angle * 3.14159 / 180) + pts[i].y * cos(angle * 3.14159 / 180);
  556.        rotated[i].x += x;
  557.        rotated[i].y += y;
  558.    }
  559.  
  560.    // In DrawAsteroid function, before Polygon call
  561.    HPEN goldPen = CreatePen(PS_SOLID, 1, RGB(255, 215, 0));
  562.    HBRUSH goldBrush = CreateSolidBrush(RGB(255, 215, 0));
  563.    SelectObject(hdc, goldPen);
  564.    SelectObject(hdc, goldBrush);
  565.    Polygon(hdc, rotated, 8);
  566.    DeleteObject(goldPen);
  567.    DeleteObject(goldBrush);
  568. }
  569.  
  570. void UpdatePlayerMovement() {
  571.    if (keyStates[VK_LEFT]) {
  572.        playerAngle -= 5;
  573.    }
  574.    if (keyStates[VK_RIGHT]) {
  575.        playerAngle += 5;
  576.    }
  577.    if (keyStates[VK_UP]) {
  578.        playerX += 5 * cos((playerAngle - 90) * 3.14159 / 180);
  579.        playerY += 5 * sin((playerAngle - 90) * 3.14159 / 180);
  580.  
  581.        // Move stars in opposite direction of player movement for parallax effect
  582.        for (int i = 0; i < NUM_STARS; i++) {
  583.            stars[i].y += 1;
  584.            if (stars[i].y > WIN_HEIGHT) {
  585.                stars[i].y = 0;
  586.                stars[i].x = rand() % WIN_WIDTH;
  587.            }
  588.        }
  589.    }
  590.    // Add to UpdatePlayerMovement() function
  591.    if (keyStates[VK_DOWN]) {
  592.        playerX -= 5 * cos((playerAngle - 90) * 3.14159 / 180);
  593.        playerY -= 5 * sin((playerAngle - 90) * 3.14159 / 180);
  594.  
  595.        // Move stars in opposite direction of player movement for parallax effect
  596.        for (int i = 0; i < NUM_STARS; i++) {
  597.            stars[i].y += 1;
  598.            if (stars[i].y > WIN_HEIGHT) {
  599.                stars[i].y = 0;
  600.                stars[i].x = rand() % WIN_WIDTH;
  601.            }
  602.        }
  603.    }
  604.    // Add to UpdatePlayerMovement() function
  605.    static int shootCooldown = 0;
  606.    if (keyStates[VK_SPACE] && shootCooldown == 0) {
  607.        ShootBullet();
  608.        shootCooldown = 10; // Adjust this value to control firing rate
  609.    }
  610.    if (shootCooldown > 0) {
  611.        shootCooldown--;
  612.    }
  613.  
  614.    // Wrap around screen
  615.    if (playerX < 0) playerX = WIN_WIDTH;
  616.    if (playerX > WIN_WIDTH) playerX = 0;
  617.    if (playerY < 0) playerY = WIN_HEIGHT;
  618.    if (playerY > WIN_HEIGHT) playerY = 0;
  619. }
  620.  
  621. bool CheckCollision(POINT player[], POINT asteroid[], int px, int py, int ax, int ay) {
  622.    for (int i = 0; i < 3; ++i) {
  623.        int px1 = player[i].x + px;
  624.        int py1 = player[i].y + py;
  625.        int px2 = player[(i + 1) % 3].x + px;
  626.        int py2 = player[(i + 1) % 3].y + py;
  627.  
  628.        for (int j = 0; j < 8; ++j) {
  629.            int ax1 = asteroid[j].x + ax;
  630.            int ay1 = asteroid[j].y + ay;
  631.            int ax2 = asteroid[(j + 1) % 8].x + ax;
  632.            int ay2 = asteroid[(j + 1) % 8].y + ay;
  633.  
  634.            // Check if the line segments intersect
  635.            if (DoLinesIntersect(px1, py1, px2, py2, ax1, ay1, ax2, ay2)) {
  636.                return true;
  637.            }
  638.        }
  639.    }
  640.    return false;
  641. }
  642.  
  643. bool DoLinesIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
  644.    // Calculate the direction of the lines
  645.    int d1 = Direction(x3, y3, x4, y4, x1, y1);
  646.    int d2 = Direction(x3, y3, x4, y4, x2, y2);
  647.    int d3 = Direction(x1, y1, x2, y2, x3, y3);
  648.    int d4 = Direction(x1, y1, x2, y2, x4, y4);
  649.  
  650.    // Check if the lines intersect
  651.    if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) {
  652.        return true;
  653.    }
  654.  
  655.    // Check for collinear points
  656.    if (d1 == 0 && OnSegment(x3, y3, x4, y4, x1, y1)) return true;
  657.    if (d2 == 0 && OnSegment(x3, y3, x4, y4, x2, y2)) return true;
  658.    if (d3 == 0 && OnSegment(x1, y1, x2, y2, x3, y3)) return true;
  659.    if (d4 == 0 && OnSegment(x1, y1, x2, y2, x4, y4)) return true;
  660.  
  661.    return false;
  662. }
  663.  
  664. int Direction(int x1, int y1, int x2, int y2, int x3, int y3) {
  665.    return (x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1);
  666. }
  667.  
  668. bool OnSegment(int x1, int y1, int x2, int y2, int x3, int y3) {
  669.    int minX = x1 < x2 ? x1 : x2;
  670.    int maxX = x1 > x2 ? x1 : x2;
  671.    int minY = y1 < y2 ? y1 : y2;
  672.    int maxY = y1 > y2 ? y1 : y2;
  673.  
  674.    if (minX <= x3 && x3 <= maxX && minY <= y3 && y3 <= maxY) {
  675.        return true;
  676.    }
  677.    return false;
  678. }
  679.  
  680. void MoveAsteroids() {
  681.    for (auto& ast : asteroids) {
  682.        ast.x += ast.speed * cos(ast.angle * 3.14159 / 180);
  683.        ast.y += ast.speed * sin(ast.angle * 3.14159 / 180);
  684.  
  685.        // Randomly adjust angle occasionally
  686.        if (rand() % 100 < 2) {
  687.            ast.angle += (rand() % 21 - 10); // Random turn between -10 and +10 degrees
  688.        }
  689.  
  690.        // Screen wrapping
  691.        if (ast.x < 0) ast.x = WIN_WIDTH;
  692.        if (ast.x > WIN_WIDTH) ast.x = 0;
  693.        if (ast.y < 0) ast.y = WIN_HEIGHT;
  694.        if (ast.y > WIN_HEIGHT) ast.y = 0;
  695.    }
  696. }
  697.  
  698. void ShootBullet() {
  699.    Bullet bullet;
  700.    // Calculate the tip of the triangle (point[0] is the top vertex)
  701.    bullet.x = playerX + player[0].x * cos(playerAngle * 3.14159 / 180)
  702.        - player[0].y * sin(playerAngle * 3.14159 / 180);
  703.    bullet.y = playerY + player[0].x * sin(playerAngle * 3.14159 / 180)
  704.        + player[0].y * cos(playerAngle * 3.14159 / 180);
  705.    // Adjust the bullet angle to match the ship's orientation
  706.     bullet.angle = playerAngle - 90;  // Subtract 90 degrees to align with the ship's nose
  707.     bullets.push_back(bullet);
  708. }
  709.  
  710. // Modified DrawBullet function for green bullets
  711. void DrawBullet(HDC hdc, int x, int y) {
  712.     HPEN greenPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));    // Bright green
  713.     HBRUSH greenBrush = CreateSolidBrush(RGB(0, 255, 0));      // Bright green
  714.     SelectObject(hdc, greenPen);
  715.     SelectObject(hdc, greenBrush);
  716.     Ellipse(hdc, x - 4, y - 4, x + 4, y + 4);
  717.     DeleteObject(greenPen);
  718.     DeleteObject(greenBrush);
  719. }
  720.  
  721. bool CheckBulletCollision(int bx, int by) {
  722.     for (auto it = asteroids.begin(); it != asteroids.end();) {
  723.         if (PointInPolygon(bx, by, it->shape, it->x, it->y)) {
  724.             //Beep(500, 50); // Add this line
  725.             it = asteroids.erase(it);
  726.             score += 10;
  727.             return true;
  728.         }
  729.         else {
  730.             ++it;
  731.         }
  732.     }
  733.     return false;
  734. }
  735.  
  736. bool PointInPolygon(int px, int py, POINT polygon[], int ox, int oy) {
  737.     int i, j, nvert = 8;
  738.     bool c = false;
  739.  
  740.     for (i = 0, j = nvert - 1; i < nvert; j = i++) {
  741.         int polyX1 = polygon[i].x + ox;
  742.         int polyY1 = polygon[i].y + oy;
  743.         int polyX2 = polygon[j].x + ox;
  744.         int polyY2 = polygon[j].y + oy;
  745.  
  746.         if (((polyY1 > py) != (polyY2 > py)) &&
  747.             (px < (polyX2 - polyX1) * (py - polyY1) / (polyY2 - polyY1) + polyX1)) {
  748.             c = !c;
  749.         }
  750.     }
  751.     return c;
  752. }
  753.  
  754. void GenerateAsteroids() {
  755.     int initialAsteroids = 3; // Start with fewer asteroids
  756.     for (int i = 0; i < initialAsteroids; ++i) {
  757.         Asteroid ast;
  758.         ast.x = rand() % WIN_WIDTH;
  759.         ast.y = rand() % WIN_HEIGHT;
  760.         ast.angle = rand() % 360;
  761.  
  762.         for (int j = 0; j < 8; ++j) {
  763.             int radius = 30 + rand() % 20;
  764.             double angle = j * 45.0 * 3.14159 / 180.0;
  765.             ast.shape[j].x = radius * cos(angle);
  766.             ast.shape[j].y = radius * sin(angle);
  767.         }
  768.         asteroids.push_back(ast);
  769.     }
  770. }
  771.  
  772. void SpawnNewAsteroid() {
  773.     if (asteroids.size() >= 6) return;
  774.  
  775.     Asteroid ast;
  776.     // Spawn from edges
  777.     if (rand() % 2 == 0) {
  778.         ast.x = (rand() % 2) * WIN_WIDTH;
  779.         ast.y = rand() % WIN_HEIGHT;
  780.     }
  781.     else {
  782.         ast.x = rand() % WIN_WIDTH;
  783.         ast.y = (rand() % 2) * WIN_HEIGHT;
  784.     }
  785.  
  786.     // Random angle between 0 and 360
  787.     ast.angle = rand() % 360;
  788.  
  789.     // Random speed variation
  790.     ast.speed = 1.0 + (rand() % 30) / 10.0; // Speed between 1.0 and 4.0
  791.  
  792.     for (int j = 0; j < 8; ++j) {
  793.         int radius = 30 + rand() % 20;
  794.         double angle = j * 45.0 * 3.14159 / 180.0;
  795.         ast.shape[j].x = radius * cos(angle);
  796.         ast.shape[j].y = radius * sin(angle);
  797.     }
  798.     asteroids.push_back(ast);
  799. }
  800.  
  801. // Add this function to initialize the stars (call it once in WinMain before the main loop)
  802. void InitStars() {
  803.     for (int i = 0; i < NUM_STARS; i++) {
  804.         stars[i].x = rand() % WIN_WIDTH;
  805.         stars[i].y = rand() % WIN_HEIGHT;
  806.         stars[i].brightness = 100 + (rand() % 156); // Random brightness between 100-255
  807.     }
  808. }
  809.  
  810. // Add this function to draw the starfield
  811. void DrawStarfield(HDC hdc) {
  812.     for (int i = 0; i < NUM_STARS; i++) {
  813.         int brightness = stars[i].brightness;
  814.         HPEN starPen = CreatePen(PS_SOLID, 1, RGB(brightness, brightness, brightness));
  815.         HBRUSH starBrush = CreateSolidBrush(RGB(brightness, brightness, brightness));
  816.         SelectObject(hdc, starPen);
  817.         SelectObject(hdc, starBrush);
  818.  
  819.         // Draw each star as a small circle
  820.         Ellipse(hdc, stars[i].x - 1, stars[i].y - 1,
  821.             stars[i].x + 1, stars[i].y + 1);
  822.  
  823.         DeleteObject(starPen);
  824.         DeleteObject(starBrush);
  825.  
  826.         // Optional: make stars twinkle
  827.         if (rand() % 100 < 5) { // 5% chance each frame
  828.             stars[i].brightness = 100 + (rand() % 156);
  829.         }
  830.     }
  831. }
  832.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement