alien_fx_fiend

Original Base Pool bkp

Aug 13th, 2024
30
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.24 KB | None | 0 0
  1. #include <windows.h>
  2. #include <vector>
  3. #include <cmath>
  4. #include <ctime>
  5.  
  6. #define ID_TIMER 1
  7. #define BALL_RADIUS 10
  8. #define TABLE_WIDTH 800
  9. #define TABLE_HEIGHT 400
  10.  
  11. HINSTANCE hInst;
  12. HWND hwnd;
  13. HDC hdcMem, hdcBall;
  14. HBITMAP hbmMem, hbmOld;
  15. HPEN hPen;
  16. HBRUSH hBrush;
  17. RECT table = { 50, 50, 850, 450 };
  18. POINT cueStart, cueEnd;
  19. bool isDragging = false;
  20. float power = 0.0f;
  21.  
  22. struct Ball {
  23.     float x, y;
  24.     float vx, vy;
  25.     COLORREF color;
  26.     bool isPocketed;
  27. };
  28.  
  29. std::vector<Ball> balls;
  30. Ball cueBall;
  31. bool playerTurn = true;
  32. bool gameOver = false;
  33.  
  34. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  35. void InitBalls();
  36. void DrawTable(HDC);
  37. void DrawBalls(HDC);
  38. void DrawCue(HDC);
  39. void DrawPowerMeter(HDC);
  40. void UpdateBalls();
  41. void CheckCollisions();
  42. void CheckPockets();
  43. void AIMove();
  44. void ApplyEnglish(Ball&, float, float);
  45. bool CheckGameOver();
  46.  
  47. int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow) {
  48.     hInst = hInstance;
  49.     WNDCLASS wc = {};
  50.     wc.lpfnWndProc = WndProc;
  51.     wc.hInstance = hInstance;
  52.     wc.lpszClassName = L"8BallPool";
  53.     RegisterClass(&wc);
  54.  
  55.     hwnd = CreateWindowEx(0, L"8BallPool", L"8-Ball Pool", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 900, 600, nullptr, nullptr, hInstance, nullptr);
  56.     ShowWindow(hwnd, nCmdShow);
  57.  
  58.     MSG msg = {};
  59.     while (GetMessage(&msg, nullptr, 0, 0)) {
  60.         TranslateMessage(&msg);
  61.         DispatchMessage(&msg);
  62.     }
  63.     return (int)msg.wParam;
  64. }
  65.  
  66. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  67.     switch (message) {
  68.     case WM_CREATE:
  69.         srand((unsigned int)time(NULL));
  70.         InitBalls();
  71.         SetTimer(hwnd, ID_TIMER, 16, NULL);
  72.         break;
  73.     case WM_PAINT: {
  74.         PAINTSTRUCT ps;
  75.         HDC hdc = BeginPaint(hwnd, &ps);
  76.         if (!hdcMem) {
  77.             hdcMem = CreateCompatibleDC(hdc);
  78.             hbmMem = CreateCompatibleBitmap(hdc, 900, 600);
  79.             hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
  80.         }
  81.         FillRect(hdcMem, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
  82.         DrawTable(hdcMem);
  83.         DrawBalls(hdcMem);
  84.         if (!gameOver && playerTurn) {
  85.             DrawCue(hdcMem);
  86.             DrawPowerMeter(hdcMem);
  87.         }
  88.         BitBlt(hdc, 0, 0, 900, 600, hdcMem, 0, 0, SRCCOPY);
  89.         EndPaint(hwnd, &ps);
  90.         break;
  91.     }
  92.     case WM_LBUTTONDOWN:
  93.         if (gameOver || !playerTurn) break;
  94.         cueStart.x = LOWORD(lParam);
  95.         cueStart.y = HIWORD(lParam);
  96.         isDragging = true;
  97.         break;
  98.     case WM_MOUSEMOVE:
  99.         if (isDragging) {
  100.             cueEnd.x = LOWORD(lParam);
  101.             cueEnd.y = HIWORD(lParam);
  102.             power = min(sqrt(pow(cueEnd.x - cueStart.x, 2) + pow(cueEnd.y - cueStart.y, 2)) / 100.0f, 1.0f);
  103.             InvalidateRect(hwnd, NULL, FALSE);
  104.         }
  105.         break;
  106.     case WM_LBUTTONUP:
  107.         if (isDragging) {
  108.             isDragging = false;
  109.             float dx = cueEnd.x - cueStart.x;
  110.             float dy = cueEnd.y - cueStart.y;
  111.             cueBall.vx = dx * power * 0.5f;
  112.             cueBall.vy = dy * power * 0.5f;
  113.             ApplyEnglish(cueBall, dx * power * 0.1f, dy * power * 0.1f);
  114.             playerTurn = false;
  115.             InvalidateRect(hwnd, NULL, FALSE);
  116.         }
  117.         break;
  118.     case WM_TIMER:
  119.         if (!gameOver) {
  120.             UpdateBalls();
  121.             CheckCollisions();
  122.             CheckPockets();
  123.             if (!playerTurn) AIMove();
  124.             if (CheckGameOver()) {
  125.                 gameOver = true;
  126.                 MessageBox(hwnd, L"Game Over! All balls are pocketed.", L"Game Over", MB_OK);
  127.             }
  128.             InvalidateRect(hwnd, NULL, FALSE);
  129.         }
  130.         break;
  131.     case WM_DESTROY:
  132.         KillTimer(hwnd, ID_TIMER);
  133.         SelectObject(hdcMem, hbmOld);
  134.         DeleteObject(hbmMem);
  135.         DeleteDC(hdcMem);
  136.         PostQuitMessage(0);
  137.         break;
  138.     default:
  139.         return DefWindowProc(hwnd, message, wParam, lParam);
  140.     }
  141.     return 0;
  142. }
  143.  
  144. void InitBalls() {
  145.     balls.clear();
  146.     cueBall = { 450.0f, 250.0f, 0.0f, 0.0f, RGB(255, 255, 255), false };
  147.     balls.push_back(cueBall);
  148.  
  149.     for (int i = 0; i < 7; ++i) {
  150.         float angle = (float)i / 7.0f * 3.14159f * 2.0f;
  151.         balls.push_back({ 600.0f + cos(angle) * 30, 250.0f + sin(angle) * 30, 0.0f, 0.0f, RGB(255, 255, 0), false });
  152.         balls.push_back({ 600.0f + cos(angle) * 60, 250.0f + sin(angle) * 60, 0.0f, 0.0f, RGB(255, 0, 0), false });
  153.     }
  154. }
  155.  
  156. void DrawTable(HDC hdc) {
  157.     HBRUSH hBrush = CreateSolidBrush(RGB(0, 128, 0));
  158.     FillRect(hdc, &table, hBrush);
  159.     DeleteObject(hBrush);
  160.  
  161.     for (int i = 0; i < 2; ++i) {
  162.         for (int j = 0; j < 3; ++j) {
  163.             Ellipse(hdc, table.left + j * TABLE_WIDTH / 2 - BALL_RADIUS, table.top + i * TABLE_HEIGHT - BALL_RADIUS, table.left + j * TABLE_WIDTH / 2 + BALL_RADIUS, table.top + i * TABLE_HEIGHT + BALL_RADIUS);
  164.         }
  165.     }
  166. }
  167.  
  168. void DrawBalls(HDC hdc) {
  169.     for (const auto& ball : balls) {
  170.         if (!ball.isPocketed) {
  171.             hBrush = CreateSolidBrush(ball.color);
  172.             SelectObject(hdc, hBrush);
  173.             Ellipse(hdc, (int)(ball.x - BALL_RADIUS), (int)(ball.y - BALL_RADIUS), (int)(ball.x + BALL_RADIUS), (int)(ball.y + BALL_RADIUS));
  174.             DeleteObject(hBrush);
  175.         }
  176.     }
  177. }
  178.  
  179. void DrawCue(HDC hdc) {
  180.     MoveToEx(hdc, (int)cueBall.x, (int)cueBall.y, NULL);
  181.     LineTo(hdc, cueEnd.x, cueEnd.y);
  182. }
  183.  
  184. void DrawPowerMeter(HDC hdc) {
  185.     HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 0));
  186.     RECT rect = { 10, 50, 30, 450 };
  187.     FillRect(hdc, &rect, hBrush);
  188.     DeleteObject(hBrush);
  189.  
  190.     hBrush = CreateSolidBrush(RGB(255, 255, 0));
  191.     rect.bottom = 450 - (int)(400 * power);
  192.     FillRect(hdc, &rect, hBrush);
  193.     DeleteObject(hBrush);
  194.  
  195.     hBrush = CreateSolidBrush(RGB(255, 0, 0));
  196.     rect.bottom = 450 - (int)(400 * power / 2);
  197.     FillRect(hdc, &rect, hBrush);
  198.     DeleteObject(hBrush);
  199. }
  200.  
  201. void UpdateBalls() {
  202.     for (auto& ball : balls) {
  203.         if (!ball.isPocketed) {
  204.             ball.x += ball.vx;
  205.             ball.y += ball.vy;
  206.             ball.vx *= 0.99f;
  207.             ball.vy *= 0.99f;
  208.             if (fabs(ball.vx) < 0.01f) ball.vx = 0.0f;
  209.             if (fabs(ball.vy) < 0.01f) ball.vy = 0.0f;
  210.         }
  211.     }
  212. }
  213.  
  214. void CheckCollisions() {
  215.     for (size_t i = 0; i < balls.size(); ++i) {
  216.         for (size_t j = i + 1; j < balls.size(); ++j) {
  217.             Ball& b1 = balls[i];
  218.             Ball& b2 = balls[j];
  219.  
  220.             if (!b1.isPocketed && !b2.isPocketed) {
  221.                 float dx = b2.x - b1.x;
  222.                 float dy = b2.y - b1.y;
  223.                 float dist = sqrt(dx * dx + dy * dy);
  224.                 if (dist < BALL_RADIUS * 2) {
  225.                     float angle = atan2(dy, dx);
  226.                     float sinA = sin(angle);
  227.                     float cosA = cos(angle);
  228.  
  229.                     // Rotate ball positions
  230.                     float x1 = 0;
  231.                     float y1 = 0;
  232.                     float x2 = dx * cosA + dy * sinA;
  233.                     float y2 = dy * cosA - dx * sinA;
  234.  
  235.                     // Rotate velocities
  236.                     float vx1 = b1.vx * cosA + b1.vy * sinA;
  237.                     float vy1 = b1.vy * cosA - b1.vx * sinA;
  238.                     float vx2 = b2.vx * cosA + b2.vy * sinA;
  239.                     float vy2 = b2.vy * cosA - b2.vx * sinA;
  240.  
  241.                     // Collision reaction
  242.                     float vx1Final = ((BALL_RADIUS - BALL_RADIUS) * vx1 + (2 * BALL_RADIUS) * vx2) / (BALL_RADIUS + BALL_RADIUS);
  243.                     float vx2Final = ((BALL_RADIUS - BALL_RADIUS) * vx2 + (2 * BALL_RADIUS) * vx1) / (BALL_RADIUS + BALL_RADIUS);
  244.  
  245.                     // Update positions to avoid overlap
  246.                     x1 += vx1Final;
  247.                     x2 += vx2Final;
  248.  
  249.                     // Rotate positions and velocities back
  250.                     b1.x = b1.x + (x1 * cosA - y1 * sinA);
  251.                     b1.y = b1.y + (y1 * cosA + x1 * sinA);
  252.                     b2.x = b1.x + (x2 * cosA - y2 * sinA);
  253.                     b2.y = b1.y + (y2 * cosA + x2 * sinA);
  254.  
  255.                     b1.vx = vx1Final * cosA - vy1 * sinA;
  256.                     b1.vy = vy1 * cosA + vx1Final * sinA;
  257.                     b2.vx = vx2Final * cosA - vy2 * sinA;
  258.                     b2.vy = vy2 * cosA + vx2Final * sinA;
  259.                 }
  260.             }
  261.         }
  262.  
  263.         // Table boundary collision
  264.         if (!balls[i].isPocketed) {
  265.             if (balls[i].x - BALL_RADIUS < table.left) {
  266.                 balls[i].x = table.left + BALL_RADIUS;
  267.                 balls[i].vx = -balls[i].vx;
  268.             }
  269.             if (balls[i].x + BALL_RADIUS > table.right) {
  270.                 balls[i].x = table.right - BALL_RADIUS;
  271.                 balls[i].vx = -balls[i].vx;
  272.             }
  273.             if (balls[i].y - BALL_RADIUS < table.top) {
  274.                 balls[i].y = table.top + BALL_RADIUS;
  275.                 balls[i].vy = -balls[i].vy;
  276.             }
  277.             if (balls[i].y + BALL_RADIUS > table.bottom) {
  278.                 balls[i].y = table.bottom - BALL_RADIUS;
  279.                 balls[i].vy = -balls[i].vy;
  280.             }
  281.         }
  282.     }
  283. }
  284.  
  285. void CheckPockets() {
  286.     for (auto& ball : balls) {
  287.         if (!ball.isPocketed) {
  288.             for (int i = 0; i < 2; ++i) {
  289.                 for (int j = 0; j < 3; ++j) {
  290.                     POINT pocket = { table.left + j * TABLE_WIDTH / 2, table.top + i * TABLE_HEIGHT };
  291.                     float dx = ball.x - pocket.x;
  292.                     float dy = ball.y - pocket.y;
  293.                     if (sqrt(dx * dx + dy * dy) < BALL_RADIUS) {
  294.                         ball.isPocketed = true;
  295.                         ball.vx = ball.vy = 0;
  296.  
  297.                         if (ball.color == RGB(255, 255, 255)) {
  298.                             cueBall.x = 450.0f;
  299.                             cueBall.y = 250.0f;
  300.                             cueBall.vx = cueBall.vy = 0.0f;
  301.                             cueBall.isPocketed = false;
  302.                         }
  303.                     }
  304.                 }
  305.             }
  306.         }
  307.     }
  308. }
  309.  
  310. void AIMove() {
  311.     if (playerTurn || gameOver) return;
  312.  
  313.     // Simple AI: hit the nearest ball
  314.     Ball* targetBall = nullptr;
  315.     float minDist = FLT_MAX;
  316.     for (auto& ball : balls) {
  317.         if (&ball != &cueBall && !ball.isPocketed) {
  318.             float dx = ball.x - cueBall.x;
  319.             float dy = ball.y - cueBall.y;
  320.             float dist = sqrt(dx * dx + dy * dy);
  321.             if (dist < minDist) {
  322.                 minDist = dist;
  323.                 targetBall = &ball;
  324.             }
  325.         }
  326.     }
  327.  
  328.     if (targetBall) {
  329.         float angle = atan2(targetBall->y - cueBall.y, targetBall->x - cueBall.x);
  330.         cueBall.vx = cos(angle) * 5;
  331.         cueBall.vy = sin(angle) * 5;
  332.     }
  333.  
  334.     playerTurn = true;
  335. }
  336.  
  337. void ApplyEnglish(Ball& ball, float englishX, float englishY) {
  338.     ball.vx += englishX * 0.05f;
  339.     ball.vy += englishY * 0.05f;
  340.     // Apply friction effect to English
  341.     ball.vx *= 0.98f;
  342.     ball.vy *= 0.98f;
  343. }
  344.  
  345. bool CheckGameOver() {
  346.     bool allPocketed = true;
  347.     for (const auto& ball : balls) {
  348.         if (&ball != &cueBall && !ball.isPocketed) {
  349.             allPocketed = false;
  350.             break;
  351.         }
  352.     }
  353.     return allPocketed;
  354. }
Add Comment
Please, Sign In to add comment