Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <windows.h>
- #include <vector>
- #include <cmath>
- #include <ctime>
- #define ID_TIMER 1
- #define BALL_RADIUS 10
- #define TABLE_WIDTH 800
- #define TABLE_HEIGHT 400
- #define MAX_SHOT_POWER 500
- HINSTANCE hInst;
- HWND hwnd;
- HDC hdcMem;
- HBITMAP hbmMem, hbmOld;
- RECT table = { 50, 50, 850, 450 };
- POINT cueStart, cueEnd;
- bool isDragging = false;
- float power = 0.0f;
- int currentPlayerColor = 0;
- bool foulOccurred = false;
- bool cueBallMoveAllowed = true;
- bool gameOver = false;
- struct Ball {
- float x, y;
- float vx, vy;
- COLORREF color;
- bool isPocketed;
- };
- std::vector<Ball> balls;
- Ball cueBall;
- Ball eightBall;
- LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
- void InitBalls();
- void DrawTable(HDC);
- void DrawBalls(HDC);
- void DrawCue(HDC);
- void DrawPowerMeter(HDC);
- void UpdateBalls();
- void CheckCollisions();
- void CheckPockets();
- void ApplyEnglish(Ball&, float, float);
- bool CheckGameOver();
- void HandleFoul();
- int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow) {
- hInst = hInstance;
- WNDCLASS wc = {};
- wc.lpfnWndProc = WndProc;
- wc.hInstance = hInstance;
- wc.lpszClassName = L"8BallPool";
- RegisterClass(&wc);
- hwnd = CreateWindowEx(0, L"8BallPool", L"8-Ball Pool", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 900, 600, nullptr, nullptr, hInstance, nullptr);
- ShowWindow(hwnd, nCmdShow);
- MSG msg = {};
- while (GetMessage(&msg, nullptr, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return (int)msg.wParam;
- }
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
- switch (message) {
- case WM_CREATE:
- srand((unsigned int)time(NULL));
- InitBalls();
- SetTimer(hwnd, ID_TIMER, 16, NULL);
- break;
- case WM_PAINT: {
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint(hwnd, &ps);
- if (!hdcMem) {
- hdcMem = CreateCompatibleDC(hdc);
- hbmMem = CreateCompatibleBitmap(hdc, 900, 600);
- hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
- }
- FillRect(hdcMem, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
- DrawTable(hdcMem);
- DrawBalls(hdcMem);
- if (!gameOver && !foulOccurred && !isDragging) {
- DrawCue(hdcMem);
- DrawPowerMeter(hdcMem);
- }
- if (foulOccurred) {
- SetTextColor(hdcMem, RGB(255, 0, 0));
- TextOut(hdcMem, 10, 10, L"Foul!", 5);
- }
- BitBlt(hdc, 0, 0, 900, 600, hdcMem, 0, 0, SRCCOPY);
- EndPaint(hwnd, &ps);
- break;
- }
- case WM_LBUTTONDOWN:
- if (gameOver) break;
- cueStart.x = LOWORD(lParam);
- cueStart.y = HIWORD(lParam);
- if (foulOccurred && cueBallMoveAllowed) {
- cueBall.x = (float)cueStart.x;
- cueBall.y = (float)cueStart.y;
- InvalidateRect(hwnd, NULL, FALSE);
- } else {
- isDragging = true;
- }
- break;
- case WM_MOUSEMOVE:
- if (isDragging) {
- cueEnd.x = LOWORD(lParam);
- cueEnd.y = HIWORD(lParam);
- power = min(sqrt(pow(cueEnd.x - cueStart.x, 2) + pow(cueEnd.y - cueStart.y, 2)) / 100.0f, 1.0f);
- InvalidateRect(hwnd, NULL, FALSE);
- }
- break;
- case WM_LBUTTONUP:
- if (isDragging) {
- isDragging = false;
- float dx = cueEnd.x - cueStart.x;
- float dy = cueEnd.y - cueStart.y;
- cueBall.vx = dx * power * 0.5f;
- cueBall.vy = dy * power * 0.5f;
- ApplyEnglish(cueBall, dx * power * 0.1f, dy * power * 0.1f);
- foulOccurred = false;
- cueBallMoveAllowed = false;
- InvalidateRect(hwnd, NULL, FALSE);
- }
- break;
- case WM_RBUTTONDOWN:
- if (isDragging) {
- power = min(sqrt(pow(cueEnd.x - cueStart.x, 2) + pow(cueEnd.y - cueStart.y, 2)) / 100.0f, 1.0f);
- InvalidateRect(hwnd, NULL, FALSE);
- }
- break;
- case WM_TIMER:
- if (!gameOver) {
- UpdateBalls();
- CheckCollisions();
- CheckPockets();
- if (CheckGameOver()) {
- gameOver = true;
- }
- InvalidateRect(hwnd, NULL, FALSE);
- }
- break;
- case WM_DESTROY:
- KillTimer(hwnd, ID_TIMER);
- SelectObject(hdcMem, hbmOld);
- DeleteObject(hbmMem);
- DeleteDC(hdcMem);
- PostQuitMessage(0);
- break;
- default:
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- return 0;
- }
- void InitBalls() {
- balls.clear();
- cueBall = { 150.0f, 250.0f, 0.0f, 0.0f, RGB(255, 255, 255), false };
- balls.push_back(cueBall);
- eightBall = { 600.0f, 250.0f, 0.0f, 0.0f, RGB(0, 0, 0), false };
- balls.push_back(eightBall);
- for (int i = 0; i < 7; ++i) {
- float angle = (float)i / 7.0f * 3.14159f * 2.0f;
- balls.push_back({ 600.0f + cos(angle) * 30, 250.0f + sin(angle) * 30, 0.0f, 0.0f, RGB(255, 255, 0), false });
- balls.push_back({ 600.0f + cos(angle) * 60, 250.0f + sin(angle) * 60, 0.0f, 0.0f, RGB(255, 0, 0), false });
- }
- }
- void DrawTable(HDC hdc) {
- HBRUSH hBrush = CreateSolidBrush(RGB(0, 128, 0));
- FillRect(hdc, &table, hBrush);
- DeleteObject(hBrush);
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 3; ++j) {
- 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);
- }
- }
- MoveToEx(hdc, (int)(table.left + 0.3f * TABLE_WIDTH), table.top, NULL);
- LineTo(hdc, (int)(table.left + 0.3f * TABLE_WIDTH), table.bottom);
- }
- void DrawBalls(HDC hdc) {
- for (const auto& ball : balls) {
- if (!ball.isPocketed) {
- hBrush = CreateSolidBrush(ball.color);
- SelectObject(hdc, hBrush);
- Ellipse(hdc, (int)(ball.x - BALL_RADIUS), (int)(ball.y - BALL_RADIUS), (int)(ball.x + BALL_RADIUS), (int)(ball.y + BALL_RADIUS));
- DeleteObject(hBrush);
- }
- }
- }
- void DrawCue(HDC hdc) {
- // Determine cue stick length and thickness
- int cueLength = 200;
- int cueThickness = 10;
- // Calculate the cue stick angle based on the position of the cue ball and the mouse position
- float angle = atan2(cueEnd.y - cueBall.y, cueEnd.x - cueBall.x);
- // Calculate the cue stick endpoint positions based on the angle and the desired cue stick length
- int cueX1 = (int)(cueBall.x + cos(angle) * BALL_RADIUS);
- int cueY1 = (int)(cueBall.y + sin(angle) * BALL_RADIUS);
- int cueX2 = (int)(cueX1 + cos(angle) * cueLength);
- int cueY2 = (int)(cueY1 + sin(angle) * cueLength);
- // Draw the cue stick as a thick line with the specified thickness
- HPEN hPen = CreatePen(PS_SOLID, cueThickness, RGB(139, 69, 19)); // Brown color for the cue stick
- SelectObject(hdc, hPen);
- MoveToEx(hdc, cueX1, cueY1, NULL);
- LineTo(hdc, cueX2, cueY2);
- // Draw the tip of the cue stick with a different color (light blue)
- HPEN hPenTip = CreatePen(PS_SOLID, cueThickness / 2, RGB(173, 216, 230)); // Light blue for the tip
- SelectObject(hdc, hPenTip);
- LineTo(hdc, cueX2 + (int)(cos(angle) * 10), cueY2 + (int)(sin(angle) * 10));
- DeleteObject(hPen);
- DeleteObject(hPenTip);
- }
- void DrawPowerMeter(HDC hdc) {
- RECT powerRect = { 750, 500, 800, 500 - (int)(power * 400) };
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0));
- FillRect(hdc, &powerRect, hBrush);
- DeleteObject(hBrush);
- }
- void UpdateBalls() {
- for (auto& ball : balls) {
- if (!ball.isPocketed) {
- ball.x += ball.vx;
- ball.y += ball.vy;
- ball.vx *= 0.99f;
- ball.vy *= 0.99f;
- if (ball.x - BALL_RADIUS < table.left || ball.x + BALL_RADIUS > table.right) {
- ball.vx = -ball.vx;
- ball.x = min(max(ball.x, table.left + BALL_RADIUS), table.right - BALL_RADIUS);
- }
- if (ball.y - BALL_RADIUS < table.top || ball.y + BALL_RADIUS > table.bottom) {
- ball.vy = -ball.vy;
- ball.y = min(max(ball.y, table.top + BALL_RADIUS), table.bottom - BALL_RADIUS);
- }
- }
- }
- }
- void CheckCollisions() {
- for (size_t i = 0; i < balls.size(); ++i) {
- for (size_t j = i + 1; j < balls.size(); ++j) {
- Ball& b1 = balls[i];
- Ball& b2 = balls[j];
- float dx = b1.x - b2.x;
- float dy = b1.y - b2.y;
- float dist = sqrt(dx * dx + dy * dy);
- if (dist < BALL_RADIUS * 2) {
- float nx = dx / dist;
- float ny = dy / dist;
- float tx = -ny;
- float ty = nx;
- float dpTan1 = b1.vx * tx + b1.vy * ty;
- float dpTan2 = b2.vx * tx + b2.vy * ty;
- float dpNorm1 = b1.vx * nx + b1.vy * ny;
- float dpNorm2 = b2.vx * nx + b2.vy * ny;
- float m1 = (dpNorm1 * (1 - 1) + 2 * dpNorm2) / 2;
- float m2 = (dpNorm2 * (1 - 1) + 2 * dpNorm1) / 2;
- b1.vx = tx * dpTan1 + nx * m1;
- b1.vy = ty * dpTan1 + ny * m1;
- b2.vx = tx * dpTan2 + nx * m2;
- b2.vy = ty * dpTan2 + ny * m2;
- float overlap = 0.5f * (BALL_RADIUS * 2 - dist);
- b1.x += nx * overlap;
- b1.y += ny * overlap;
- b2.x -= nx * overlap;
- b2.y -= ny * overlap;
- }
- }
- }
- }
- void CheckPockets() {
- for (auto& ball : balls) {
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 3; ++j) {
- int px = table.left + j * TABLE_WIDTH / 2;
- int py = table.top + i * TABLE_HEIGHT;
- float dist = sqrt(pow(ball.x - px, 2) + pow(ball.y - py, 2));
- if (dist < BALL_RADIUS * 1.5f) {
- ball.isPocketed = true;
- ball.vx = 0;
- ball.vy = 0;
- if (&ball == &cueBall) {
- foulOccurred = true;
- cueBallMoveAllowed = true;
- } else if (&ball == &eightBall) {
- gameOver = true;
- }
- }
- }
- }
- }
- }
- void ApplyEnglish(Ball& ball, float ex, float ey) {
- ball.vx += ex * 0.1f;
- ball.vy += ey * 0.1f;
- }
- bool CheckGameOver() {
- for (const auto& ball : balls) {
- if (!ball.isPocketed && &ball != &eightBall) {
- return false;
- }
- }
- return true;
- }
- void HandleFoul() {
- cueBall.vx = 0;
- cueBall.vy = 0;
- cueBallMoveAllowed = true;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement