Advertisement
alien_fx_fiend

Full 8 Ball Y!Pool Java Clone Code With Features (C++ Win32 GDI-Based)

Jul 23rd, 2024
197
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 20.52 KB | None | 0 0
  1. ```cpp
  2. #include <windows.h>
  3. #include <vector>
  4. #include <cmath>
  5. #include <ctime>
  6.  
  7. #define ID_TIMER 1
  8. #define BALL_RADIUS 10
  9. #define TABLE_WIDTH 800
  10. #define TABLE_HEIGHT 400
  11. #define BALL_COUNT 16
  12.  
  13. HINSTANCE hInst;
  14. HWND hwnd;
  15. HDC hdcMem, hdcBall;
  16. HBITMAP hbmMem, hbmOld;
  17. HPEN hPen;
  18. HBRUSH hBrush;
  19. RECT table = { 50, 50, 850, 450 };
  20. POINT cueStart, cueEnd;
  21. bool isDragging = false;
  22. float power = 0.0f;
  23. int playerColors[2] = { 0, 0 };
  24. int currentPlayer = 0;
  25.  
  26. struct Ball {
  27.     float x, y;
  28.     float vx, vy;
  29.     COLORREF color;
  30.     bool isPocketed;
  31.     bool isStriped;
  32. };
  33.  
  34. std::vector<Ball> balls;
  35. Ball cueBall;
  36. bool playerTurn = true;
  37. bool gameOver = false;
  38.  
  39. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  40. void InitBalls();
  41. void DrawTable(HDC);
  42. void DrawBalls(HDC);
  43. void DrawCue(HDC);
  44. void DrawPowerMeter(HDC);
  45. void UpdateBalls();
  46. void CheckCollisions();
  47. void CheckPockets();
  48. void AIMove();
  49. void ApplyEnglish(Ball&, float, float);
  50. bool CheckGameOver();
  51. void AssignPlayerColor(COLORREF);
  52. void HandleFoul();
  53.  
  54. int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow) {
  55.     hInst = hInstance;
  56.     WNDCLASS wc = {};
  57.     wc.lpfnWndProc = WndProc;
  58.     wc.hInstance = hInstance;
  59.     wc.lpszClassName = L"8BallPool";
  60.     RegisterClass(&wc);
  61.  
  62.     hwnd = CreateWindowEx(0, L"8BallPool", L"8-Ball Pool", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 900, 600, nullptr, nullptr, hInstance, nullptr);
  63.     ShowWindow(hwnd, nCmdShow);
  64.  
  65.     MSG msg = {};
  66.     while (GetMessage(&msg, nullptr, 0, 0)) {
  67.         TranslateMessage(&msg);
  68.         DispatchMessage(&msg);
  69.     }
  70.     return (int)msg.wParam;
  71. }
  72.  
  73. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  74.     switch (message) {
  75.     case WM_CREATE:
  76.         srand((unsigned int)time(NULL));
  77.         InitBalls();
  78.         SetTimer(hwnd, ID_TIMER, 16, NULL);
  79.         break;
  80.     case WM_PAINT: {
  81.         PAINTSTRUCT ps;
  82.         HDC hdc = BeginPaint(hwnd, &ps);
  83.         if (!hdcMem) {
  84.             hdcMem = CreateCompatibleDC(hdc);
  85.             hbmMem = CreateCompatibleBitmap(hdc, 900, 600);
  86.             hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
  87.         }
  88.         FillRect(hdcMem, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
  89.         DrawTable(hdcMem);
  90.         DrawBalls(hdcMem);
  91.         if (!gameOver && playerTurn) {
  92.             DrawCue(hdcMem);
  93.             DrawPowerMeter(hdcMem);
  94.         }
  95.         BitBlt(hdc, 0, 0, 900, 600, hdcMem, 0, 0, SRCCOPY);
  96.         EndPaint(hwnd, &ps);
  97.         break;
  98.     }
  99.     case WM_LBUTTONDOWN:
  100.         if (gameOver || !playerTurn) break;
  101.         cueStart.x = LOWORD(lParam);
  102.         cueStart.y = HIWORD(lParam);
  103.         isDragging = true;
  104.         break;
  105.     case WM_MOUSEMOVE:
  106.         if (isDragging) {
  107.             cueEnd.x = LOWORD(lParam);
  108.             cueEnd.y = HIWORD(lParam);
  109.             power = min(sqrt(pow(cueEnd.x - cueStart.x, 2) + pow(cueEnd.y - cueStart.y, 2)) / 100.0f, 1.0f);
  110.             InvalidateRect(hwnd, NULL, FALSE);
  111.         }
  112.         break;
  113.     case WM_LBUTTONUP:
  114.         if (isDragging) {
  115.             isDragging = false;
  116.             float dx = cueEnd.x - cueStart.x;
  117.             float dy = cueEnd.y - cueStart.y;
  118.             cueBall.vx = dx * power * 0.5f;
  119.             cueBall.vy = dy * power * 0.5f;
  120.             ApplyEnglish(cueBall, dx * power * 0.1f, dy * power * 0.1f);
  121.             playerTurn = false;
  122.             InvalidateRect(hwnd, NULL, FALSE);
  123.         }
  124.         break;
  125.     case WM_TIMER:
  126.         if (!gameOver) {
  127.             UpdateBalls();
  128.             CheckCollisions();
  129.             CheckPockets();
  130.             if (!playerTurn) AIMove();
  131.             if (CheckGameOver()) {
  132.                 gameOver = true;
  133.                 MessageBox(hwnd, L"Game Over! All balls are pocketed.", L"Game Over", MB_OK);
  134.             }
  135.             InvalidateRect(hwnd, NULL, FALSE);
  136.         }
  137.         break;
  138.     case WM_DESTROY:
  139.         KillTimer(hwnd, ID_TIMER);
  140.         SelectObject(hdcMem, hbmOld);
  141.         DeleteObject(hbmMem);
  142.         DeleteDC(hdcMem);
  143.         PostQuitMessage(0);
  144.         break;
  145.     default:
  146.         return DefWindowProc(hwnd, message, wParam, lParam);
  147.     }
  148.     return 0;
  149. }
  150.  
  151. void InitBalls() {
  152.     balls.clear();
  153.     cueBall = { 200.0f, 250.0f, 0.0f, 0.0f, RGB(255, 255, 255), false, false };
  154.     balls.push_back(cueBall);
  155.  
  156.     std::vector<COLORREF> colors = {
  157.         RGB(255, 255, 0), RGB(255, 0, 0), RGB(255, 255, 0), RGB(255, 0, 0),
  158.         RGB(255, 255, 0), RGB(255, 0, 0), RGB(255, 255, 0), RGB(255, 0, 0),
  159.         RGB(255, 255, 0), RGB(255, 0, 0), RGB(255, 255, 0), RGB(255, 0, 0),
  160.         RGB(255, 255, 0), RGB(255, 0, 0), RGB(0, 0, 0)
  161.     };
  162.  
  163.     float startX = 600.0f;
  164.     float startY = 250.0f;
  165.     int colorIndex = 0;
  166.  
  167.     for (int row = 0; row < 5; ++row) {
  168.         for (int col = 0; col <= row; ++col) {
  169.             float x = startX + row * 2 * BALL_RADIUS * cosf(M_PI / 3);
  170.             float y = startY + (col - row / 2.0f) * 2 * BALL_RADIUS * sinf(M_PI / 3);
  171.             bool isStriped = colorIndex < 7 || (colorIndex >= 7 && colorIndex < 14 && colors[colorIndex] == RGB(255, 0, 0));
  172.             balls.push_back({ x, y, 0.0f, 0.0f, colors[colorIndex++], false, isStriped });
  173.         }
  174.     }
  175. }
  176.  
  177. void DrawTable(HDC hdc) {
  178.     HBRUSH hBrush = CreateSolidBrush(RGB(0, 128, 0));
  179.     FillRect(hdc, &table, hBrush);
  180.     DeleteObject(hBrush);
  181.  
  182.     for (int i = 0; i < 2; ++i) {
  183.         for (int j = 0; j < 3; ++j) {
  184.             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);
  185.         }
  186.     }
  187. }
  188.  
  189. void DrawBalls(HDC hdc) {
  190.     for (const auto& ball : balls) {
  191.         if (!ball.isPocketed) {
  192.             hBrush = CreateSolidBrush(ball.color);
  193.             SelectObject(hdc, hBrush);
  194.             Ellipse(hdc, (int)(ball.x - BALL_RADIUS), (int)(ball.y - BALL_RADIUS), (int)(ball.x + BALL_RADIUS), (int)(ball.y + BALL_RADIUS));
  195.             DeleteObject(hBrush);
  196.         }
  197.     }
  198. }
  199.  
  200. void DrawCue(HDC hdc) {
  201.     MoveToEx(hdc, (int)cueBall.x, (int)cueBall.y, NULL);
  202.     LineTo(hdc, cueEnd.x, cueEnd.y);
  203. }
  204.  
  205. void DrawPowerMeter(HDC hdc) {
  206.     HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 0));
  207.     RECT rect = { 10, 50, 30, 450 };
  208.     FillRect(hdc, &rect, hBrush);
  209.     DeleteObject(hBrush);
  210.  
  211.     hBrush = CreateSolidBrush(RGB(255, 255, 0));
  212.     rect.bottom = 450 - (int)(400 * power);
  213.     FillRect(hdc, &rect, hBrush);
  214.     DeleteObject(hBrush);
  215.  
  216.     hBrush = CreateSolidBrush(RGB(255, 0, 0));
  217.     rect.bottom = 450 - (int)(400 * power / 2);
  218.     FillRect(hdc, &rect, hBrush);
  219.    
  220.  
  221.  DeleteObject(hBrush);
  222. }
  223.  
  224. void UpdateBalls() {
  225.     for (auto& ball : balls) {
  226.         if (!ball.isPocketed) {
  227.             ball.x += ball.vx;
  228.             ball.y += ball.vy;
  229.  
  230.             ball.vx *= 0.99f;
  231.             ball.vy *= 0.99f;
  232.  
  233.             if (fabs(ball.vx) < 0.01f) ball.vx = 0.0f;
  234.             if (fabs(ball.vy) < 0.01f) ball.vy = 0.0f;
  235.         }
  236.     }
  237. }
  238.  
  239. void CheckCollisions() {
  240.     for (size_t i = 0; i < balls.size(); ++i) {
  241.         Ball& ball1 = balls[i];
  242.         if (ball1.isPocketed) continue;
  243.         for (size_t j = i + 1; j < balls.size(); ++j) {
  244.             Ball& ball2 = balls[j];
  245.             if (ball2.isPocketed) continue;
  246.             float dx = ball2.x - ball1.x;
  247.             float dy = ball2.y - ball1.y;
  248.             float distance = sqrtf(dx * dx + dy * dy);
  249.             if (distance < 2 * BALL_RADIUS) {
  250.                 float angle = atan2f(dy, dx);
  251.                 float totalVx = ball1.vx + ball2.vx;
  252.                 float totalVy = ball1.vy + ball2.vy;
  253.  
  254.                 ball1.vx = totalVx * cosf(angle);
  255.                 ball1.vy = totalVy * sinf(angle);
  256.                 ball2.vx = totalVx * cosf(angle + M_PI);
  257.                 ball2.vy = totalVy * sinf(angle + M_PI);
  258.  
  259.                 ball1.x += ball1.vx;
  260.                 ball1.y += ball1.vy;
  261.                 ball2.x += ball2.vx;
  262.                 ball2.y += ball2.vy;
  263.             }
  264.         }
  265.     }
  266. }
  267.  
  268. void CheckPockets() {
  269.     for (auto& ball : balls) {
  270.         if (ball.isPocketed) continue;
  271.         for (int i = 0; i < 2; ++i) {
  272.             for (int j = 0; j < 3; ++j) {
  273.                 float dx = table.left + j * TABLE_WIDTH / 2 - ball.x;
  274.                 float dy = table.top + i * TABLE_HEIGHT - ball.y;
  275.                 if (sqrtf(dx * dx + dy * dy) < BALL_RADIUS) {
  276.                     ball.isPocketed = true;
  277.                     if (&ball == &cueBall) {
  278.                         HandleFoul();
  279.                         return;
  280.                     } else {
  281.                         playerTurn = true;
  282.                         return;
  283.                     }
  284.                 }
  285.             }
  286.         }
  287.     }
  288. }
  289.  
  290. void AIMove() {
  291.     if (!playerTurn) {
  292.         cueBall.vx = (rand() % 200 - 100) / 100.0f;
  293.         cueBall.vy = (rand() % 200 - 100) / 100.0f;
  294.         ApplyEnglish(cueBall, cueBall.vx * 0.1f, cueBall.vy * 0.1f);
  295.         playerTurn = true;
  296.     }
  297. }
  298.  
  299. void ApplyEnglish(Ball& ball, float ex, float ey) {
  300.     ball.vx += ex;
  301.     ball.vy += ey;
  302. }
  303.  
  304. bool CheckGameOver() {
  305.     for (const auto& ball : balls) {
  306.         if (!ball.isPocketed) return false;
  307.     }
  308.     return true;
  309. }
  310.  
  311. void AssignPlayerColor(COLORREF color) {
  312.     if (playerColors[0] == 0) playerColors[0] = color;
  313.     else if (playerColors[1] == 0 && playerColors[0] != color) playerColors[1] = color;
  314. }
  315.  
  316. void HandleFoul() {
  317.     cueBall.isPocketed = false;
  318.     cueBall.x = 200.0f;
  319.     cueBall.y = 250.0f;
  320.     cueBall.vx = 0.0f;
  321.     cueBall.vy = 0.0f;
  322.     playerTurn = true;
  323. }
  324. ```
  325.  
  326. ++=====================++
  327. ++=====================++
  328.  
  329. ```cpp
  330.     RECT foulRect = { 50, 50, 250, 150 };
  331.     InvalidateRect(hwnd, &foulRect, TRUE);
  332. }
  333.  
  334. void DrawFoul(HDC hdc) {
  335.     RECT rect = { 50, 50, 250, 150 };
  336.     SetBkMode(hdc, TRANSPARENT);
  337.     SetTextColor(hdc, RGB(255, 0, 0));
  338.     DrawText(hdc, L"Foul!", -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  339. }
  340.  
  341. void DrawCurrentPlayerIndicator(HDC hdc) {
  342.     RECT rect = { 400, 10, 500, 40 };
  343.     wchar_t text[50];
  344.     wsprintf(text, L"Player %d's Turn", currentPlayer + 1);
  345.     SetBkMode(hdc, TRANSPARENT);
  346.     SetTextColor(hdc, RGB(0, 0, 255));
  347.     DrawText(hdc, text, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  348. }
  349.  
  350. void DrawPocketedBalls(HDC hdc) {
  351.     RECT rect = { 50, 500, 850, 550 };
  352.     FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
  353.     int x = 60;
  354.     for (const auto& ball : balls) {
  355.         if (ball.isPocketed) {
  356.             hBrush = CreateSolidBrush(ball.color);
  357.             SelectObject(hdc, hBrush);
  358.             Ellipse(hdc, x, 510, x + BALL_RADIUS * 2, 510 + BALL_RADIUS * 2);
  359.             DeleteObject(hBrush);
  360.             x += BALL_RADIUS * 3;
  361.         }
  362.     }
  363. }
  364.  
  365. void DrawTargetingLine(HDC hdc) {
  366.     if (isDragging) {
  367.         MoveToEx(hdc, (int)cueBall.x, (int)cueBall.y, NULL);
  368.         LineTo(hdc, cueEnd.x, cueEnd.y);
  369.         float dx = cueEnd.x - cueBall.x;
  370.         float dy = cueEnd.y - cueBall.y;
  371.         float len = sqrt(dx * dx + dy * dy);
  372.         dx /= len;
  373.         dy /= len;
  374.         int tx = (int)(cueBall.x + dx * (len + BALL_RADIUS));
  375.         int ty = (int)(cueBall.y + dy * (len + BALL_RADIUS));
  376.         Ellipse(hdc, tx - 2, ty - 2, tx + 2, ty + 2);
  377.     }
  378. }
  379.  
  380. void DrawCueBallEnglish(HDC hdc) {
  381.     RECT rect = { 50, 450, 100, 500 };
  382.     FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
  383.     Ellipse(hdc, 50, 450, 100, 500);
  384.     Ellipse(hdc, 72, 472, 78, 478);
  385. }
  386.  
  387. void DrawCueBallLimitLine(HDC hdc) {
  388.     HPEN hPenOld = (HPEN)SelectObject(hdc, CreatePen(PS_DOT, 1, RGB(255, 0, 0)));
  389.     MoveToEx(hdc, table.left + 0.3 * TABLE_WIDTH, table.top, NULL);
  390.     LineTo(hdc, table.left + 0.3 * TABLE_WIDTH, table.bottom);
  391.     SelectObject(hdc, hPenOld);
  392.     DeleteObject(hPen);
  393. }
  394.  
  395. void DrawUIElements(HDC hdc) {
  396.     DrawCurrentPlayerIndicator(hdc);
  397.     DrawPocketedBalls(hdc);
  398.     DrawCueBallLimitLine(hdc);
  399.     DrawCueBallEnglish(hdc);
  400.     if (!playerTurn) {
  401.         RECT rect = { 400, 500, 500, 550 };
  402.         wchar_t text[50];
  403.         wsprintf(text, L"Player %d's Turn", currentPlayer + 1);
  404.         SetBkMode(hdc, TRANSPARENT);
  405.         SetTextColor(hdc, RGB(0, 0, 255));
  406.         DrawText(hdc, text, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  407.     }
  408. }
  409.  
  410. void UpdateGame() {
  411.     if (!gameOver) {
  412.         UpdateBalls();
  413.         CheckCollisions();
  414.         CheckPockets();
  415.         if (!playerTurn) AIMove();
  416.         if (CheckGameOver()) {
  417.             gameOver = true;
  418.             InvalidateRect(hwnd, NULL, TRUE);
  419.         }
  420.     }
  421. }
  422. ```
  423.  
  424. ++=====================++
  425. ++=====================++
  426.  
  427. ```cpp
  428. void Paint(HWND hwnd) {
  429.     PAINTSTRUCT ps;
  430.     HDC hdc = BeginPaint(hwnd, &ps);
  431.     HDC hdcMem = CreateCompatibleDC(hdc);
  432.     HBITMAP hbmMem = CreateCompatibleBitmap(hdc, TABLE_WIDTH, TABLE_HEIGHT);
  433.     HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
  434.     HBRUSH hbrBkGnd = CreateSolidBrush(RGB(0, 128, 0));
  435.     FillRect(hdcMem, &table, hbrBkGnd);
  436.     DeleteObject(hbrBkGnd);
  437.     DrawTable(hdcMem);
  438.     DrawBalls(hdcMem);
  439.     DrawCueStick(hdcMem);
  440.     DrawUIElements(hdcMem);
  441.     if (foul) DrawFoul(hdcMem);
  442.     BitBlt(hdc, 0, 0, TABLE_WIDTH, TABLE_HEIGHT, hdcMem, 0, 0, SRCCOPY);
  443.     SelectObject(hdcMem, hbmOld);
  444.     DeleteObject(hbmMem);
  445.     DeleteDC(hdcMem);
  446.     EndPaint(hwnd, &ps);
  447. }
  448.  
  449. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  450.     switch (uMsg) {
  451.     case WM_CREATE:
  452.         SetTimer(hwnd, 1, 16, NULL);
  453.         break;
  454.     case WM_PAINT:
  455.         Paint(hwnd);
  456.         break;
  457.     case WM_TIMER:
  458.         UpdateGame();
  459.         InvalidateRect(hwnd, NULL, FALSE);
  460.         break;
  461.     case WM_LBUTTONDOWN:
  462.         OnLButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  463.         break;
  464.     case WM_MOUSEMOVE:
  465.         OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  466.         break;
  467.     case WM_LBUTTONUP:
  468.         OnLButtonUp(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  469.         break;
  470.     case WM_DESTROY:
  471.         PostQuitMessage(0);
  472.         break;
  473.     default:
  474.         return DefWindowProc(hwnd, uMsg, wParam, lParam);
  475.     }
  476.     return 0;
  477. }
  478.  
  479. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) {
  480.     const wchar_t CLASS_NAME[] = L"8BallPoolClass";
  481.     WNDCLASS wc = {};
  482.     wc.lpfnWndProc = WindowProc;
  483.     wc.hInstance = hInstance;
  484.     wc.lpszClassName = CLASS_NAME;
  485.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  486.     RegisterClass(&wc);
  487.     HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"8-Ball Pool", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, TABLE_WIDTH, TABLE_HEIGHT, NULL, NULL, hInstance, NULL);
  488.     ShowWindow(hwnd, nCmdShow);
  489.     MSG msg = {};
  490.     while (GetMessage(&msg, NULL, 0, 0)) {
  491.         TranslateMessage(&msg);
  492.         DispatchMessage(&msg);
  493.     }
  494.     return 0;
  495. }
  496. ```
  497.  
  498. ++=====================++
  499. ++=====================++ Superfluous?
  500.  
  501. ```cpp
  502. void DrawUIElements(HDC hdc) {
  503.     // Draw player turn indicator
  504.     if (currentPlayer == 0) {
  505.         DrawText(hdc, L"Player 1's Turn", -1, &turnIndicatorRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  506.     } else {
  507.         DrawText(hdc, L"Player 2's Turn", -1, &turnIndicatorRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  508.     }
  509.     // Draw pocketed balls
  510.     DrawPocketedBalls(hdc);
  511. }
  512.  
  513. void DrawFoul(HDC hdc) {
  514.     HFONT hFont = CreateFont(72, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Arial");
  515.     HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
  516.     SetTextColor(hdc, RGB(255, 0, 0));
  517.     SetBkMode(hdc, TRANSPARENT);
  518.     RECT rect = { 50, 50, TABLE_WIDTH - 50, TABLE_HEIGHT - 50 };
  519.     DrawText(hdc, L"Foul!", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  520.     SelectObject(hdc, hOldFont);
  521.     DeleteObject(hFont);
  522. }
  523.  
  524. void DrawPocketedBalls(HDC hdc) {
  525.     for (int i = 0; i < pocketedBallsPlayer1.size(); i++) {
  526.         DrawBall(hdc, pocketedBallsPlayer1[i], 50 + i * BALL_RADIUS * 2, TABLE_HEIGHT - 30);
  527.     }
  528.     for (int i = 0; i < pocketedBallsPlayer2.size(); i++) {
  529.         DrawBall(hdc, pocketedBallsPlayer2[i], 50 + i * BALL_RADIUS * 2, TABLE_HEIGHT - 60);
  530.     }
  531. }
  532.  
  533. void OnLButtonDown(int x, int y) {
  534.     if (isCueBallInHand) {
  535.         SetCueBallPosition(x, y);
  536.     } else {
  537.         aiming = true;
  538.         aimStartX = x;
  539.         aimStartY = y;
  540.     }
  541. }
  542.  
  543. void OnMouseMove(int x, int y) {
  544.     if (aiming) {
  545.         aimEndX = x;
  546.         aimEndY = y;
  547.     }
  548. }
  549.  
  550. void OnLButtonUp(int x, int y) {
  551.     if (aiming) {
  552.         aiming = false;
  553.         ShootCueBall(aimEndX - aimStartX, aimEndY - aimStartY);
  554.     }
  555. }
  556.  
  557. void SetCueBallPosition(int x, int y) {
  558.     if (x >= CUE_BALL_MIN_X && x <= CUE_BALL_MAX_X && y >= CUE_BALL_MIN_Y && y <= CUE_BALL_MAX_Y) {
  559.         balls[0].x = x;
  560.         balls[0].y = y;
  561.     }
  562. }
  563.  
  564. void ShootCueBall(int dx, int dy) {
  565.     balls[0].vx = dx * SHOT_STRENGTH;
  566.     balls[0].vy = dy * SHOT_STRENGTH;
  567.     isCueBallInHand = false;
  568. }
  569.  
  570. void DrawBall(HDC hdc, Ball& ball, int x, int y) {
  571.     HBRUSH hbr = CreateSolidBrush(ball.color);
  572.     HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hbr);
  573.     Ellipse(hdc, x - BALL_RADIUS, y - BALL_RADIUS, x + BALL_RADIUS, y + BALL_RADIUS);
  574.     SelectObject(hdc, hOldBrush);
  575.     DeleteObject(hbr);
  576.     if (ball.type == SOLID || ball.type == STRIPE) {
  577.         // Draw ball number or stripe here if necessary
  578.     }
  579. }
  580.  
  581. void DrawCueStick(HDC hdc) {
  582.     if (aiming) {
  583.         HPEN hPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
  584.         HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
  585.         MoveToEx(hdc, balls[0].x, balls[0].y, NULL);
  586.         LineTo(hdc, aimEndX, aimEndY);
  587.         SelectObject(hdc, hOldPen);
  588.         DeleteObject(hPen);
  589.     }
  590. }
  591.  
  592. void DrawTable(HDC hdc) {
  593.     HBRUSH hbrTable = CreateSolidBrush(RGB(0, 128, 0));
  594.     HBRUSH hbrEdge = CreateSolidBrush(RGB(255, 0, 0));
  595.     SelectObject(hdc, hbrTable);
  596.     Rectangle(hdc, 0, 0, TABLE_WIDTH, TABLE_HEIGHT);
  597.     SelectObject(hdc, hbrEdge);
  598.     Rectangle(hdc, 0, 0, TABLE_WIDTH, EDGE_WIDTH);
  599.     Rectangle(hdc, 0, 0, EDGE_WIDTH, TABLE_HEIGHT);
  600.     Rectangle(hdc, TABLE_WIDTH - EDGE_WIDTH, 0, TABLE_WIDTH, TABLE_HEIGHT);
  601.     Rectangle(hdc, 0, TABLE_HEIGHT - EDGE_WIDTH, TABLE_WIDTH, TABLE_HEIGHT);
  602.     DeleteObject(hbrTable);
  603.     DeleteObject(hbrEdge);
  604.     DrawPockets(hdc);
  605. }
  606.  
  607. void DrawPockets(HDC hdc) {
  608.     HBRUSH hbrPocket = CreateSolidBrush(RGB(0, 0, 0));
  609.     HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hbrPocket);
  610.     for (int i = 0; i < 6; i++) {
  611.         Ellipse(hdc, pockets[i].x - POCKET_RADIUS, pockets[i].y - POCKET_RADIUS, pockets[i].x + POCKET_RADIUS, pockets[i].y + POCKET_RADIUS);
  612.     }
  613.     SelectObject(hdc, hOldBrush);
  614.     DeleteObject(hbrPocket);
  615. }
  616. ```
  617.  
  618. ++=====================++
  619. ++=====================++
  620.  
  621. #Can you repeat the source code provided above between "void HandleFoul() {" and "void DrawFoul(HDC hdc) {" because "    RECT foulRect = { 50, 50, 250, 150 };
  622.     InvalidateRect(hwnd, &foulRect, TRUE);
  623. }" seems out of place after continuing the code! Don't show the full entire code, only between those two points and why "    RECT foulRect = { 50, 50, 250, 150 };
  624.     InvalidateRect(hwnd, &foulRect, TRUE);
  625. }" is shown when it's out of the scope of "void HandleFoul() {" Thank you!
  626.  
  627. Sure, here is the code between `void HandleFoul() {` and `void DrawFoul(HDC hdc) {` with the `RECT foulRect = { 50, 50, 250, 150 }; InvalidateRect(hwnd, &foulRect, TRUE);` properly placed within the `HandleFoul` function:
  628.  
  629. ```cpp
  630. void HandleFoul() {
  631.    isCueBallInHand = true;
  632.    RECT foulRect = { 50, 50, 250, 150 };
  633.    InvalidateRect(hwnd, &foulRect, TRUE);
  634.    currentPlayer = (currentPlayer + 1) % 2;
  635. }
  636.  
  637. void DrawFoul(HDC hdc) {
  638.    HFONT hFont = CreateFont(72, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Arial");
  639.    HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
  640.    SetTextColor(hdc, RGB(255, 0, 0));
  641.    SetBkMode(hdc, TRANSPARENT);
  642.    RECT rect = { 50, 50, TABLE_WIDTH - 50, TABLE_HEIGHT - 50 };
  643.    DrawText(hdc, L"Foul!", -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  644.    SelectObject(hdc, hOldFont);
  645.    DeleteObject(hFont);
  646. }
  647. ```
  648.  
  649. In this revised version, the `RECT foulRect = { 50, 50, 250, 150 }; InvalidateRect(hwnd, &foulRect, TRUE);` line is placed inside the `HandleFoul` function where it belongs, ensuring that the invalidation of the rectangle occurs when a foul is handled. This triggers a redraw of the specified rectangle, which is needed to display the "Foul!" message properly.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement