Advertisement
alien_fx_fiend

Asteroids Game Latest Needs Fixing (Reverting)

Nov 1st, 2024
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.12 KB | Source Code | 0 0
  1. #include <windows.h>
  2. #include <vector>
  3. #include <cmath>
  4. #include <ctime>
  5. #include <algorithm>  // Include this header for std::min and std::max
  6. #include "resource.h"
  7.  
  8. #define WIN_WIDTH 800
  9. #define WIN_HEIGHT 600
  10. // Add with other global variables
  11. bool keyStates[256] = { false };  // Track key states
  12. bool godMode = false; // Track God Mode state
  13. bool paused = false; // Track paused state
  14.  
  15. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  16. void DrawTriangle(HDC hdc, POINT pts[], int x, int y, double angle);
  17. void DrawAsteroid(HDC hdc, POINT pts[], int x, int y, double angle);
  18. bool CheckCollision(POINT player[], POINT asteroid[], int px, int py, int ax, int ay);
  19. void MoveAsteroids();
  20. void ShootBullet();
  21. void DrawBullet(HDC hdc, int x, int y);
  22. bool CheckBulletCollision(int bx, int by);
  23. bool DoLinesIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
  24. int Direction(int x1, int y1, int x2, int y2, int x3, int y3);
  25. bool OnSegment(int x1, int y1, int x2, int y2, int x3, int y3);
  26. bool PointInPolygon(int px, int py, POINT polygon[], int ox, int oy);
  27. void GenerateAsteroids();
  28. void SpawnNewAsteroid();
  29. void UpdatePlayerMovement();
  30.  
  31. struct Asteroid {
  32.     int x, y;
  33.     double angle;
  34.     POINT shape[8];
  35. };
  36.  
  37. struct Bullet {
  38.     int x, y;
  39.     double angle;
  40. };
  41.  
  42. std::vector<Asteroid> asteroids;
  43. std::vector<Bullet> bullets;
  44. POINT player[3] = { {0, -30}, {20, 20}, {-20, 20} };
  45. int playerX = WIN_WIDTH / 2, playerY = WIN_HEIGHT / 2;
  46. double playerAngle = 0;
  47. int score = 0;
  48. int lives = 3;
  49.  
  50.  
  51. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  52.     WNDCLASSEX wcex;
  53.     HWND hwnd;
  54.     MSG msg;
  55.  
  56.     wcex.cbSize = sizeof(WNDCLASSEX);
  57.     wcex.style = CS_HREDRAW | CS_VREDRAW;
  58.     wcex.lpfnWndProc = WndProc;
  59.     wcex.cbClsExtra = 0;
  60.     wcex.cbWndExtra = 0;
  61.     wcex.hInstance = hInstance;
  62.     wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  63.     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  64.     wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  65.     wcex.lpszMenuName = NULL;
  66.     wcex.lpszClassName = TEXT("Asteroids");
  67.     wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON1));
  68.     //wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  69.  
  70.     RegisterClassEx(&wcex);
  71.  
  72.     // Get the screen dimensions
  73.     int screenWidth = GetSystemMetrics(SM_CXSCREEN);
  74.     int screenHeight = GetSystemMetrics(SM_CYSCREEN);
  75.  
  76.     // Calculate the window position to center it
  77.     int windowWidth = WIN_WIDTH + 16;
  78.     int windowHeight = WIN_HEIGHT + 39;
  79.     int posX = (screenWidth - windowWidth) / 2;
  80.     int posY = (screenHeight - windowHeight) / 2;
  81.  
  82.     hwnd = CreateWindow(TEXT("Asteroids"), TEXT("Asteroids ArrowKeys=Controls Space=Shoot F1=GodMode P=Pause F2=About Escape=Quit"), WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
  83.         posX, posY, windowWidth + 16, windowHeight + 39, NULL, NULL, hInstance, NULL);
  84.  
  85.     ShowWindow(hwnd, SW_SHOW); // Instead of ShowWindow(hwnd, nCmdShow);
  86.     UpdateWindow(hwnd);
  87.  
  88.     srand(static_cast<unsigned int>(time(0)));
  89.  
  90.     GenerateAsteroids();
  91.  
  92.     LARGE_INTEGER freq, startTime, endTime;
  93.     QueryPerformanceFrequency(&freq);
  94.     QueryPerformanceCounter(&startTime);
  95.  
  96.     // Main game loop
  97.     while (true) {
  98.         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  99.             if (msg.message == WM_QUIT) break;
  100.             TranslateMessage(&msg);
  101.             DispatchMessage(&msg);
  102.         }
  103.         else {
  104.             // Only update game state if not paused
  105.             if (!paused) {
  106.                 UpdatePlayerMovement();
  107.                 for (auto& ast : asteroids) {
  108.                     if (!godMode && CheckCollision(player, ast.shape, playerX, playerY, ast.x, ast.y)) {
  109.                         lives--;
  110.                         if (lives <= 0) {
  111.                             MessageBox(hwnd, TEXT("Game Over!"), TEXT("Asteroids"), MB_OK);
  112.                             PostQuitMessage(0);
  113.                         }
  114.                         playerX = WIN_WIDTH / 2;
  115.                         playerY = WIN_HEIGHT / 2;
  116.                         playerAngle = 0;
  117.                         memset(keyStates, 0, sizeof(keyStates));
  118.                     }
  119.                 }
  120.                 if (rand() % 100 < 2) {
  121.                     SpawnNewAsteroid();
  122.                 }
  123.  
  124.                 MoveAsteroids();
  125.                 for (auto it = bullets.begin(); it != bullets.end();) {
  126.                     it->x += 10 * cos(it->angle * 3.14159 / 180);
  127.                     it->y += 10 * sin(it->angle * 3.14159 / 180);
  128.  
  129.                     if (CheckBulletCollision(it->x, it->y)) {
  130.                         it = bullets.erase(it);
  131.                     }
  132.                     else {
  133.                         ++it;
  134.                     }
  135.                 }
  136.             }
  137.             RECT clientRect;
  138.             GetClientRect(hwnd, &clientRect);
  139.             InvalidateRect(hwnd, &clientRect, TRUE); // Invalidate with TRUE
  140.         }
  141.         QueryPerformanceCounter(&endTime);
  142.         double elapsedTime = (endTime.QuadPart - startTime.QuadPart) / (double)freq.QuadPart;
  143.         if (elapsedTime < 0.016) { // Cap at approximately 60 FPS
  144.             Sleep((DWORD)((0.016 - elapsedTime) * 1000));
  145.         }
  146.         QueryPerformanceCounter(&startTime); // Reset for next frame
  147.     }
  148.  
  149.  
  150.     return (int)msg.wParam;
  151. }
  152.  
  153.  
  154. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  155.     static HDC hdcMem;
  156.     static HBITMAP hbmMem;
  157.     static HBITMAP hbmOld;
  158.     static HBRUSH hbrBkGnd;
  159.     static RECT rect;
  160.     PAINTSTRUCT ps;
  161.     static TCHAR scoreText[50];
  162.  
  163.     switch (msg) {
  164.     case WM_CREATE:
  165.         GetClientRect(hwnd, &rect);
  166.         hdcMem = CreateCompatibleDC(NULL);
  167.         hbmMem = CreateCompatibleBitmap(GetDC(hwnd), rect.right, rect.bottom);
  168.         hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
  169.         hbrBkGnd = (HBRUSH)GetStockObject(BLACK_BRUSH); // Use black background brush
  170.         SelectObject(hdcMem, hbrBkGnd); // Select background brush here
  171.         ValidateRect(hwnd, &rect); // Validate client area to prevent initial WM_PAINT
  172.         break;
  173.  
  174.     case WM_PAINT: {
  175.         HDC hdc = BeginPaint(hwnd, &ps);
  176.  
  177.         FillRect(hdcMem, &rect, hbrBkGnd);
  178.  
  179.         DrawTriangle(hdcMem, player, playerX, playerY, playerAngle);
  180.  
  181.         for (auto& ast : asteroids) {
  182.             DrawAsteroid(hdcMem, ast.shape, ast.x, ast.y, ast.angle);
  183.         }
  184.  
  185.         for (auto& bullet : bullets) {
  186.             DrawBullet(hdcMem, bullet.x, bullet.y);
  187.         }
  188.  
  189.         SetTextColor(hdcMem, RGB(255, 255, 255));
  190.         SetBkMode(hdcMem, TRANSPARENT);
  191.         wsprintf(scoreText, TEXT("Score: %d  Lives: %d"), score, lives);
  192.         TextOut(hdcMem, 10, 10, scoreText, lstrlen(scoreText));
  193.  
  194.         if (godMode) {
  195.             TextOut(hdcMem, WIN_WIDTH / 2 - 50, 10, TEXT("God Mode"), 8);
  196.         }
  197.  
  198.         if (paused) {
  199.             TextOut(hdcMem, WIN_WIDTH / 2 - 50, WIN_HEIGHT / 2 - 10, TEXT("Game Paused"), 10);
  200.         }
  201.  
  202.         BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
  203.         EndPaint(hwnd, &ps);
  204.         break;
  205.     }
  206.  
  207.     case WM_KEYDOWN:
  208.         keyStates[wParam] = true;
  209.         if (wParam == VK_F1) {
  210.             godMode = !godMode; // Toggle God Mode
  211.         }
  212.         else if (wParam == 'P') {
  213.             paused = !paused; // Toggle Pause
  214.         }
  215.         if (wParam == VK_ESCAPE) {
  216.             PostQuitMessage(0);
  217.             return 0;
  218.         }
  219.         // Add this new code block
  220.         else if (wParam == VK_F2) {
  221.             MessageBox(hwnd, TEXT("Asteroids v10.8 Basic GDI-Based C++ Win32 Game (384 lines of code) by Entisoft Software (c) Evans Thorpemorton"), TEXT("About"), MB_OK | MB_ICONINFORMATION);
  222.         }
  223.         break;
  224.  
  225.     case WM_KEYUP:
  226.         keyStates[wParam] = false;
  227.         break;
  228.  
  229.     case WM_DESTROY:
  230.         SelectObject(hdcMem, hbmOld);
  231.         DeleteObject(hbrBkGnd); // Deselect and delete the brush here
  232.         DeleteObject(hbmMem);
  233.         DeleteDC(hdcMem);
  234.         PostQuitMessage(0);
  235.         break;
  236.  
  237.     default:
  238.         return DefWindowProc(hwnd, msg, wParam, lParam);
  239.     }
  240.     return 0;
  241. }
  242.  
  243. void DrawTriangle(HDC hdc, POINT pts[], int x, int y, double angle) {
  244.     POINT rotated[3];
  245.     for (int i = 0; i < 3; ++i) {
  246.         rotated[i].x = pts[i].x * cos(angle * 3.14159 / 180) - pts[i].y * sin(angle * 3.14159 / 180);
  247.         rotated[i].y = pts[i].x * sin(angle * 3.14159 / 180) + pts[i].y * cos(angle * 3.14159 / 180);
  248.         rotated[i].x += x;
  249.         rotated[i].y += y;
  250.     }
  251.     // In DrawTriangle function, before Polygon call
  252.     HPEN hotPinkPen = CreatePen(PS_SOLID, 1, RGB(255, 20, 147));
  253.     HBRUSH hotPinkBrush = CreateSolidBrush(RGB(255, 20, 147));
  254.     SelectObject(hdc, hotPinkPen);
  255.     SelectObject(hdc, hotPinkBrush);
  256.     Polygon(hdc, rotated, 3);
  257.     DeleteObject(hotPinkPen);
  258.     DeleteObject(hotPinkBrush);
  259. }
  260.  
  261. void DrawAsteroid(HDC hdc, POINT pts[], int x, int y, double angle) {
  262.     POINT rotated[8];
  263.     for (int i = 0; i < 8; ++i) {
  264.         rotated[i].x = pts[i].x * cos(angle * 3.14159 / 180) - pts[i].y * sin(angle * 3.14159 / 180);
  265.         rotated[i].y = pts[i].x * sin(angle * 3.14159 / 180) + pts[i].y * cos(angle * 3.14159 / 180);
  266.         rotated[i].x += x;
  267.         rotated[i].y += y;
  268.     }
  269.  
  270.     // In DrawAsteroid function, before Polygon call
  271.     HPEN goldPen = CreatePen(PS_SOLID, 1, RGB(255, 215, 0));
  272.     HBRUSH goldBrush = CreateSolidBrush(RGB(255, 215, 0));
  273.     SelectObject(hdc, goldPen);
  274.     SelectObject(hdc, goldBrush);
  275.     Polygon(hdc, rotated, 8);
  276.     DeleteObject(goldPen);
  277.     DeleteObject(goldBrush);
  278. }
  279.  
  280. void UpdatePlayerMovement() {
  281.     if (keyStates[VK_LEFT]) {
  282.         playerAngle -= 5;
  283.     }
  284.     if (keyStates[VK_RIGHT]) {
  285.         playerAngle += 5;
  286.     }
  287.     if (keyStates[VK_UP]) {
  288.         playerX += 5 * cos((playerAngle - 90) * 3.14159 / 180);
  289.         playerY += 5 * sin((playerAngle - 90) * 3.14159 / 180);
  290.     }
  291.     // Add to UpdatePlayerMovement() function
  292.     if (keyStates[VK_DOWN]) {
  293.         playerX -= 5 * cos((playerAngle - 90) * 3.14159 / 180);
  294.         playerY -= 5 * sin((playerAngle - 90) * 3.14159 / 180);
  295.     }
  296.     // Add to UpdatePlayerMovement() function
  297.     static int shootCooldown = 0;
  298.     if (keyStates[VK_SPACE] && shootCooldown == 0) {
  299.         ShootBullet();
  300.         shootCooldown = 10; // Adjust this value to control firing rate
  301.     }
  302.     if (shootCooldown > 0) {
  303.         shootCooldown--;
  304.     }
  305.  
  306.     // Wrap around screen
  307.     if (playerX < 0) playerX = WIN_WIDTH;
  308.     if (playerX > WIN_WIDTH) playerX = 0;
  309.     if (playerY < 0) playerY = WIN_HEIGHT;
  310.     if (playerY > WIN_HEIGHT) playerY = 0;
  311. }
  312.  
  313. bool CheckCollision(POINT player[], POINT asteroid[], int px, int py, int ax, int ay) {
  314.     for (int i = 0; i < 3; ++i) {
  315.         int px1 = player[i].x + px;
  316.         int py1 = player[i].y + py;
  317.         int px2 = player[(i + 1) % 3].x + px;
  318.         int py2 = player[(i + 1) % 3].y + py;
  319.  
  320.         for (int j = 0; j < 8; ++j) {
  321.             int ax1 = asteroid[j].x + ax;
  322.             int ay1 = asteroid[j].y + ay;
  323.             int ax2 = asteroid[(j + 1) % 8].x + ax;
  324.             int ay2 = asteroid[(j + 1) % 8].y + ay;
  325.  
  326.             // Check if the line segments intersect
  327.             if (DoLinesIntersect(px1, py1, px2, py2, ax1, ay1, ax2, ay2)) {
  328.                 return true;
  329.             }
  330.         }
  331.     }
  332.     return false;
  333. }
  334.  
  335. bool DoLinesIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
  336.     // Calculate the direction of the lines
  337.     int d1 = Direction(x3, y3, x4, y4, x1, y1);
  338.     int d2 = Direction(x3, y3, x4, y4, x2, y2);
  339.     int d3 = Direction(x1, y1, x2, y2, x3, y3);
  340.     int d4 = Direction(x1, y1, x2, y2, x4, y4);
  341.  
  342.     // Check if the lines intersect
  343.     if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) {
  344.         return true;
  345.     }
  346.  
  347.     // Check for collinear points
  348.     if (d1 == 0 && OnSegment(x3, y3, x4, y4, x1, y1)) return true;
  349.     if (d2 == 0 && OnSegment(x3, y3, x4, y4, x2, y2)) return true;
  350.     if (d3 == 0 && OnSegment(x1, y1, x2, y2, x3, y3)) return true;
  351.     if (d4 == 0 && OnSegment(x1, y1, x2, y2, x4, y4)) return true;
  352.  
  353.     return false;
  354. }
  355.  
  356. int Direction(int x1, int y1, int x2, int y2, int x3, int y3) {
  357.     return (x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1);
  358. }
  359.  
  360. bool OnSegment(int x1, int y1, int x2, int y2, int x3, int y3) {
  361.     int minX = x1 < x2 ? x1 : x2;
  362.     int maxX = x1 > x2 ? x1 : x2;
  363.     int minY = y1 < y2 ? y1 : y2;
  364.     int maxY = y1 > y2 ? y1 : y2;
  365.  
  366.     if (minX <= x3 && x3 <= maxX && minY <= y3 && y3 <= maxY) {
  367.         return true;
  368.     }
  369.     return false;
  370. }
  371.  
  372. void MoveAsteroids() {
  373.     for (auto& ast : asteroids) {
  374.         ast.x += 2 * cos(ast.angle * 3.14159 / 180);
  375.         ast.y += 2 * sin(ast.angle * 3.14159 / 180);
  376.  
  377.         // Wrap around screen
  378.         if (ast.x < 0) ast.x = WIN_WIDTH;
  379.         if (ast.x > WIN_WIDTH) ast.x = 0;
  380.         if (ast.y < 0) ast.y = WIN_HEIGHT;
  381.         if (ast.y > WIN_HEIGHT) ast.y = 0;
  382.     }
  383. }
  384.  
  385. void ShootBullet() {
  386.     Bullet bullet;
  387.     // Calculate the tip of the triangle (point[0] is the top vertex)
  388.     bullet.x = playerX + player[0].x * cos(playerAngle * 3.14159 / 180)
  389.         - player[0].y * sin(playerAngle * 3.14159 / 180);
  390.     bullet.y = playerY + player[0].x * sin(playerAngle * 3.14159 / 180)
  391.         + player[0].y * cos(playerAngle * 3.14159 / 180);
  392.     // Adjust the bullet angle to match the ship's orientation
  393.     bullet.angle = playerAngle - 90;  // Subtract 90 degrees to align with the ship's nose
  394.     bullets.push_back(bullet);
  395. }
  396.  
  397. // Modified DrawBullet function for green bullets
  398. void DrawBullet(HDC hdc, int x, int y) {
  399.     HPEN greenPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));    // Bright green
  400.     HBRUSH greenBrush = CreateSolidBrush(RGB(0, 255, 0));      // Bright green
  401.     SelectObject(hdc, greenPen);
  402.     SelectObject(hdc, greenBrush);
  403.     Ellipse(hdc, x - 4, y - 4, x + 4, y + 4);
  404.     DeleteObject(greenPen);
  405.     DeleteObject(greenBrush);
  406. }
  407.  
  408. bool CheckBulletCollision(int bx, int by) {
  409.     for (auto it = asteroids.begin(); it != asteroids.end();) {
  410.         if (PointInPolygon(bx, by, it->shape, it->x, it->y)) {
  411.             it = asteroids.erase(it);
  412.             score += 10;
  413.             return true;
  414.         }
  415.         else {
  416.             ++it;
  417.         }
  418.     }
  419.     return false;
  420. }
  421.  
  422. bool PointInPolygon(int px, int py, POINT polygon[], int ox, int oy) {
  423.     int i, j, nvert = 8;
  424.     bool c = false;
  425.  
  426.     for (i = 0, j = nvert - 1; i < nvert; j = i++) {
  427.         int polyX1 = polygon[i].x + ox;
  428.         int polyY1 = polygon[i].y + oy;
  429.         int polyX2 = polygon[j].x + ox;
  430.         int polyY2 = polygon[j].y + oy;
  431.  
  432.         if (((polyY1 > py) != (polyY2 > py)) &&
  433.             (px < (polyX2 - polyX1) * (py - polyY1) / (polyY2 - polyY1) + polyX1)) {
  434.             c = !c;
  435.         }
  436.     }
  437.     return c;
  438. }
  439.  
  440. void GenerateAsteroids() {
  441.     for (int i = 0; i < 5; ++i) {
  442.         Asteroid ast;
  443.         ast.x = rand() % WIN_WIDTH;
  444.         ast.y = rand() % WIN_HEIGHT;
  445.         ast.angle = rand() % 360;
  446.         for (int j = 0; j < 8; ++j) {
  447.             double angle = j * 45 * 3.14159 / 180;
  448.             ast.shape[j].x = (rand() % 20 + 10) * cos(angle);
  449.             ast.shape[j].y = (rand() % 20 + 10) * sin(angle);
  450.         }
  451.         asteroids.push_back(ast);
  452.     }
  453. }
  454.  
  455. void SpawnNewAsteroid() {
  456.     Asteroid ast;
  457.     // Randomly choose a side of the screen to spawn from
  458.     int side = rand() % 4;
  459.     switch (side) {
  460.     case 0: // Top
  461.         ast.x = rand() % WIN_WIDTH;
  462.         ast.y = -30;
  463.         break;
  464.     case 1: // Right
  465.         ast.x = WIN_WIDTH + 30;
  466.         ast.y = rand() % WIN_HEIGHT;
  467.         break;
  468.     case 2: // Bottom
  469.         ast.x = rand() % WIN_WIDTH;
  470.         ast.y = WIN_HEIGHT + 30;
  471.         break;
  472.     case 3: // Left
  473.         ast.x = -30;
  474.         ast.y = rand() % WIN_HEIGHT;
  475.         break;
  476.     }
  477.  
  478.     ast.angle = rand() % 360;
  479.     for (int j = 0; j < 8; ++j) {
  480.         double angle = j * 45 * 3.14159 / 180;
  481.         ast.shape[j].x = (rand() % 20 + 10) * cos(angle);
  482.         ast.shape[j].y = (rand() % 20 + 10) * sin(angle);
  483.     }
  484.     asteroids.push_back(ast);
  485. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement