From 1a7348dbd07fa212fc4ef83c9d55d40f20081edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barra=20=C3=93=20Cath=C3=A1in?= Date: Mon, 16 Oct 2023 23:43:21 +0100 Subject: [PATCH] Current Working Tree on <2023-10-16> --- source/Spacewar-Client.c | 124 +++++++++++++++++++++++++++++++------- source/Spacewar-Physics.c | 29 ++++++--- source/Spacewar-Physics.h | 2 +- source/Spacewar-Server.c | 16 ++--- 4 files changed, 131 insertions(+), 40 deletions(-) diff --git a/source/Spacewar-Client.c b/source/Spacewar-Client.c index 927a2bb..d091e84 100644 --- a/source/Spacewar-Client.c +++ b/source/Spacewar-Client.c @@ -17,8 +17,7 @@ const char * messageStrings[] = {"HELLO", "GOODBYE", "PING", "PONG", "SECRET"}; typedef struct SpacewarNetworkConfig { - uint8_t playerNumber; - uint32_t secretKey; + SpacewarClientInput input; SpacewarState * state; } SpacewarNetworkConfig; @@ -42,23 +41,20 @@ void * runNetworkThread (void * parameters) // A structure to store the most recent state from the network: SpacewarState * updatedState = calloc(1, sizeof(SpacewarState)); - - SpacewarClientInput input; - input.secret = configuration->secretKey; - input.playerNumber = configuration->playerNumber; while (true) { - sendto(udpSocket, &input, sizeof(SpacewarClientInput), 0, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in)); + sendto(udpSocket, &configuration->input, sizeof(SpacewarClientInput), 0, + (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in)); recvfrom(udpSocket, updatedState, sizeof(SpacewarState), 0, NULL, NULL); memcpy(configuration->state, updatedState, sizeof(SpacewarState)); -// printf("Received, %f\t%f\n", updatedState->playerStates[0].position.xComponent, -// updatedState->playerStates[0].position.yComponent); } } int main(int argc, char ** argv) { + xyVector upVector = {0, 0.1}; + // Initialize the SDL library, video, sound, and input: if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { @@ -73,7 +69,8 @@ int main(int argc, char ** argv) TTF_Init(); // Create an SDL window and rendering context in that window: - SDL_Window * window = SDL_CreateWindow("SDL_TEST", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 360, 0); + SDL_Window * window = SDL_CreateWindow("SDL_TEST", SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, 640, 360, 0); uint32_t rendererFlags = SDL_RENDERER_ACCELERATED; SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, rendererFlags); SDL_SetWindowTitle(window, "Spacewar!"); @@ -167,6 +164,7 @@ int main(int argc, char ** argv) printf("Connected.\n"); bool playerNumberSet, secretKeySet; + uint8_t playerNumber; SpacewarNetworkConfig networkConfiguration; SpacewarMessage message; @@ -178,21 +176,20 @@ int main(int argc, char ** argv) case 0: { playerNumberSet = true; - networkConfiguration.playerNumber = message.content; + playerNumber = message.content; + networkConfiguration.input.playerNumber = message.content; break; } case 4: { secretKeySet = true; - networkConfiguration.secretKey = message.content; + networkConfiguration.input.secret = message.content; } } } - networkConfiguration.state = calloc(1, sizeof(SpacewarState)); - - printf("Player Number: %u\n" - "Secret Key: %u\n", networkConfiguration.playerNumber, networkConfiguration.secretKey); + SpacewarState * state = calloc(1, sizeof(SpacewarState)); + networkConfiguration.state = state; // Spawn network thread: pthread_t networkThread; @@ -203,20 +200,101 @@ int main(int argc, char ** argv) { pthread_t clientSidePredictionThread; } + + // Load in all of our textures: + SDL_Texture * blackHoleTexture, * idleTexture, * acceleratingTexture, * clockwiseTexture, + * anticlockwiseTexture, * currentTexture, * acceleratingTexture2, *blackHolePointerTexture; + + SDL_Rect starfieldRect; + SDL_Texture * starfieldTexture = IMG_LoadTexture(renderer, "../Images/Starfield.png"); + SDL_QueryTexture(starfieldTexture, NULL, NULL, &starfieldRect.w, &starfieldRect.h); + + idleTexture = IMG_LoadTexture(renderer, "../Images/Ship-Idle.png"); + blackHoleTexture = IMG_LoadTexture(renderer, "../Images/Black-Hole.png"); + clockwiseTexture = IMG_LoadTexture(renderer, "../Images/Ship-Clockwise.png"); + acceleratingTexture = IMG_LoadTexture(renderer, "../Images/Ship-Accelerating.png"); + anticlockwiseTexture = IMG_LoadTexture(renderer, "../Images/Ship-Anticlockwise.png"); + blackHolePointerTexture = IMG_LoadTexture(renderer, "../Images/Black-Hole-Pointer.png"); + acceleratingTexture2 = IMG_LoadTexture(renderer, "../Images/Ship-Accelerating-Frame-2.png"); + currentTexture = acceleratingTexture; + + SDL_Rect blackHoleRectangle; + blackHoleRectangle.x = 0; + blackHoleRectangle.y = 0; + SDL_QueryTexture(blackHoleTexture, NULL, NULL, + &blackHoleRectangle.w, &blackHoleRectangle.h); + + + SDL_Rect blackHolePointerRectangle; + blackHolePointerRectangle.x = 0; + blackHolePointerRectangle.y = 0; + blackHolePointerRectangle.w = 128; + blackHolePointerRectangle.h = 128; + + SDL_Rect shipRectangles[32]; + for (int index = 0; index < 32; index++) + { + shipRectangles[index].w = 32; + shipRectangles[index].h = 32; + } - // Spawn graphics thread: int width, height; while (true) { SDL_PumpEvents(); + SDL_GetKeyboardState(&keyCount); + SDL_GetWindowSize(window, &width, &height); + + // Do input: + networkConfiguration.input.input.turningClockwise = keyboardState[SDL_SCANCODE_RIGHT]; + networkConfiguration.input.input.turningAnticlockwise = keyboardState[SDL_SCANCODE_LEFT]; + networkConfiguration.input.input.accelerating = keyboardState[SDL_SCANCODE_UP]; + + // Clear the screen: SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); - SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); - SDL_GetWindowSize(window, &width, &height); - SDL_RenderDrawLine(renderer, width/2, height/2, - width/2 + (long)(networkConfiguration.state->playerStates[0].velocity.xComponent), - height/2 + (long)(networkConfiguration.state->playerStates[0].velocity.yComponent)); + + // Draw the starfield: + starfieldRect.x = -900 - (long)state->playerStates[playerNumber].position.xComponent % 800; + starfieldRect.y = -900 - (long)state->playerStates[playerNumber].position.yComponent % 800; + + while(starfieldRect.x <= (width + 800)) + { + while(starfieldRect.y <= (height + 800)) + { + SDL_RenderCopy(renderer, starfieldTexture, NULL, &starfieldRect); + starfieldRect.y += 800; + } + starfieldRect.y = -900 - (long)state->playerStates[playerNumber].position.yComponent % 800; + starfieldRect.x += 800; + } + + // Draw the black hole: + blackHoleRectangle.x = ((long)(0 - state->playerStates[playerNumber].position.xComponent + - (blackHoleRectangle.w / 2)) + width/2); + blackHoleRectangle.y = ((long)(0 - state->playerStates[playerNumber].position.yComponent + - (blackHoleRectangle.h / 2)) + height/2); + + SDL_RenderCopy(renderer, blackHoleTexture, NULL, &blackHoleRectangle); + + // Draw the black hole directional indicator: + blackHolePointerRectangle.x = width/2 - (blackHolePointerRectangle.w / 2); + blackHolePointerRectangle.y = height/2 - (blackHolePointerRectangle.h / 2); + SDL_RenderCopyEx(renderer, blackHolePointerTexture, NULL, &blackHolePointerRectangle, + angleBetweenVectors(&state->playerStates[playerNumber].gravity, &upVector) + 90, + NULL, 0); + + // Draw the player's ship: + shipRectangles[playerNumber].x = (width/2) - 16; + shipRectangles[playerNumber].y = (height/2) - 16; + + SDL_RenderCopyEx(renderer, currentTexture, NULL, &shipRectangles[playerNumber], + angleBetweenVectors(&state->playerStates[playerNumber].engine, &upVector) + 90, + NULL, 0); + + // Present to the screen: SDL_RenderPresent(renderer); + SDL_Delay(1000 / 144); } pthread_join(networkThread, NULL); @@ -240,5 +318,5 @@ int main(int argc, char ** argv) // along with this program. If not, see . // Local Variables: -// compile-command: "gcc `sdl2-config --libs --cflags` Spacewar-Client.c Spacewar-Graphics.c Spacewar-Server.c -lSDL2_image -lSDL2_ttf -lm -o 'Spacewar-Client'" +// compile-command: "gcc `sdl2-config --libs --cflags` Spacewar-Client.c Spacewar-Graphics.c Spacewar-Server.c Spacewar-Physics.c -lSDL2_image -lSDL2_ttf -lm -o 'Spacewar-Client'" // End: diff --git a/source/Spacewar-Physics.c b/source/Spacewar-Physics.c index 3e1cc6a..792bcdf 100644 --- a/source/Spacewar-Physics.c +++ b/source/Spacewar-Physics.c @@ -10,7 +10,7 @@ void doPhysicsTick(SpacewarState * state) { - double gravityMagnitude, gravityAcceleration; + double gravityMagnitude, gravityAcceleration, velocityMagnitude; for (int shipIndex = 0; shipIndex < 32; shipIndex++) { SpacewarShipState * currentShip = &state->playerStates[shipIndex]; @@ -21,26 +21,40 @@ void doPhysicsTick(SpacewarState * state) 0.0, 0.0, ¤tShip->gravity); gravityMagnitude = normalizeXYVector(¤tShip->gravity); gravityAcceleration = 0; - + // Some maths that felt okay: if (gravityMagnitude >= 116) { - gravityAcceleration = pow(2, (3000 / (gravityMagnitude / 2))) / 16; + gravityAcceleration = (45000 / pow(gravityMagnitude, 2)) * 6.67; } - // We're actually in the black hole; teleport: + // We're pactually in the black hole; teleport: else { currentShip->position.xComponent = (double)(random() % 7500); currentShip->position.yComponent = (double)(random() % 7500); - currentShip->velocity.xComponent *= 0.01; - currentShip->velocity.yComponent *= 0.01; + currentShip->velocity.xComponent = 0; + currentShip->velocity.yComponent = 0; } - + multiplyXYVector(¤tShip->gravity, gravityAcceleration); // Apply Inputs: + + // Rotate the engine vector if needed: + if (state->playerInputs[shipIndex].turningClockwise == 1) + { + rotateXYVector(¤tShip->engine, 2.5); + } + if (state->playerInputs[shipIndex].turningAnticlockwise == 1) + { + rotateXYVector(¤tShip->engine, -2.5); + } // Apply Gravity and Velocity to Position: + if (state->playerInputs[shipIndex].accelerating == 1) + { + addXYVector(¤tShip->velocity, ¤tShip->engine); + } addXYVector(¤tShip->velocity, ¤tShip->gravity); addXYVector(¤tShip->position, ¤tShip->velocity); @@ -65,7 +79,6 @@ void doPhysicsTick(SpacewarState * state) state->playerStates[shipIndex].position.yComponent = 7999.0; state->playerStates[shipIndex].velocity.yComponent *= 0.9; } - printf("%f %f\n", currentShip->position.xComponent, currentShip->position.yComponent); } } } diff --git a/source/Spacewar-Physics.h b/source/Spacewar-Physics.h index 0ea6f24..c6f707e 100644 --- a/source/Spacewar-Physics.h +++ b/source/Spacewar-Physics.h @@ -22,7 +22,7 @@ typedef struct SpacewarShipState typedef struct SpacewarShipInput { double turningAmount, acceleratingAmount; - bool turningClockwise, turningAnticlockwise, accelerating; + uint8_t turningClockwise, turningAnticlockwise, accelerating; } SpacewarShipInput; typedef struct SpacewarClientInput diff --git a/source/Spacewar-Server.c b/source/Spacewar-Server.c index 3ff0a95..b0bcf55 100644 --- a/source/Spacewar-Server.c +++ b/source/Spacewar-Server.c @@ -43,7 +43,11 @@ void sendCurrentState(SpacewarState * state, SpacewarConnection * connections, i void * runServerPhysics(void * parameters) { SpacewarServerSharedState * sharedState = (SpacewarServerSharedState *)parameters; - + for(int index = 0; index < 32; index++) + { + sharedState->physicsState->playerStates[index].engine.yComponent = 0.1; + } + while (true) { doPhysicsTick(sharedState->physicsState); @@ -67,25 +71,21 @@ void * runInputReceiver(void * parameters) { bytesRead = recvfrom(sharedState->udpSocket, &input, sizeof(SpacewarClientInput), 0, (struct sockaddr *)&clientAddress, &socketAddressLength); -// printf("Read an input... "); if (bytesRead == sizeof(SpacewarClientInput)) { -// printf("It's the right size... "); if (input.playerNumber < 32) { -// printf("Valid player number... "); if (input.secret == sharedState->connections[input.playerNumber].playerSecret) { -// printf("Valid input for player %d!\n", index); sharedState->physicsState->playerStates[input.playerNumber].inPlay = true; memcpy(&sharedState->connections[input.playerNumber].clientAddress, &clientAddress, sizeof(struct sockaddr_in)); - memcpy(&sharedState->physicsState->playerInputs[input.playerNumber], &(input.input), - sizeof(struct SpacewarShipInput)); + memcpy(&sharedState->physicsState->playerInputs[input.playerNumber], &input.input, + sizeof(SpacewarShipInput)); } } } - bzero(&input, sizeof(struct SpacewarClientInput)); + bzero(&input, sizeof(SpacewarClientInput)); } return NULL;