#include <glad/glad.h> #include <GLFW/glfw3.h> #include <math.h> #include <iostream> #include <string> #include <chrono> #include <thread> #include <filesystem> #include "networking.h" #include "renderer.h" #include "raycaster.h" #include "UI.h" #include "constants.h" using std::cin; using std::cout; using std::endl; using std::string; using std::thread; // NETWORK Network network; char inBuff[IN_OUT_BUFF_SIZE]; // data to receive char outBuff[IN_OUT_BUFF_SIZE]; // data to send size_t bytesReceived; // PLAYERS GLfloat positions[STARTING_PARAMETER_COUNT] = {}; // our x,y GLfloat otherPlayerPositions[STARTING_PARAMETER_COUNT] = {}; // other player x, y GLfloat vertices1[VERTICES_SIZE]; // our controlled character matrix GLfloat vertices2[VERTICES_SIZE]; // other player matrix // RENDERING GLFWwindow* window; // GAMESTATE int GAMESTATE = START; bool connected = false; double xpos = 0, ypos = 0; // mouse bool firstMouse = true; double lastX = 0, lastY = 0; bool shooting = false; int hitCount = 0; float deltaTime = 1 / 60; // stores actual speed of the game, 1/60 is placeholder double lastShotTime = 0.0; bool newImageAvaliable = false; string msg = ""; static void updatePlayer(GLfloat* newPositions, GLfloat* playerVerticies) { // newPositions comes in as [x, y], vertices is [x, y, z, r, g, b, ... ... ] playerVerticies[0] = newPositions[0] + PLAYER_SIZE; // Top right x playerVerticies[1] = newPositions[1] + PLAYER_SIZE; // Top right y playerVerticies[6] = newPositions[0] - PLAYER_SIZE; // Top left x playerVerticies[7] = newPositions[1] + PLAYER_SIZE; // Top left y playerVerticies[12] = newPositions[0] - PLAYER_SIZE; // Bottom left x playerVerticies[13] = newPositions[1] - PLAYER_SIZE; // Bottom left y playerVerticies[18] = newPositions[0] + PLAYER_SIZE; // Bottom right x playerVerticies[19] = newPositions[1] - PLAYER_SIZE; // Bottom right y } static bool isCollision(GLfloat xPos, GLfloat yPos) { int mapXpos = static_cast<int>((xPos + 1.0f) / tileSize); int mapYpos = static_cast<int>((1.0f - yPos) / tileSize); if (mapXpos < 0) mapXpos = 0; if (mapYpos < 0) mapYpos = 0; if (mapXpos >= mapX) mapXpos = mapX - 1; if (mapYpos >= mapY) mapYpos = mapY - 1; return map[mapYpos * mapX + mapXpos] == 1; } bool isCrosshairOverPlayer(float xpos, float ypos, const GLfloat* myPos, const GLfloat* otherPos) { float dx = otherPos[0] - myPos[0]; float dy = otherPos[1] - myPos[1]; float distance = sqrt(dx * dx + dy * dy); float angleToOther = atan2f(dx, dy) * (180.0f / 3.14159f); float relativeAngle = angleToOther - xpos; if (relativeAngle < -180.0f) relativeAngle += 360.0f; if (relativeAngle > 180.0f) relativeAngle -= 360.0f; float screenX = (relativeAngle / (RAY_NUM * 0.5f)); float verticalAngleToOther = 0.0f; float relativePitch = verticalAngleToOther - ypos; float screenY = (relativePitch / 100.0f); return fabs(screenX) < (0.005 / distance) && fabs(screenY) < (0.01 / distance); // adjust numbers for hitbox } static void processInput(SOCKET sock) { float moveAmount = MOVE_SPEED * deltaTime; // scales move speed by framerate if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } double x, y; glfwGetCursorPos(window, &x, &y); if (firstMouse) { lastX = x; lastY = y; firstMouse = false; } double xoffset = x - lastX; double yoffset = y - lastY; lastX = x; lastY = y; xoffset /= MOUSE_SENS; yoffset /= MOUSE_SENS; xpos += xoffset; ypos += yoffset; if (ypos > 50) ypos = 50; if (ypos < -50) ypos = -50; if (xpos < 0) xpos += 360; if (xpos >= 360) xpos -= 360; static double shotCooldown = 1.0 / 60.0; double currentTime = glfwGetTime(); if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) { if (currentTime - lastShotTime >= shotCooldown) { shooting = true; lastShotTime = currentTime; } else { shooting = false; } } else { shooting = false; GLfloat newX = positions[0]; GLfloat newY = positions[1]; if ((glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)) { newX -= moveAmount * -sin(degToRad(xpos)); newY += moveAmount * cos(degToRad(xpos)); } if ((glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)) { newX += moveAmount * -sin(degToRad(xpos)); newY -= moveAmount * cos(degToRad(xpos)); } if ((glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)) { newX -= moveAmount * cos(degToRad(xpos)); newY += moveAmount * sin(degToRad(xpos)); } if ((glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)) { newX += moveAmount * cos(degToRad(xpos)); newY -= moveAmount * sin(degToRad(xpos)); } if (!isCollision(newX, newY)) { positions[0] = newX; positions[1] = newY; } else { if (!isCollision(newX, positions[1])) { positions[0] = newX; } if (!isCollision(positions[0], newY)) { positions[1] = newY; } } updatePlayer(positions, vertices1); } if (GAMESTATE == DEBUG) { GLfloat newX = otherPlayerPositions[0]; GLfloat newY = otherPlayerPositions[1]; if ((glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)) { newY += moveAmount; } if ((glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)) { newY -= moveAmount; } if ((glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)) { newX -= moveAmount; } if ((glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS)) { newX += moveAmount; } if (!isCollision(newX, newY)) { otherPlayerPositions[0] = newX; otherPlayerPositions[1] = newY; } else { if (!isCollision(newX, otherPlayerPositions[1])) { otherPlayerPositions[0] = newX; } if (!isCollision(otherPlayerPositions[0], newY)) { otherPlayerPositions[1] = newY; } } updatePlayer(otherPlayerPositions, vertices2); } } static bool sendStatePacket(SOCKET sock) { char outBuff[IN_OUT_BUFF_SIZE]; int offset = 0; // Use header 1 for the full state packet outBuff[offset++] = 1; // Serialize positions[0] as a network order uint32_t uint32_t netPosX; memcpy(&netPosX, &positions[0], sizeof(float)); netPosX = htonl(netPosX); memcpy(outBuff + offset, &netPosX, sizeof(uint32_t)); offset += sizeof(uint32_t); // Serialize positions[1] as a network order uint32_t uint32_t netPosY; memcpy(&netPosY, &positions[1], sizeof(float)); netPosY = htonl(netPosY); memcpy(outBuff + offset, &netPosY, sizeof(uint32_t)); offset += sizeof(uint32_t); // Serialize shooting flag as uint8_t 1 for true 0 for false outBuff[offset++] = shooting ? 1 : 0; // Serialize hitCount as int32_t in network order int32_t netHitCount = htonl(hitCount); memcpy(outBuff + offset, &netHitCount, sizeof(int32_t)); offset += sizeof(int32_t); // Serialize GAMESTATE as int32_t in network order int32_t gameState = htonl(GAMESTATE); //cout << "sending " << gameState << endl; memcpy(outBuff + offset, &gameState, sizeof(int32_t)); offset += sizeof(int32_t); return network.sendData(sock, outBuff, offset); } static bool sendPlayerTexture(SOCKET sock) { std::ifstream textureFile("textures/playerTexture.png", std::ios::binary | std::ios::ate); if (!textureFile.is_open()) { std::cerr << "Failed to open texture file for reading." << endl; return false; } std::streamsize fileSize = textureFile.tellg(); textureFile.seekg(0, std::ios::beg); if (fileSize > IN_OUT_BUFF_SIZE - sizeof(uint8_t) - sizeof(uint32_t)) { std::cerr << "Texture file is too large to send." << endl; textureFile.close(); return false; } std::vector<char> buffer(static_cast<size_t>(fileSize)); if (!textureFile.read(buffer.data(), fileSize)) { std::cerr << "Failed to read texture file." << endl; textureFile.close(); return false; } textureFile.close(); char outBuff[IN_OUT_BUFF_SIZE]; int offset = 0; outBuff[offset++] = 2; uint32_t netFileSize = htonl(static_cast<uint32_t>(fileSize)); memcpy(outBuff + offset, &netFileSize, sizeof(uint32_t)); offset += sizeof(uint32_t); memcpy(outBuff + offset, buffer.data(), static_cast<size_t>(fileSize)); offset += static_cast<int>(fileSize); newImageAvaliable = true; return network.sendData(sock, outBuff, offset); } static void handlePacket(const char* packet, size_t packetSize) { int offset = 0; uint8_t header = packet[offset++]; if (header == 1) { // Full state packet expects 2 uint32_t positions, 1 byte for shooting, 1 int32_t hitCount if (packetSize >= offset + (2 * sizeof(uint32_t) + sizeof(uint8_t) + sizeof(int32_t))) { // Deserialize positions[0] uint32_t netPosX; memcpy(&netPosX, packet + offset, sizeof(uint32_t)); netPosX = ntohl(netPosX); float posX; memcpy(&posX, &netPosX, sizeof(float)); offset += sizeof(uint32_t); // Deserialize positions[1] uint32_t netPosY; memcpy(&netPosY, packet + offset, sizeof(uint32_t)); netPosY = ntohl(netPosY); float posY; memcpy(&posY, &netPosY, sizeof(float)); offset += sizeof(uint32_t); // Deserialize shooting flag uint8_t shootFlag = packet[offset++]; bool remoteShooting = (shootFlag != 0); // Deserialize hitCount int32_t netHitCount; memcpy(&netHitCount, packet + offset, sizeof(int32_t)); int receivedHitCount = ntohl(netHitCount); offset += sizeof(int32_t); // Deserialize GAMESTATE int32_t state; memcpy(&state, packet + offset, sizeof(int32_t)); int receivedstate = ntohl(state); offset += sizeof(int32_t); //cout << "receiving " << receivedstate << endl; // Update if (receivedstate == WIN) { GAMESTATE = LOSS; // we really only detect when we lose and send that but checking anyway } else if (receivedstate == LOSS) { GAMESTATE = WIN; msg = "YOU ARE A WINNER"; } otherPlayerPositions[0] = posX; otherPlayerPositions[1] = posY; updatePlayer(otherPlayerPositions, vertices2); if (receivedHitCount >= maxHealth) { cout << "You died." << endl; msg = "YOU ARE A LOSER"; GAMESTATE = LOSS; } } } else if (header == 2) { // Texture packet cout << "recieved texture packet" << endl; int offset = 1; if (packetSize >= offset + sizeof(uint32_t)) { // Deserialize texture data uint32_t netFileSize; memcpy(&netFileSize, packet + offset, sizeof(uint32_t)); uint32_t fileSize = ntohl(netFileSize); offset += sizeof(uint32_t); // Check if the packet contains the full texture data if (packetSize >= offset + fileSize) { // Extract the texture data const char* textureData = packet + offset; // Save the texture data std::ofstream outFile("textures/receivedPlayerTexture.png", std::ios::binary); if (outFile.is_open()) { outFile.write(textureData, fileSize); outFile.close(); // Reload texture //textureIDs[2] = loadTexture("textures/receivedPlayerTexture.png"); } else { std::cerr << "Failed to open file for writing texture." << endl; } } else { std::cerr << "Incomplete texture data received." << endl; } } else { std::cerr << "Texture packet does not contain size information." << endl; } } else { // Unknown } } /* TODO: x wall collisions x other player rendering x textures x texture coordinates x fix hit detection ? texture mapped walls x separate rendering functions x separate raycasting functions x framerate based shooting x UI x start menu x end menu x character editor x character texture sending x text and typing */ int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); window = glfwCreateWindow(SCREEN_X, SCREEN_Y, "AWESOME GAME", nullptr, nullptr); //window = glfwCreateWindow(SCREEN_X, SCREEN_Y, "AWESOME GAME", glfwGetPrimaryMonitor(), nullptr); if (window == nullptr) { cout << "Failed to create GLFW window" << endl; glfwTerminate(); WSACleanup(); return -1; } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { cout << "Failed to initialize GLAD" << endl; return -1; } glViewport(0, 0, SCREEN_X, SCREEN_Y); GLuint dummyTexture = loadTexture("textures/dummyTexture.png"); // 0 GLuint wallTexture = loadTexture("textures/dummyTexture.png"); // wall texture is broken for now... GLuint playerTexture = loadTexture("textures/playerTexture.png"); // previously saved texture but will be updated after main menu GLuint buttonTextures = loadTexture("textures/buttons.png"); GLuint textTextures = loadTexture("textures/boldText.png"); // ensure to update frag shader when adding more textures GLuint textureIDs[] = { dummyTexture, wallTexture, playerTexture, buttonTextures, textTextures }; int textureCount = sizeof(textureIDs) / sizeof(textureIDs[0]); Shader shaderProgram("shaders/default.vert", "shaders/default.frag"); Renderer renderer(shaderProgram, textureIDs, textureCount); shaderProgram.Activate(); glUniform1f(glGetUniformLocation(shaderProgram.ID, "scale"), 1.0f); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); SOCKET sock = INVALID_SOCKET; while (!glfwWindowShouldClose(window)) { bool textBoxEditMode = false; sock = INVALID_SOCKET; SOCKET listeningSocket = INVALID_SOCKET; SOCKET client_socket = INVALID_SOCKET; sockaddr_in client; int clientSize = sizeof(client); bool waitingForClient = false; string placeholderText = "WELCOME, SELECT A MODE TO BEGIN."; const float btnY = 0.15f; const float hostBtnX = -0.05f; const float joinBtnX = 0.35f; const float soloBtnX = 0.75f; const float btnW = 300.0f; const float btnH = 400.0f; const float btnWPressed = 290.0f; const float btnHPressed = 390.0f; Button hostButton = Button(btnW, btnH, hostBtnX, btnY, 200, 50, 50, 4, "HOST"); Button joinButton = Button(btnW, btnH, joinBtnX, btnY, 50, 200, 50, 4, "JOIN"); Button soloButton = Button(btnW, btnH, soloBtnX, btnY, 50, 50, 200, 4, "SOLO"); Text message = Text(1000, 0.35, 0, 4, "ENTER HOST IP ADRESS:"); TextBox IPTextBox = TextBox(600, 50, 0.60, -.250, 4, "__.__.__..."); DrawingBoard drawingBoard(900.0f, 300.0f, -0.65f, 0.1f, "textures/playerTexture.png"); Text drawDesc = Text(800, -0.65, 0.8, 4, "DRAW YOUR PLAYER!"); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); while (!glfwWindowShouldClose(window)) { // main menu if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // networking if (waitingForClient && listeningSocket != INVALID_SOCKET) { client_socket = accept(listeningSocket, (sockaddr*)&client, &clientSize); if (client_socket == INVALID_SOCKET) { int err = WSAGetLastError(); if (err != WSAEWOULDBLOCK) { placeholderText = "Client connection failed!"; closesocket(listeningSocket); listeningSocket = INVALID_SOCKET; WSACleanup(); waitingForClient = false; } } else { closesocket(listeningSocket); listeningSocket = INVALID_SOCKET; sock = client_socket; waitingForClient = false; GAMESTATE = SERVER; placeholderText = "Client connected!"; for (int i = 0; i < STARTING_PARAMETER_COUNT; i++) positions[i] = defaultServerPos[i]; for (int i = 0; i < STARTING_PARAMETER_COUNT; i++) otherPlayerPositions[i] = defaultClientPos[i]; updatePlayer(positions, vertices1); updatePlayer(otherPlayerPositions, vertices2); break; } } Text titleText(SCREEN_X, .35, 0.7f, 4, "AWESOME GAME"); titleText.pushToRenderer(&renderer); Text statusText(SCREEN_X, 0.35, 0.5f, 4, placeholderText); statusText.pushToRenderer(&renderer); Text ipLabel(600, 0.1f, -.250, 4, "IP ADDRESS:"); ipLabel.pushToRenderer(&renderer); IPTextBox.pushToRenderer(&renderer); // drawing board logic drawingBoard.isClicked(window); drawingBoard.pushToRenderer(&renderer); // button visual feedback Button hostButton(btnW, btnH, hostBtnX, btnY, 200, 50, 50, 4, "HOST"); Button joinButton(btnW, btnH, joinBtnX, btnY, 50, 200, 50, 4, "JOIN"); Button soloButton(btnW, btnH, soloBtnX, btnY, 50, 50, 200, 4, "SOLO"); bool hostPressed = hostButton.isClicked(window); bool joinPressed = joinButton.isClicked(window); bool soloPressed = soloButton.isClicked(window); bool hostHovered = hostButton.isHovered(window); bool joinHovered = joinButton.isHovered(window); bool soloHovered = soloButton.isHovered(window); Button hostBtnDraw = hostButton; Button joinBtnDraw = joinButton; Button soloBtnDraw = soloButton; if (hostPressed) { hostBtnDraw = Button(btnWPressed, btnHPressed, hostBtnX, btnY, 255, 50, 50, 4, "HOST"); } else if (hostHovered) { hostBtnDraw = Button(btnW, btnH, hostBtnX, btnY, 230, 50, 50, 4, "HOST"); } if (joinPressed) { joinBtnDraw = Button(btnWPressed, btnHPressed, joinBtnX, btnY, 50, 255, 50, 4, "JOIN"); } else if (joinHovered) { joinBtnDraw = Button(btnW, btnH, joinBtnX, btnY, 50, 230, 50, 4, "JOIN"); } if (soloPressed) { soloBtnDraw = Button(btnWPressed, btnHPressed, soloBtnX, btnY, 50, 50, 255, 4, "SOLO"); } else if (soloHovered) { soloBtnDraw = Button(btnW, btnH, soloBtnX, btnY, 50, 50, 230, 4, "SOLO"); } hostBtnDraw.pushToRenderer(&renderer); joinBtnDraw.pushToRenderer(&renderer); soloBtnDraw.pushToRenderer(&renderer); // instructions Text hostDesc(1600, 0.35, -0.5f, 4, "* HOST: STARTS A SERVER FOR OTHERS TO JOIN."); Text joinDesc(1600, 0.35, -0.6f, 4, "* JOIN: CONNECTS TO EXISTING SERVER BY IP."); Text soloDesc(1600, 0.35, -0.7f, 4, "* SOLO: STARTS A SINGLE PLAYER SESSION."); hostDesc.pushToRenderer(&renderer); joinDesc.pushToRenderer(&renderer); soloDesc.pushToRenderer(&renderer); drawDesc.pushToRenderer(&renderer); // button logic if (hostPressed && !waitingForClient) { listeningSocket = network.serverSetup(); if (listeningSocket == INVALID_SOCKET) { placeholderText = "SERVER SETUP ERROR!"; } else { waitingForClient = true; placeholderText = "WAITING FOR CLIENT ON: " + network.printLocalIPAddress(); } } if (joinPressed) { if (listeningSocket != INVALID_SOCKET) { closesocket(listeningSocket); listeningSocket = INVALID_SOCKET; waitingForClient = false; } if (IPTextBox.message.empty() || IPTextBox.message == "PLEASE ENTER IP HERE.") { IPTextBox.message = "PLEASE ENTER IP HERE."; placeholderText = "PLEASE ENTER A VALID IP ADDRESS."; } else { placeholderText = "IP ADDRESS ERROR TRY AGAIN!"; IPTextBox.pushToRenderer(&renderer); sock = network.clientSetup(IPTextBox.message); if (sock == INVALID_SOCKET) { placeholderText = "IP ADDRESS ERROR TRY AGAIN!"; } else { GAMESTATE = CLIENT; for (int i = 0; i < STARTING_PARAMETER_COUNT; i++) positions[i] = defaultClientPos[i]; for (int i = 0; i < STARTING_PARAMETER_COUNT; i++) otherPlayerPositions[i] = defaultServerPos[i]; updatePlayer(positions, vertices1); updatePlayer(otherPlayerPositions, vertices2); break; } } } if (soloPressed) { if (listeningSocket != INVALID_SOCKET) { closesocket(listeningSocket); listeningSocket = INVALID_SOCKET; WSACleanup(); waitingForClient = false; } GAMESTATE = DEBUG; cout << "debug/singleplayer mode >>" << endl; for (int i = 0; i < STARTING_PARAMETER_COUNT; i++) { positions[i] = defaultServerPos[i]; } for (int i = 0; i < STARTING_PARAMETER_COUNT; i++) { otherPlayerPositions[i] = defaultClientPos[i]; } updatePlayer(positions, vertices1); updatePlayer(otherPlayerPositions, vertices2); break; } // text box input if (IPTextBox.isClicked(window)) { IPTextBox.message = ""; textBoxEditMode = true; } else if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) { textBoxEditMode = false; } if (textBoxEditMode) IPTextBox.collectInput(window); renderer.renderFrame(); if (drawingBoard.saveRequested) { glFinish(); glReadBuffer(GL_BACK); float leftNDC = drawingBoard.xpos - 0.5f * (drawingBoard.width / SCREEN_X); float rightNDC = drawingBoard.xpos + 0.5f * (drawingBoard.width / SCREEN_X); float bottomNDC = drawingBoard.ypos - 0.5f * (drawingBoard.height / SCREEN_Y); float topNDC = drawingBoard.ypos + 0.5f * (drawingBoard.height / SCREEN_Y); int leftPx = static_cast<int>((leftNDC + 1.0f) * 0.5f * SCREEN_X); int rightPx = static_cast<int>((rightNDC + 1.0f) * 0.5f * SCREEN_X); int bottomPx = static_cast<int>((bottomNDC + 1.0f) * 0.5f * SCREEN_Y); int topPx = static_cast<int>((topNDC + 1.0f) * 0.5f * SCREEN_Y); captureRegion(leftPx, bottomPx, rightPx - leftPx, topPx - bottomPx, drawingBoard.saveAs); drawingBoard.saved = true; drawingBoard.saveRequested = false; } glfwSwapBuffers(window); glfwPollEvents(); } if (GAMESTATE == SERVER || GAMESTATE == CLIENT) { sendPlayerTexture(sock); newImageAvaliable = true; connected = true; //textureIDs[2] = loadTexture("textures/receivedPlayerTexture.png"); //cout << "set received texture" << endl; } else { //cout << "loaded own texture" << endl; //textureIDs[2] = loadTexture("textures/playerTexture.png"); } auto lastTime = std::chrono::high_resolution_clock::now(); Text FPSText = Text(400, 0.8, 0.8, 4, "FPS: 0"); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // multiplayer loop while (!glfwWindowShouldClose(window) && (GAMESTATE == SERVER || GAMESTATE == CLIENT)) { glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); processInput(sock); if (!sendStatePacket(sock)) { cout << "connection lost..." << endl; break; } if (!network.recvData(sock, inBuff, IN_OUT_BUFF_SIZE, bytesReceived)) { cout << "Connection lost..." << endl; break; } handlePacket(inBuff, bytesReceived); for (int i = -0.5 * RAY_NUM; i < 0.5 * RAY_NUM; i++) { // cast rays drawRaycastLine(renderer, xpos + i, xpos, ypos, positions); drawMap(renderer); } // get angle to other player float angleToOther = atan2f((otherPlayerPositions[0] - positions[0]), (otherPlayerPositions[1] - positions[1])); float angleToOtherDegrees = angleToOther * (180.0f / 3.14159f); float relativeAngle = angleToOtherDegrees - xpos; if (relativeAngle < -180.0f) relativeAngle += 360.0f; if (relativeAngle > 180.0f) relativeAngle -= 360.0f; bool onScreen = drawPlayer(renderer, relativeAngle, angleToOther, ypos, otherPlayerPositions, positions, hitCount); // check if we can and draw other player if (shooting && isCrosshairOverPlayer(xpos, ypos, positions, otherPlayerPositions) && onScreen) { shooting = false; hitCount++; if (hitCount > maxHealth) { hitCount = 0; } } drawCrosshair(renderer, Renderer::ColorRGB()); drawPlayerQuad(renderer, positions, Renderer::ColorRGB()); drawPlayerQuad(renderer, otherPlayerPositions, Renderer::ColorRGB()); FPSText.message = "FPS: " + std::to_string(int(1.0f / deltaTime)); FPSText.pushToRenderer(&renderer); renderer.renderFrame(); glfwSwapBuffers(window); glfwPollEvents(); shooting = false; ZeroMemory(inBuff, IN_OUT_BUFF_SIZE); auto currentTime = std::chrono::high_resolution_clock::now(); std::chrono::duration<float> elapsed = currentTime - lastTime; deltaTime = elapsed.count(); lastTime = currentTime; if (newImageAvaliable) { textureIDs[2] = loadTexture("textures/receivedPlayerTexture.png"); newImageAvaliable = false; } } // debug loop while (!glfwWindowShouldClose(window) && (GAMESTATE == DEBUG)) { glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); for (int i = -0.5 * RAY_NUM; i < 0.5 * RAY_NUM; i++) { // cast rays drawRaycastLine(renderer, xpos + i, xpos, ypos, positions); drawMap(renderer); } // angle to other player float angleToOther = atan2f((otherPlayerPositions[0] - positions[0]), (otherPlayerPositions[1] - positions[1])); float angleToOtherDegrees = angleToOther * (180.0f / 3.14159f); float relativeAngle = angleToOtherDegrees - xpos; if (relativeAngle < -180.0f) relativeAngle += 360.0f; if (relativeAngle > 180.0f) relativeAngle -= 360.0f; bool onScreen = drawPlayer(renderer, relativeAngle, angleToOther, ypos, otherPlayerPositions, positions, hitCount); if (shooting && isCrosshairOverPlayer(xpos, ypos, positions, otherPlayerPositions) && onScreen) { shooting = false; hitCount++; if (hitCount > maxHealth) { GAMESTATE = WIN; msg = "GOOD JOB!"; } } drawCrosshair(renderer, Renderer::ColorRGB()); drawPlayerQuad(renderer, positions, Renderer::ColorRGB()); drawPlayerQuad(renderer, otherPlayerPositions, Renderer::ColorRGB()); FPSText.message = "FPS: " + std::to_string(int(1.0f / deltaTime)); FPSText.pushToRenderer(&renderer); renderer.renderFrame(); glfwSwapBuffers(window); glfwPollEvents(); processInput(sock); auto currentTime = std::chrono::high_resolution_clock::now(); std::chrono::duration<float> elapsed = currentTime - lastTime; deltaTime = elapsed.count(); lastTime = currentTime; //cout << "fps: " << 1.0f / deltaTime << endl; } // end menu glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); while (!glfwWindowShouldClose(window) && (GAMESTATE == WIN || GAMESTATE == LOSS)) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); if (connected) { // we dont really enforce sendStatePacket(sock); network.recvData(sock, inBuff, IN_OUT_BUFF_SIZE, bytesReceived); handlePacket(inBuff, bytesReceived); } Text instrText(SCREEN_X, 0, 0.7f, 4, "PRESS 'C' TO GO BACK TO MAIN MENU"); Text statusText(SCREEN_X, 0, 0.5f, 4, msg); instrText.pushToRenderer(&renderer); statusText.pushToRenderer(&renderer); if (glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) { break; closesocket(sock); WSACleanup(); } renderer.renderFrame(); glfwSwapBuffers(window); glfwPollEvents(); } GAMESTATE = START; msg = ""; hitCount = 0; } shaderProgram.Delete(); glfwDestroyWindow(window); glfwTerminate(); closesocket(sock); WSACleanup(); return 0; }