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;
- struct Ball {
- float x, y;
- float vx, vy;
- COLORREF color;
- bool isPocketed;
- };
- enum class PlayerColor {
- None,
- Solids,
- Stripes,
- };
- std::vector<Ball> balls;
- Ball cueBall;
- bool playerTurn = true;
- bool gameOver = false;
- PlayerColor playerColor = PlayerColor::None;
- 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();
- 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 && playerTurn) {
- DrawCue(hdcMem);
- DrawPowerMeter(hdcMem);
- }
- BitBlt(hdc, 0, 0, 900, 600, hdcMem, 0, 0, SRCCOPY);
- EndPaint(hwnd, &ps);
- break;
- }
- case WM_LBUTTONDOWN:
- if (gameOver || !playerTurn) break;
- if (LOWORD(lParam) >= 10 && LOWORD(lParam) <= 30 && HIWORD(lParam) >= 10 && HIWORD(lParam) <= 50) {
- cueStart.x = 20;
- cueStart.y = 30;
- } else {
- cueStart.x = LOWORD(lParam);
- cueStart.y = HIWORD(lParam);
- }
- isDragging = true;
- break;
- case WM_MOUSEMOVE:
- if (isDragging) {
- if (cueStart.x == 20 && cueStart.y == 30) {
- cueStart.x = 20;
- cueStart.y = 30;
- } else {
- 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 = { 450.0f, 250.0f, 0.0f, 0.0f, RGB(255, 255, 255), false };
- balls.push_back(cueBall);
- balls.push_back({ 600.0f, 250.0f, 0.0f, 0.0f, RGB(0, 0, 0), false });
- const float baseX = 600.0f;
- const float baseY = 250.0f;
- const float offset = 30.0f;
- balls[0].x = baseX;
- balls.push_back({ baseX - offset, baseY + offset, 0.0f, 0.0f, RGB(255, 255, 0), false });
- balls.push_back({ baseX + offset, baseY + offset, 0.0f, 0.0f, RGB(255, 0, 0), false });
- balls.push_back({ baseX - 2 * offset, baseY + 2 * offset, 0.0f, 0.0f, RGB(255, 255, 0), false });
- balls.push_back({ baseX, baseY + 2 * offset, 0.0f, 0.0f, RGB(255, 0, 0), false });
- balls.push_back({ baseX + 2 * offset, baseY + 2 * offset, 0.0f, 0.0f, RGB(255, 255, 0), false });
- balls.push_back({ baseX - 3 * offset, baseY + 3 * offset, 0.0f, 0.0f, RGB(255, 0, 0), false });
- balls.push_back({ baseX - offset, baseY + 3 * offset, 0.0f, 0.0f, RGB(255, 255, 0), false });
- balls.push_back({ baseX + offset, baseY + 3 * offset, 0.0f, 0.0f, RGB(255, 0, 0), false });
- balls.push_back({ baseX + 3 * offset, baseY + 3 * offset, 0.0f, 0.0f, RGB(255, 255, 0), false });
- }
- void DrawTable(HDC hdc) {
- HBRUSH hBrush = CreateSolidBrush(RGB(0, 128, 0));
- FillRect(hdc, &table, hBrush);
- DeleteObject(hBrush);
- HPEN hPenRed = CreatePen(PS_SOLID, 5, RGB(255, 0, 0));
- SelectObject(hdc, hPenRed);
- Rectangle(hdc, table.left, table.top, table.right, table.bottom);
- DeleteObject(hPenRed);
- HBRUSH hBrushBlack = CreateSolidBrush(RGB(0, 0, 0));
- SelectObject(hdc, hBrushBlack);
- 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);
- }
- }
- DeleteObject(hBrushBlack);
- }
- 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) {
- MoveToEx(hdc, (int)cueBall.x, (int)cueBall.y, NULL);
- LineTo(hdc, cueEnd.x, cueEnd.y);
- float dx = cueEnd.x - cueBall.x;
- float dy = cueEnd.y - cueBall.y;
- float length = sqrt(dx * dx + dy * dy);
- if (length > 0) {
- dx /= length;
- dy /= length;
- }
- float aimBallX = cueBall.x + dx * 100;
- float aimBallY = cueBall.y + dy * 100;
- MoveToEx(hdc, cueBall.x, cueBall.y, NULL);
- LineTo(hdc, aimBallX, aimBallY);
- for (const auto& ball : balls) {
- if (!ball.isPocketed) {
- float ballEdgeX = ball.x + (BALL_RADIUS * dx);
- float ballEdgeY = ball.y + (BALL_RADIUS * dy);
- float distToBall = sqrt(pow(ball.x - cueBall.x, 2) + pow(ball.y - cueBall.y, 2));
- if (distToBall < 100 + BALL_RADIUS) {
- MoveToEx(hdc, ballEdgeX, ballEdgeY, NULL);
- LineTo(hdc, ballEdgeX + dx * 10, ballEdgeY + dy * 10);
- }
- }
- }
- }
- void DrawPowerMeter(HDC hdc) {
- HBRUSH hBrush = CreateSolidBrush(RGB(0, 255, 0));
- RECT rect = { 10, 50, 30, 450 };
- FillRect(hdc, &rect, hBrush);
- DeleteObject(hBrush);
- hBrush = CreateSolidBrush(RGB(255, 255, 0));
- rect.bottom = 450 - (int)(400 * power);
- FillRect(hdc, &rect, hBrush);
- DeleteObject(hBrush);
- hBrush = CreateSolidBrush(RGB(255, 0, 0));
- rect.bottom = 450 - (int)(400 * power / 2);
- FillRect(hdc, &rect, hBrush);
- DeleteObject(hBrush);
- const int ballX = 20;
- const int ballY = 30;
- hBrush = CreateSolidBrush(RGB(255, 255, 255));
- SelectObject(hdc, hBrush);
- Ellipse(hdc, ballX - BALL_RADIUS * 2, ballY - BALL_RADIUS * 2, ballX + BALL_RADIUS * 2, ballY + BALL_RADIUS * 2);
- 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 (fabs(ball.vx) < 0.01f) ball.vx = 0.0f;
- if (fabs(ball.vy) < 0.01f) ball.vy = 0.0f;
- }
- }
- }
- 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];
- if (!b1.isPocketed && !b2.isPocketed) {
- float dx = b2.x - b1.x;
- float dy = b2.y - b1.y;
- float dist = sqrt(dx * dx + dy * dy);
- if (dist < BALL_RADIUS * 2) {
- float angle = atan2(dy, dx);
- float sinA = sin(angle);
- float cosA = cos(angle);
- float v1 = (b1.vx * cosA + b1.vy * sinA);
- float v2 = (b2.vx * cosA + b2.vy * sinA);
- b1.vx += v2;
- b2.vx += v1;
- b1.vx *= 0.9f;
- b2.vx *= 0.9f;
- b1.vy += v2;
- b2.vy += v1;
- b1.vy *= 0.9f;
- b2.vy *= 0.9f;
- }
- }
- }
- }
- }
- void CheckPockets() {
- for (auto& ball : balls) {
- if (!ball.isPocketed) {
- if (/* condition to check if the ball is pocketed */) {
- ball.isPocketed = true;
- if (playerColor == PlayerColor::None) {
- if (ball.color == RGB(255, 0, 0)) {
- playerColor = PlayerColor::Solids;
- } else if (ball.color == RGB(255, 255, 0)) {
- playerColor = PlayerColor::Stripes;
- }
- } else {
- if (playerColor == PlayerColor::Solids && ball.color == RGB(255, 255, 0)) {
- MessageBox(hwnd, L"You can only pocket your assigned balls!", L"Invalid Shot", MB_OK);
- ball.isPocketed = false;
- return;
- } else if (playerColor == PlayerColor::Stripes && ball.color == RGB(255, 0, 0)) {
- MessageBox(hwnd, L"You can only pocket your assigned balls!", L"Invalid Shot", MB_OK);
- ball.isPocketed = false;
- return;
- }
- }
- }
- }
- }
- }
- void AIMove() {
- // Simple AI logic for making a move; implement as needed
- }
- void ApplyEnglish(Ball& ball, float ex, float ey) {
- // Apply English effect to the ball; implement as needed
- }
- bool CheckGameOver() {
- for (const auto& ball : balls) {
- if (!ball.isPocketed) return false;
- }
- return true;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement