C++ Graphics Program to Build Multiplayer Sea Battleship Game GUI Desktop App

Thanks for reading my article first. C++ Graphics Program to Build Multiplayer Sea Battleship Game GUI Desktop App We are going to learn more about this in this article. Let’s go into the article

C++ Graphics Program to Build Multiplayer Sea Battleship Game GUI Desktop App

C++ Graphics Program to Build Multiplayer Sea Battleship Game GUI Desktop App

#include <Windows.h>
#include <windowsx.h>
#include <string>
#include <future>
#include <algorithm>
#include "player.h"
#include "game.h"
using std::string;
using std::to_string;
#define clBackgroundColor RGB(255,255,255)
#define clLineColor RGB(232, 180, 255)
#define clBoxLineColor RGB(111, 0, 255)
#define clRedColor RGB(231, 69, 96)
#define clCellColor RGB(231, 69, 96)

/* system setting vars */
int cellSize = 20;
int xCell = 25;
int yCell = 28;
int width = xCell*cellSize;
int height = yCell*cellSize;
int speed = 1;
bool multithreading = true;

Player one, two;
Game game(one, two);
/* window procedure */
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdParam, int cmdShow)
{
    MSG messages;        /* for messages queue manipulation */
    WNDCLASSEX WndClass; /* data struct for window class */
    HWND hWnd;           /* handle for window */

    /* define window class */
    WndClass.cbSize = sizeof(WNDCLASSEX);
    WndClass.style = CS_DBLCLKS;
    WndClass.hInstance = hInst;
    WndClass.lpszClassName = "WindowClassName";
    WndClass.lpfnWndProc = WndProc;

    /* icons, cursor and menu */
    WndClass.hIcon = LoadIcon(hInst, "MAINICON"); /* default icon */
    WndClass.hIconSm = LoadIcon(hInst, "MAINICON"); /* default icon */
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); /* cursor */
    WndClass.lpszMenuName = NULL; /* no menu */
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;

    /* window background color */
    WndClass.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
    RegisterClassEx(&WndClass);
    hWnd = CreateWindowEx(0,                     /* extended window style */
                          "WindowClassName",     /* registered class */
                          "Sea-Battle", /* window title */
                          (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX),   /* default window style */
                          CW_USEDEFAULT,         /* x position */
                          CW_USEDEFAULT,         /* y position */
                          width,                   /* width of window */
                          height,                   /* heigth of window */
                          HWND_DESKTOP,          /* The window is a child-window to desktop */
                          NULL,                  /* no menu */
                          hInst,                 /* Program Instance handler */
                          NULL);                 /* No Window Creation data */


    HMENU hmenu1;
    hmenu1 = CreateMenu();

    AppendMenu(hmenu1, MF_STRING, 0, "&File");
    AppendMenu(hmenu1, MF_STRING, 1, "&Edit");
    AppendMenu(hmenu1, MF_STRING, 2, "&Help");
    ModifyMenu(hmenu1, 2, MF_GRAYED, 2, MF_STRING);

    SetMenu(hWnd, hmenu1);

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    /* loop messages. run until GetMessage return 0*/
    while (GetMessage(&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages); /* translate virtual keys into character messages*/
        DispatchMessage(&messages);  /* Send message to WndProc */
    }
    /* return value to system */
    return static_cast<int>(messages.wParam);
}

void drawLine(HDC);
void drawText(HDC, string, int, int);
void drawArea(HDC);
void drawCell(HDC, int, int, int);
void drawPoint(HDC, int, int, int);
void drawCross(HDC, int, int, int);
std::vector<std::pair<int, int> > mas;
UINT TimerId;
std::future<bool> fut; /* for asynchrony */
/*  This function is called by the Windows function DispatchMessage()  */
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hDC, memDC;
    HBITMAP hScreen, oldBtm;
    int xPos = 0, yPos = 0;
    switch (message)
    {
    case WM_LBUTTONDOWN:
        xPos = LOWORD(lParam)/cellSize;
        yPos = HIWORD(lParam)/cellSize-1;
        mas.push_back(std::make_pair(xPos, yPos));
        break;

    case WM_KEYDOWN:
        switch(wParam) {
        case 27: /* Key Esc */
            PostQuitMessage(0);
            break;
        case 96: /* NumPad 0 */
            one = Player(); two = Player();
            Sleep(1000);
            one.genNew();
            TimerId = SetTimer(hwnd, 2, speed, NULL);
            break;
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0); /* send a WM_QUIT to the message queue */
        break;
    case WM_CREATE:
        SetTimer(hwnd, 1, 100, NULL);
        TimerId = SetTimer(hwnd, 2, speed, NULL);
        one.genNew();
        Sleep(1000);
        two.genNew();
        break;
    case WM_TIMER:
        switch (wParam)
        {
            case 2:
                /* Test multithreading and asynchrony */
                if(multithreading){
                    fut = std::async([&](){
                            if(!game.playerMove()){
                                KillTimer(hwnd, TimerId);
                                return true;
                            }else return false;
                            });
                    fut.get();
                }else
                    if(!game.playerMove()) KillTimer(hwnd, TimerId);
                break;
            case 1:
                hDC = GetDC(hwnd);

                memDC = CreateCompatibleDC(hDC);
                hScreen = CreateCompatibleBitmap(hDC, width, height);
                oldBtm = static_cast<HBITMAP>(SelectObject(memDC, hScreen));
                PatBlt(memDC, 0, 0, width, height, WHITENESS);

                drawArea(memDC);

                for(int i=0; i<10; i++)
                    for(int j=0; j<10; j++) {
                        if(one.checkCell(i,j)) drawCell(memDC, i+1, j+1, 1);

                        if(one.getShootCell(i, j)==-1) drawPoint(memDC, i+1, j+1, 2);
                        else if(one.getShootCell(i, j)==1) drawCross(memDC, i+1, j+1, 2);
                        if(one.getWoundCell(i, j)==-1) drawPoint(memDC, i+1, j+1, 1);
                        else if(one.getWoundCell(i, j)==1) drawCross(memDC, i+1, j+1, 1);

                        if(two.checkCell(i,j)) drawCell(memDC, i+1, j+1, 4);

                        if(two.getShootCell(i, j)==-1) drawPoint(memDC, i+1, j+1, 3);
                        else if(two.getShootCell(i, j)==1) drawCross(memDC, i+1, j+1, 3);
                        if(two.getWoundCell(i, j)==-1) drawPoint(memDC, i+1, j+1, 4);
                        else if(two.getWoundCell(i, j)==1) drawCross(memDC, i+1, j+1, 4);

                    }
                drawText(memDC, to_string(one.counter), xCell/2*cellSize, 2);
                drawText(memDC, to_string(two.counter), xCell/2*cellSize, 13*cellSize);
                
                BitBlt(hDC, 0, 0, width, height, memDC, 0, 0, SRCCOPY);
                SelectObject(memDC, oldBtm);
                DeleteObject(hScreen);
                DeleteDC(memDC);
                ReleaseDC(hwnd, hDC);
                break;
        }
        break;
    default:                /* for messages that we don't deal with */
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}
void drawText(HDC hDC, string str, int x, int y) {
    SetBkMode(hDC, TRANSPARENT);
    TextOut(hDC, x, y, str.c_str(), static_cast<int>(str.length()));
}
void drawCell(HDC hDC, int x, int y, int k) {
    HBRUSH hBrush = CreateSolidBrush(clBackgroundColor);
    HPEN hPen = CreatePen(PS_SOLID, 3, clBoxLineColor);
    HBRUSH hOldBrush = static_cast<HBRUSH>(SelectObject(hDC, hBrush));
    HPEN hOldPen = static_cast<HPEN>(SelectObject(hDC, hPen));

    if(k==0) Rectangle(hDC, x*cellSize, y*cellSize+cellSize, x*cellSize+cellSize+1, y*cellSize+cellSize*2+1);
    if(k==1) Rectangle(hDC, x*cellSize, y*cellSize+cellSize, x*cellSize+cellSize+1, y*cellSize+cellSize*2+1);
    if(k==2) Rectangle(hDC, 13*cellSize+x*cellSize, y*cellSize+cellSize, x*cellSize+14*cellSize+1, y*cellSize+cellSize*2+1);
    if(k==3) Rectangle(hDC, x*cellSize, y*cellSize+14*cellSize, x*cellSize+cellSize+1, y*cellSize+cellSize*15+1);
    if(k==4) Rectangle(hDC, 13*cellSize+x*cellSize, y*cellSize+14*cellSize, x*cellSize+14*cellSize+1, y*cellSize+cellSize*15+1);

    SelectObject(hDC, hOldBrush);
    SelectObject(hDC, hOldPen);
    DeleteObject(hBrush);
    DeleteObject(hPen);
}
void drawPoint(HDC hDC, int x, int y, int k) {
    HPEN hPen = CreatePen(PS_SOLID, 3, clRedColor);
    HPEN hOldPen = static_cast<HPEN>(SelectObject(hDC, hPen));

    if(k==1) Ellipse(hDC, 0.46*cellSize+x*cellSize, y*cellSize+cellSize*1.46, 0.54*cellSize+x*cellSize+1, y*cellSize+cellSize*1.54+1);
    if(k==2) Ellipse(hDC, 13.46*cellSize+x*cellSize, y*cellSize+cellSize*1.46, 13.54*cellSize+x*cellSize+1, y*cellSize+cellSize*1.54+1);
    if(k==3) Ellipse(hDC, 0.46*cellSize+x*cellSize, y*cellSize+cellSize*14.46, 0.54*cellSize+x*cellSize+1, y*cellSize+cellSize*14.54+1);
    if(k==4) Ellipse(hDC, 13.46*cellSize+x*cellSize, y*cellSize+cellSize*14.46, 13.54*cellSize+x*cellSize+1, y*cellSize+cellSize*14.54+1);

    SelectObject(hDC, hOldPen);
    DeleteObject(hPen);
}
void drawCross(HDC hDC, int x, int y, int k) {
    HPEN hPen = CreatePen(PS_SOLID, 2, clRedColor);
    HPEN hOldPen = static_cast<HPEN>(SelectObject(hDC, hPen));

    if(k==1) {
        MoveToEx(hDC, x*cellSize+2, y*cellSize+cellSize+2, NULL);
        LineTo(hDC, x*cellSize+cellSize-2, y*cellSize+cellSize*2-2);
        MoveToEx(hDC, x*cellSize+cellSize-2, y*cellSize+cellSize+2, NULL);
        LineTo(hDC, x*cellSize+2, y*cellSize+cellSize*2-2);
    } else if(k==2) {
        MoveToEx(hDC, 13*cellSize+x*cellSize+2, y*cellSize+cellSize+2, NULL);
        LineTo(hDC, x*cellSize+14*cellSize-2,  y*cellSize+cellSize*2-2);
        MoveToEx(hDC, 14*cellSize+x*cellSize-2, y*cellSize+cellSize+2, NULL);
        LineTo(hDC, 13*cellSize+x*cellSize+2, y*cellSize+cellSize*2-2);
    }else if(k==3) {
        MoveToEx(hDC, x*cellSize+2, y*cellSize+14*cellSize+2, NULL);
        LineTo(hDC, x*cellSize+cellSize-2, y*cellSize+cellSize*15-2);
        MoveToEx(hDC, x*cellSize+cellSize-2, y*cellSize+14*cellSize+2, NULL);
        LineTo(hDC, x*cellSize+2, y*cellSize+cellSize*15-2);
    } else if(k==4) {
        MoveToEx(hDC, 13*cellSize+x*cellSize+2, y*cellSize+14*cellSize+2, NULL);
        LineTo(hDC, x*cellSize+14*cellSize-2,  y*cellSize+cellSize*15-2);
        MoveToEx(hDC, 14*cellSize+x*cellSize-2, y*cellSize+14*cellSize+2, NULL);
        LineTo(hDC, 13*cellSize+x*cellSize+2, y*cellSize+cellSize*15-2);
    }

    SelectObject(hDC, hOldPen);
    DeleteObject(hPen);
}
void drawArea(HDC hDC) {
    drawLine(hDC);

    HPEN hPen = CreatePen(PS_SOLID, 3, clBoxLineColor);
    HPEN hOldPen = static_cast<HPEN>(SelectObject(hDC, hPen));
    HBRUSH hOldBrush = static_cast<HBRUSH>(SelectObject(hDC, GetStockBrush(NULL_BRUSH)));

    /* First Box */
    Rectangle(hDC, cellSize, 2*cellSize, 11*cellSize+1, 12*cellSize+1);
    for(int i=1; i<=10; i++) {
        drawText(hDC, string(1,static_cast<char>(64+i)), cellSize*i+3, cellSize+2);
        drawText(hDC, to_string(i), 2, cellSize*(i+1)+2);
    }

    /* Second Box */
    Rectangle(hDC, 14*cellSize, 2*cellSize, 24*cellSize+1, 12*cellSize+1);
    for(int i=1; i<=10; i++) {
        drawText(hDC, string(1,static_cast<char>(64+i)), cellSize*13+cellSize*i+3, cellSize+2);
        drawText(hDC, to_string(i), cellSize*13+2, cellSize*(i+1)+2);
    }

    /* Third Box */
    Rectangle(hDC, cellSize, 15*cellSize, 11*cellSize+1, 25*cellSize+1);
    for(int i=1; i<=10; i++) {
        drawText(hDC, string(1,static_cast<char>(64+i)), cellSize*i+3, 14*cellSize+2);
        drawText(hDC, to_string(i), 2, cellSize*(i+14)+2);
    }

    /* Fourth Box */
    Rectangle(hDC, 14*cellSize, 15*cellSize, 24*cellSize+1, 25*cellSize+1);
    for(int i=1; i<=10; i++) {
        drawText(hDC, string(1,static_cast<char>(64+i)), cellSize*13+cellSize*i+3, 14*cellSize+2);
        drawText(hDC, to_string(i), cellSize*13+2, cellSize*(i+14)+2);
    }

    SelectObject(hDC, hOldBrush);
    SelectObject(hDC, hOldPen);
    DeleteObject(hPen);
}
void drawLine(HDC hDC) {
    HBRUSH hBrush = CreateSolidBrush(clBackgroundColor);
    HBRUSH hOldBrush = static_cast<HBRUSH>(SelectObject(hDC, hBrush));

    /* Draw all window */
    Rectangle(hDC, 0, 0, width, height);

    SelectObject(hDC, hOldBrush);
    DeleteObject(hBrush);

    HPEN hPen = CreatePen(PS_SOLID, 1, clLineColor);
    HPEN hOldPen = static_cast<HPEN>(SelectObject(hDC, hPen));

    /* Horizontal lines */
    for(int i=0; i<xCell; i++)
    {
        MoveToEx(hDC, i*cellSize, cellSize, NULL);
        LineTo(hDC, i*cellSize, height);
    }
    /* Vertical lines */
    for(int i=0; i<yCell; i++)
    {
        MoveToEx(hDC, 0, i*cellSize, NULL);
        LineTo(hDC, width, i*cellSize);
    }

    SelectObject(hDC, hOldPen);
    DeleteObject(hPen);
}

Read Also: C++ Graphics Program to Draw Bouncing Ball Animation on Surface in Command Line

Final Words

C++ Graphics Program to Build Multiplayer Sea Battleship Game GUI Desktop App We hope this article solves all your doubts. If in doubt let me know.

Hi, I'm Ranjith a full-time Blogger, YouTuber, Affiliate Marketer, & founder of Coding Deekshi. Here, I post about programming to help developers.

Share on:

Leave a Comment