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
- HINSTANCE hInst;
- HWND hwnd;
- HDC hdcMem, hdcBall;
- HBITMAP hbmMem, hbmOld;
- HPEN hPen;
- HBRUSH hBrush;
- RECT table = { 50, 50, 850, 450 };
- POINT cueStart, cueEnd;
- bool isDragging = false;
- float power = 0.0f;
- bool isCueBallFreeMove = false;
- struct Ball {
- float x, y;
- float vx, vy;
- COLORREF color;
- bool isPocketed;
- bool isStriped;
- };
- std::vector<Ball> balls;
- Ball cueBall;
- bool playerTurn = true;
- bool gameOver = false;
- bool isSolids = false;
- bool player1Solids = false;
- bool firstShot = true;
- 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 AIMove();
- void ApplyEnglish(Ball&, float, float);
- bool CheckGameOver();
- void CheckFoul(Ball&);
- void PocketBall(Ball&);
- void DrawPockets(HDC);
- void DrawPlayerTurn(HDC);
- 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);
- DrawPockets(hdcMem);
- DrawPlayerTurn(hdcMem);
- if (!gameOver && playerTurn && !isCueBallFreeMove) {
- DrawCue(hdcMem);
- DrawPowerMeter(hdcMem);
- }
- BitBlt(hdc, 0, 0, 900, 600, hdcMem, 0, 0, SRCCOPY);
- EndPaint(hwnd, &ps);
- break;
- }
- case WM_LBUTTONDOWN:
- if (gameOver) break;
- if (isCueBallFreeMove) {
- cueBall.x = LOWORD(lParam);
- cueBall.y = HIWORD(lParam);
- isCueBallFreeMove = false;
- InvalidateRect(hwnd, NULL, FALSE);
- } else if (playerTurn) {
- cueStart.x = LOWORD(lParam);
- cueStart.y = HIWORD(lParam);
- 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);
- playerTurn = false;
- InvalidateRect(hwnd, NULL, FALSE);
- }
- break;
- case WM_TIMER:
- if (!gameOver) {
- UpdateBalls();
- CheckCollisions();
- CheckPockets();
- if (!playerTurn) AIMove();
- if (CheckGameOver()) {
- gameOver = true;
- MessageBox(hwnd, L"Game Over! All balls are pocketed.", L"Game Over", MB_OK);
- }
- 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 = { 250.0f, 250.0f, 0.0f, 0.0f, RGB(255, 255, 255), false, false };
- balls.push_back(cueBall);
- // Triangular rack setup
- int colors[] = { RGB(255, 255, 0), RGB(255, 0, 0) };
- bool striped[] = { false, true };
- int colorIndex = 0;
- int ballIndex = 0;
- for (int row = 0; row < 5; ++row) {
- for (int col = 0; col <= row; ++col) {
- float x = 600.0f + col * 22.0f - row * 11.0f;
- float y = 250.0f + row * 20.0f;
- balls.push_back({ x, y, 0.0f, 0.0f, colors[colorIndex], false, striped[colorIndex] });
- ballIndex++;
- if (ballIndex == 7) {
- balls.push_back({ 600.0f, 250.0f + (row + 1) * 20.0f, 0.0f, 0.0f, RGB(0, 0, 0), false, false });
- }
- if (ballIndex >= 14) {
- break;
- }
- colorIndex = (colorIndex + 1) % 2;
- }
- }
- }
- void DrawTable(HDC hdc) {
- HBRUSH hBrush = CreateSolidBrush(RGB(0, 128, 0));
- FillRect(hdc, &table, hBrush);
- DeleteObject(hBrush);
- HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
- SelectObject(hdc, hPen);
- for (int i = 0; i < 2; ++i) {
- for (int j = 0; j < 3; ++j) {
- Ellipse(hdc, table.left + j * TABLE_WIDTH / 2 - BALL_RADIUS * 2, table.top + i * TABLE_HEIGHT - BALL_RADIUS * 2, table.left + j * TABLE_WIDTH / 2 + BALL_RADIUS * 2, table.top + i * TABLE_HEIGHT + BALL_RADIUS * 2);
- }
- }
- DeleteObject(hPen);
- }
- 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);
- // Draw stripes/solids
- if (ball.isStriped) {
- hBrush = CreateSolidBrush(RGB(255, 255, 255));
- SelectObject(hdc, hBrush);
- RECT stripe = { (int)(ball.x - BALL_RADIUS), (int)(ball.y - BALL_RADIUS / 3), (int)(ball.x + BALL_RADIUS), (int)(ball.y + BALL_RADIUS / 3) };
- FillRect(hdc, &stripe, hBrush);
- DeleteObject(hBrush);
- } else {
- hBrush = CreateSolidBrush(RGB(255, 255, 255));
- SelectObject(hdc, hBrush);
- Ellipse(hdc, (int)(ball.x - BALL
- _RADIUS / 4), (int)(ball.y - BALL_RADIUS / 4), (int)(ball.x + BALL_RADIUS / 4), (int)(ball.y + BALL_RADIUS / 4));
- DeleteObject(hBrush);
- }
- }
- }
- }
- void DrawCue(HDC hdc) {
- HPEN hPen = CreatePen(PS_SOLID, 2, RGB(139, 69, 19));
- SelectObject(hdc, hPen);
- MoveToEx(hdc, (int)cueBall.x, (int)cueBall.y, NULL);
- LineTo(hdc, (int)(cueBall.x - (cueEnd.x - cueStart.x)), (int)(cueBall.y - (cueEnd.y - cueStart.y)));
- DeleteObject(hPen);
- }
- void DrawPowerMeter(HDC hdc) {
- HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
- HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0));
- SelectObject(hdc, hPen);
- SelectObject(hdc, hBrush);
- RECT powerRect = { 50, 500, (int)(50 + power * 200), 520 };
- FillRect(hdc, &powerRect, hBrush);
- Rectangle(hdc, 50, 500, 250, 520);
- DeleteObject(hPen);
- 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;
- }
- if (ball.y - BALL_RADIUS < table.top || ball.y + BALL_RADIUS > table.bottom) {
- ball.vy = -ball.vy;
- }
- }
- }
- }
- void CheckCollisions() {
- for (size_t i = 0; i < balls.size(); ++i) {
- for (size_t j = i + 1; j < balls.size(); ++j) {
- Ball& ball1 = balls[i];
- Ball& ball2 = balls[j];
- float dx = ball2.x - ball1.x;
- float dy = ball2.y - ball1.y;
- float distance = sqrt(dx * dx + dy * dy);
- if (distance < BALL_RADIUS * 2 && !ball1.isPocketed && !ball2.isPocketed) {
- float nx = dx / distance;
- float ny = dy / distance;
- float kx = ball1.vx - ball2.vx;
- float ky = ball1.vy - ball2.vy;
- float p = 2.0f * (nx * kx + ny * ky) / 2.0f;
- ball1.vx -= p * nx;
- ball1.vy -= p * ny;
- ball2.vx += p * nx;
- ball2.vy += p * ny;
- }
- }
- }
- }
- void CheckPockets() {
- for (auto& ball : balls) {
- if (!ball.isPocketed) {
- if (ball.x < table.left || ball.x > table.right || ball.y < table.top || ball.y > table.bottom) {
- PocketBall(ball);
- if (ball.color == RGB(0, 0, 0)) {
- gameOver = true;
- }
- if (firstShot) {
- isSolids = ball.isStriped ? false : true;
- player1Solids = isSolids;
- firstShot = false;
- }
- CheckFoul(ball);
- }
- }
- }
- }
- void AIMove() {
- // Simplified AI move: just hit the ball towards a random direction
- if (!playerTurn && !gameOver) {
- cueBall.vx = (rand() % 100 - 50) / 10.0f;
- cueBall.vy = (rand() % 100 - 50) / 10.0f;
- playerTurn = true;
- }
- }
- void ApplyEnglish(Ball& ball, float spinX, float spinY) {
- ball.vx += spinX;
- ball.vy += spinY;
- }
- bool CheckGameOver() {
- for (const auto& ball : balls) {
- if (!ball.isPocketed && ball.color != RGB(0, 0, 0)) {
- return false;
- }
- }
- return true;
- }
- void CheckFoul(Ball& ball) {
- if (ball.color == RGB(255, 255, 255)) {
- isCueBallFreeMove = true;
- playerTurn = !playerTurn;
- }
- }
- void PocketBall(Ball& ball) {
- ball.isPocketed = true;
- ball.vx = 0;
- ball.vy = 0;
- }
- void DrawPockets(HDC hdc) {
- HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0));
- SelectObject(hdc, 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 * 2, table.top + i * TABLE_HEIGHT - BALL_RADIUS * 2, table.left + j * TABLE_WIDTH / 2 + BALL_RADIUS * 2, table.top + i * TABLE_HEIGHT + BALL_RADIUS * 2);
- }
- }
- DeleteObject(hBrush);
- }
- void DrawPlayerTurn(HDC hdc) {
- const wchar_t* playerText = playerTurn ? L"Player 1's Turn" : L"Player 2's Turn";
- SetBkMode(hdc, TRANSPARENT);
- TextOut(hdc, 350, 20, playerText, lstrlen(playerText));
- }
- // Additional helper function to reset the game
- void ResetGame() {
- InitBalls();
- playerTurn = true;
- gameOver = false;
- firstShot = true;
- isSolids = false;
- player1Solids = false;
- isCueBallFreeMove = false;
- InvalidateRect(hwnd, NULL, FALSE);
- }
- // Main message processing function
- 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);
- DrawPockets(hdcMem);
- DrawPlayerTurn(hdcMem);
- if (!gameOver && playerTurn && !isCueBallFreeMove) {
- DrawCue(hdcMem);
- DrawPowerMeter(hdcMem);
- }
- BitBlt(hdc, 0, 0, 900, 600, hdcMem, 0, 0, SRCCOPY);
- EndPaint(hwnd, &ps);
- break;
- }
- case WM_LBUTTONDOWN:
- if (gameOver) break;
- if (isCueBallFreeMove) {
- cueBall.x = LOWORD(lParam);
- cueBall.y = HIWORD(lParam);
- isCueBallFreeMove = false;
- InvalidateRect(hwnd, NULL, FALSE);
- } else if (playerTurn) {
- cueStart.x = LOWORD(lParam);
- cueStart.y = HIWORD(lParam);
- 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);
- playerTurn = false;
- InvalidateRect(hwnd, NULL, FALSE);
- }
- break;
- case WM_TIMER:
- if (!gameOver) {
- UpdateBalls();
- CheckCollisions();
- CheckPockets();
- if (!playerTurn) AIMove();
- if (CheckGameOver()) {
- gameOver = true;
- MessageBox(hwnd, L"Game Over! All balls are pocketed.", L"Game Over", MB_OK);
- }
- InvalidateRect(hwnd, NULL, FALSE);
- }
- break;
- case WM_DESTROY:
- KillTimer(hwnd, ID_TIMER);
- SelectObject(hdcMem, hbmOld);
- DeleteObject(hbmMem);
- DeleteDC(hdcMem);
- PostQuitMessage(0);
- break;
- case WM_KEYDOWN:
- if (wParam == 'R') {
- ResetGame();
- }
- break;
- default:
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement