From ce76166c3fe2618ac75fbd9a141b93f4d8949043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barra=20=C3=93=20Cath=C3=A1in?= Date: Sun, 8 Oct 2023 22:22:21 +0100 Subject: [PATCH] Current Working Tree on <2023-10-08> --- source/Spacewar-Client | Bin 0 -> 16920 bytes source/Spacewar-Client.c | 138 ++++++++++++++++++++++++++++++++ source/Spacewar-Graphics.c | 157 +++++++++++++++++++++++++++++++++++++ source/Spacewar-Graphics.h | 55 +++++++++++++ source/Spacewar-Messages.h | 42 ++++++++++ source/Spacewar-Physics.h | 54 +++++++++++++ source/Spacewar-Server.c | 138 ++++++++++++++++++++++++++++++++ source/Spacewar-Server.h | 36 +++++++++ source/xyVector.h | 68 ++++++++++++++++ 9 files changed, 688 insertions(+) create mode 100755 source/Spacewar-Client create mode 100644 source/Spacewar-Client.c create mode 100644 source/Spacewar-Graphics.c create mode 100644 source/Spacewar-Graphics.h create mode 100644 source/Spacewar-Messages.h create mode 100644 source/Spacewar-Physics.h create mode 100644 source/Spacewar-Server.c create mode 100644 source/Spacewar-Server.h create mode 100644 source/xyVector.h diff --git a/source/Spacewar-Client b/source/Spacewar-Client new file mode 100755 index 0000000000000000000000000000000000000000..19b37acf92fa16aa386c18a075b8caba46c81d73 GIT binary patch literal 16920 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 ZOjjY-t4e9lU0Hu*gOa%3rQl-4e*+)F%y|F+ literal 0 HcmV?d00001 diff --git a/source/Spacewar-Client.c b/source/Spacewar-Client.c new file mode 100644 index 0000000..f15fd90 --- /dev/null +++ b/source/Spacewar-Client.c @@ -0,0 +1,138 @@ +// ========================================= +// | Spacewar-Client.c | +// | Copyright (C) 2023, Barra Ó Catháin | +// | See end of file for copyright notice. | +// ========================================= +#include +#include +#include +#include +#include + +#include "Spacewar-Graphics.h" + +int main(int argc, char ** argv) +{ + // Initialize the SDL library, video, sound, and input: + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) + { + printf("SDL Initialization Error: %s\n", SDL_GetError()); + } + + // Initialize image loading: + IMG_Init(IMG_INIT_PNG); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); + + // Initialize font support: + 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); + uint32_t rendererFlags = SDL_RENDERER_ACCELERATED; + SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, rendererFlags); + SDL_SetWindowTitle(window, "Spacewar!"); + SDL_SetWindowResizable(window, SDL_TRUE); + + // Set up keyboard input: + int keyCount = 0; + const uint8_t * keyboardState = SDL_GetKeyboardState(&keyCount); + + // Prep the titlescreen struct: + bool titlescreenInput = false; + TTF_Font * font = TTF_OpenFont("../Robtronika.ttf", 12); + SpacewarTitlescreen titlescreen = prepareTitleScreen(window, renderer, + "../Images/Starfield.png", + "../Images/Title.png", font, + "Press Enter or Button 0."); + // Set up event handling: + SDL_Event event; + bool keepRunning = true; + + // Display the titlescreen until we get an input: + while (!titlescreenInput && keepRunning) + { + // Update events and input: + SDL_PumpEvents(); + SDL_GetKeyboardState(&keyCount); + + // Check windowing system events: + while (SDL_PollEvent(&event) != 0) + { + switch (event.type) + { + case SDL_QUIT: + { + keepRunning = false; + continue; + } + } + } + + // Check if Enter was pressed: + if(keyboardState[SDL_SCANCODE_RETURN] == 1) + { + titlescreenInput = true; + } + + // Draw the title screen: + drawTitleScreen(&titlescreen); + + // Delay enough so that we run at 60 frames in the menu: + SDL_Delay(1000 / 60); + } + + + // Connect to server: + while (keepRunning) + { + // Update events and input: + SDL_PumpEvents(); + SDL_GetKeyboardState(&keyCount); + + // Check windowing system events: + while (SDL_PollEvent(&event) != 0) + { + switch (event.type) + { + case SDL_QUIT: + { + keepRunning = false; + continue; + } + } + } + + drawMenuScreen(&titlescreen); + + // Delay enough so that we run at 60 frames in the menu: + SDL_Delay(1000 / 60); + } + + // Spawn network thread: + + // Spawn game thread: + + // Spawn graphics thread: + + return 0; +} +// ======================================================= +// | End of Spacewar-Client.c, copyright notice follows. | +// ======================================================= + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// Local Variables: +// compile-command: "gcc `sdl2-config --libs --cflags` Spacewar-Client.c Spacewar-Graphics.c -lSDL2_image -lSDL2_ttf -lm -o 'Spacewar-Client'" +// End: diff --git a/source/Spacewar-Graphics.c b/source/Spacewar-Graphics.c new file mode 100644 index 0000000..b469864 --- /dev/null +++ b/source/Spacewar-Graphics.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include + +#include "Spacewar-Graphics.h" + +SpacewarTitlescreen prepareTitleScreen(SDL_Window * window, SDL_Renderer * renderer, + char * starfieldTexturePath, char * logoTexturePath, + TTF_Font * font, char * text) +{ + SpacewarTitlescreen newTitleScreen; + + // Basic state: + newTitleScreen.xScroll = 0; + newTitleScreen.textAlpha = 0; + newTitleScreen.titleAlpha = 0; + + // Requirements for drawing: + newTitleScreen.window = window; + newTitleScreen.renderer = renderer; + + // Textures: + newTitleScreen.titleTexture = IMG_LoadTexture(renderer, logoTexturePath); + newTitleScreen.starfieldTexture = IMG_LoadTexture(renderer, starfieldTexturePath); + + // Text message: + SDL_Color white = {255, 255, 255}; + SDL_Surface * fontSurface = TTF_RenderText_Blended(font, text, white); + newTitleScreen.textTexture = SDL_CreateTextureFromSurface(renderer, fontSurface); + SDL_FreeSurface(fontSurface); + + // Rects: + newTitleScreen.titleRectangle = calloc(1, sizeof(SDL_Rect)); + newTitleScreen.textRectangle = calloc(1, sizeof(SDL_Rect)); + newTitleScreen.starfieldRectangle = calloc(1, sizeof(SDL_Rect)); + + // Set the rects to the size of the textures: + SDL_QueryTexture(newTitleScreen.textTexture, NULL, NULL, NULL, &newTitleScreen.textRectangle->h); + SDL_QueryTexture(newTitleScreen.textTexture, NULL, NULL, &newTitleScreen.textRectangle->w, NULL); + SDL_QueryTexture(newTitleScreen.titleTexture, NULL, NULL, NULL, &newTitleScreen.titleRectangle->h); + SDL_QueryTexture(newTitleScreen.titleTexture, NULL, NULL, &newTitleScreen.titleRectangle->w, NULL); + SDL_QueryTexture(newTitleScreen.starfieldTexture, NULL, NULL, NULL, &newTitleScreen.starfieldRectangle->h); + SDL_QueryTexture(newTitleScreen.starfieldTexture, NULL, NULL, &newTitleScreen.starfieldRectangle->w, NULL); + + return newTitleScreen; +} + +void drawTitleScreen(SpacewarTitlescreen * titlescreen) +{ + // Get the current size of the window: + int width = 0, height = 0; + SDL_GetWindowSize(titlescreen->window, &width, &height); + + // Position the elements on-screen: + titlescreen->titleRectangle->x = (width/2) - (titlescreen->titleRectangle->w / 2); + titlescreen->titleRectangle->y = (height/2) - titlescreen->titleRectangle->h; + + titlescreen->textRectangle->x = (width/2) - (titlescreen->textRectangle->w / 2); + titlescreen->textRectangle->y = (height/2) + (titlescreen->textRectangle->h * 2); + + // Set the renderer colour to black and clear the screen: + SDL_SetRenderDrawColor(titlescreen->renderer, 0, 0, 0, 255); + SDL_RenderClear(titlescreen->renderer); + + // Set the correct position to begin the starfield, and scroll it back for the next frame: + titlescreen->starfieldRectangle->x = 0 - titlescreen->xScroll++; + titlescreen->starfieldRectangle->y = 0; + + // Draw the starfield by tiling the starfield texture: + while (titlescreen->starfieldRectangle->x <= (width + titlescreen->starfieldRectangle->w)) + { + // Go down, covering a column of the screen: + while(titlescreen->starfieldRectangle->y <= (height + titlescreen->starfieldRectangle->h)) + { + SDL_RenderCopy(titlescreen->renderer, titlescreen->starfieldTexture, NULL, + titlescreen->starfieldRectangle); + titlescreen->starfieldRectangle->y += titlescreen->starfieldRectangle->h; + } + + // Back to the top, move over one texture width: + titlescreen->starfieldRectangle->y = 0; + titlescreen->starfieldRectangle->x += titlescreen->starfieldRectangle->w; + } + + // Reset the xScroll if it goes farther than a texture width away: + if (titlescreen->xScroll == titlescreen->starfieldRectangle->w + 1) + { + titlescreen->xScroll = 0; + } + + // Set the opacity of the logo so we can fade it in: + if (titlescreen->titleAlpha < 254) + { + titlescreen->titleAlpha += 10; + } + if (titlescreen->titleAlpha >= 254) + { + titlescreen->titleAlpha = 254; + } + SDL_SetTextureAlphaMod(titlescreen->titleTexture, titlescreen->titleAlpha); + + // Set the opacity of the text so we can fade it in after we fade in the logo: + if (titlescreen->textAlpha < 254 && titlescreen->titleAlpha == 254) + { + titlescreen->textAlpha += 10; + } + if (titlescreen->textAlpha >= 254) + { + titlescreen->textAlpha = 254; + } + SDL_SetTextureAlphaMod(titlescreen->textTexture, titlescreen->textAlpha); + + // Display the logo and text: + SDL_RenderCopy(titlescreen->renderer, titlescreen->titleTexture, NULL, titlescreen->titleRectangle); + SDL_RenderCopy(titlescreen->renderer, titlescreen->textTexture, NULL, titlescreen->textRectangle); + + // Display to the renderer: + SDL_RenderPresent(titlescreen->renderer); +} + +void drawMenuScreen(SpacewarMenuscreen * menuscreen) +{ + // Get the current size of the window: + int width = 0, height = 0; + SDL_GetWindowSize(titlescreen->window, &width, &height); + + // Set the renderer colour to black and clear the screen: + SDL_SetRenderDrawColor(titlescreen->renderer, 0, 0, 0, 255); + SDL_RenderClear(titlescreen->renderer); + + // Set the correct position to begin the starfield, and scroll it back for the next frame: + titlescreen->starfieldRectangle->x = 0 - titlescreen->xScroll++; + titlescreen->starfieldRectangle->y = 0; + + // Draw the starfield by tiling the starfield texture: + while (titlescreen->starfieldRectangle->x <= (width + titlescreen->starfieldRectangle->w)) + { + // Go down, covering a column of the screen: + while(titlescreen->starfieldRectangle->y <= (height + titlescreen->starfieldRectangle->h)) + { + SDL_RenderCopy(titlescreen->renderer, titlescreen->starfieldTexture, NULL, + titlescreen->starfieldRectangle); + titlescreen->starfieldRectangle->y += titlescreen->starfieldRectangle->h; + } + + // Back to the top, move over one texture width: + titlescreen->starfieldRectangle->y = 0; + titlescreen->starfieldRectangle->x += titlescreen->starfieldRectangle->w; + } + + // Display to the renderer: + SDL_RenderPresent(titlescreen->renderer); +} + diff --git a/source/Spacewar-Graphics.h b/source/Spacewar-Graphics.h new file mode 100644 index 0000000..dd94e32 --- /dev/null +++ b/source/Spacewar-Graphics.h @@ -0,0 +1,55 @@ +// ========================================= +// | Spacewar-Graphics.h | +// | Copyright (C) 2023, Barra Ó Catháin | +// | See end of file for copyright notice. | +// ========================================= +#ifndef SPACEWAR_GRAPHICS +#define SPACEWAR_GRAPHICS + +#include +#include + +typedef struct SpacewarTitlescreen +{ + SDL_Window * window; + SDL_Renderer * renderer; + uint16_t xScroll, titleAlpha, textAlpha; + SDL_Texture * titleTexture, * textTexture, * starfieldTexture; + SDL_Rect * titleRectangle, * textRectangle, * starfieldRectangle; +} SpacewarTitlescreen; + +typedef struct SpacewarMenuscreen +{ + SDL_Window * window; + SDL_Renderer * renderer; + uint16_t xScroll; + SDL_Texture * starfieldTexture; +} SpacewarMenuscreen; + +SpacewarTitlescreen prepareTitleScreen(SDL_Window * window, SDL_Renderer * renderer, + char * starfieldTexturePath, char * logoTexturePath, + TTF_Font * font, char * text); + +SpacewarMenuscreen prepareMenuscreenFromTitle(SpacewarTitlescreen * titlescreen); + +void drawTitleScreen(SpacewarTitlescreen * titlescreen); + +void drawMenuScreen(SpacewarMenuscreen * menuscreen); + +#endif +// ========================================================= +// | End of Spacewar-Graphics.h, copyright notice follows. | +// ========================================================= + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . diff --git a/source/Spacewar-Messages.h b/source/Spacewar-Messages.h new file mode 100644 index 0000000..0540f84 --- /dev/null +++ b/source/Spacewar-Messages.h @@ -0,0 +1,42 @@ +// ========================================= +// | Spacewar-Messages.h | +// | Copyright (C) 2023, Barra Ó Catháin | +// | See end of file for copyright notice. | +// ========================================= +#ifndef SPACEWAR_MESSAGES +#define SPACEWAR_MESSAGES + +#include + +const char * messageStrings[] = {"HELLO", "GOODBYE", "PING", "PONG"}; + +struct SpacewarMessage +{ + uint8_t type; + uint8_t content; +}; + +/* Message Types: + 0 - HELLO: Contents sent to client indicate a given player number. + 1 - GOODBYE: No contents, end the connection. + 2 - PING: Contents indicate the missed amount of pongs. + 3 - PONG: No contents. +*/ + +#endif +// ========================================================= +// | End of Spacewar-Messages.h, copyright notice follows. | +// ========================================================= + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . diff --git a/source/Spacewar-Physics.h b/source/Spacewar-Physics.h new file mode 100644 index 0000000..4e0aac3 --- /dev/null +++ b/source/Spacewar-Physics.h @@ -0,0 +1,54 @@ +// ========================================= +// | Spacewar-Physics.h | +// | Copyright (C) 2023, Barra Ó Catháin | +// | See end of file for copyright notice. | +// ========================================= +#ifndef SPACEWAR_PHYSICS +#define SPACEWAR_PHYSICS + +#include +#include "xyVector.h" + +typedef struct SpacewarShipState +{ + bool inPlay; + xyVector engine; + xyVector gravity; + xyVector position; + xyVector velocity; +} SpacewarShipState; + +typedef struct SpacewarClientInput +{ + double turningAmount, acceleratingAmount; + bool turningClockwise, turningAnticlockwise, accelerating; +} SpacewarClientInput; + +typedef struct SpacewarState +{ + uint64_t tickNumber; + struct timeval timestamp; + SpacewarShipState playerStates[32]; + SpacewarClientInput playerInputs[32]; +} SpacewarState; + +// Does a single step of the physics: +void doPhysicsTick(SpacewarState * state); + +#endif +// ======================================================== +// | End of Spacewar-Physics.h, copyright notice follows. | +// ======================================================== + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . diff --git a/source/Spacewar-Server.c b/source/Spacewar-Server.c new file mode 100644 index 0000000..f05a4a0 --- /dev/null +++ b/source/Spacewar-Server.c @@ -0,0 +1,138 @@ +// ========================================= +// | Spacewar Server.c | +// | Copyright (C) 2023, Barra Ó Catháin | +// | See end of file for copyright notice. | +// ========================================= +#include + +void * runServerPhysics(void * parameters) +{ + struct SpacewarState * state = (struct SpacewarState *)parameters; + + while (true) + { + doPhysicsTick(state); + usleep(15625); + } +} + +// Creates a Spacewar server, intended to be ran by the standalone server or forked by the game client: +int runSpacewarServer(uint16_t port) +{ + // Initialize a simulation: + struct SpacewarState * currentState = calloc(1, sizeof(struct SpacewarState)); + + // Create our network listeners: + int masterSocket = socket(AF_INET, SOCK_STREAM, 0); + int masterListeningSocket = socket(AF_INET, SOCK_DGRAM, 0); + int masterSendingSocket = socket(AF_INET, SOCK_DGRAM, 0); + + if (masterListeningSocket < 0 || masterSendingSocket < 0 || masterSocket < 0) + { + fprintf(stderr, "Failed to create socket.\n"); + exit(EXIT_FAILURE); + } + + // Make the socket timeout: + struct timeval readTimeout; + readTimeout.tv_sec = 0; + readTimeout.tv_usec = 800; + setsockopt(masterListeningSocket, SOL_SOCKET, SO_RCVTIMEO, &readTimeout, sizeof(readTimeout)); + + // Create a structure to store the address we're sending to: + struct sockaddr_in sendingAddress; + sendingAddress.sin_family = AF_INET; // IPv4 + sendingAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); + sendingAddress.sin_port = htons(12000); + + // Create a structure to bind the listening socket: + struct sockaddr_in listeningAddress; + memset(&listeningAddress, 0, sizeof(listeningAddress)); + listeningAddress.sin_family = AF_INET; // IPv4 + listeningAddress.sin_addr.s_addr = INADDR_ANY; + listeningAddress.sin_port = port; + + // Bind to the listening socket: + if (bind(masterSocket, (const struct sockaddr *)&masterListeningAddress, sizeof(listeningAddress)) < 0) + { + fprintf(stderr, "Failed to bind socket.\n"); + exit(EXIT_FAILURE); + } + if (bind(masterListeningSocket, (const struct sockaddr *)&masterListeningAddress, sizeof(listeningAddress)) < 0) + { + fprintf(stderr, "Failed to bind socket.\n"); + exit(EXIT_FAILURE); + } + + // Begin the simulation: + pthread_t physicsThread; + pthread_create(&physicsThread, NULL, runServerPhysics, currentState); + + // Begin listening on the master socket: + listen(masterSocket, 32); + + // Create an epoll descriptor to keep track of clients: + int epollDescriptor = epoll_create1(); + + // Add the master socket to the epoll set: + struct epoll_event requestedEvents; + requestedEvents.events = EPOLLIN; + requestedEvents.data.fd = masterSocket; + epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, masterSocket, &requestedEvents); + + int recievedEventCount = 0; + struct epoll_event receivedEvents[32]; + + // Manage clients and sending packets back and forth: + while (true) + { + receivedEventCount = epoll_wait(epollDescriptor, receivedEvents, 32, -1); + + for (int eventIndex = 0; eventIndex < receivedEventCount, eventIndex++) + { + // If there's activity on the master socket, there's a new connection: + if (receivedEvents[eventIndex].data.fd == masterSocket) + { + struct sockaddr_in clientAddress; + int newClientSocket = accept(masterSocket, (struct sockaddr *)&clientAddress, + sizeof(struct sockaddr_in)); + + // Check that the socket is functional: + if (newClientSocket < 0) + { + fprintf(stderr, "Failed to accept client connection.\n"); + continue; + } + + // Register the new client in the epoll set: + requestedEvents.events = EPOLLIN; + requestedEvents.data.fd = newClientSocket; + epoll_ctl(epollDescriptor, EPOLL_CTL_ADD, newClientSocket, &requestedEvents); + + + } + // Otherwise, we've been sent a packet from one of the connected clients: + else + { + + } + } + } +} + +// ======================================================= +// | End of Spacewar-Server.c, copyright notice follows. | +// ======================================================= + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . diff --git a/source/Spacewar-Server.h b/source/Spacewar-Server.h new file mode 100644 index 0000000..29ad545 --- /dev/null +++ b/source/Spacewar-Server.h @@ -0,0 +1,36 @@ +// ========================================= +// | Spacewar-Server.h | +// | Copyright (C) 2023, Barra Ó Catháin | +// | See end of file for copyright notice. | +// ========================================= +#ifndef SPACEWAR_SERVER +#define SPACEWAR_SERVER + +typedef struct SpacewarConnection +{ + uint8_t missedPongs; + int clientSocket; + int playerNumber; + struct sockaddr_in clientAddress; +} SpacewarConnection; + +// Creates a spacewar server, intended to be ran by the standalone server or forked by the game client: +int runSpacewarServer(uint16_t port); + +#endif +// ======================================================= +// | End of Spacewar-Server.h, copyright notice follows. | +// ======================================================= + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . diff --git a/source/xyVector.h b/source/xyVector.h new file mode 100644 index 0000000..ad32290 --- /dev/null +++ b/source/xyVector.h @@ -0,0 +1,68 @@ +#ifndef XYVECTOR_H +#define XYVECTOR_H +#include + +// A 2D vector: +typedef struct xyVector +{ + double xComponent; + double yComponent; +} xyVector; + +static inline double angleBetweenVectors(xyVector * vectorA, xyVector * vectorB) +{ + double dotProduct = (vectorA->xComponent * vectorB->xComponent) + (vectorA->yComponent * vectorB->yComponent); + double determinant = (vectorA->xComponent * vectorB->yComponent) - (vectorA->yComponent * vectorB->xComponent); + + return atan2(dotProduct, determinant) / 0.01745329; +} + +// Calculate the vector from point A to point B: +static inline void xyVectorBetweenPoints(long ax, long ay, long bx, long by, xyVector * vector) +{ + vector->xComponent = bx - ax; + vector->yComponent = by - ay; +} + +// Normalize a vector, returning the magnitude: +static inline double normalizeXYVector(xyVector * vector) +{ + double magnitude = sqrt(pow(vector->xComponent, 2) + pow(vector->yComponent, 2)); + if(magnitude != 0) + { + vector->xComponent /= magnitude; + vector->yComponent /= magnitude; + } + return magnitude; +} + +// Rotate XY vector by a given number of degrees: +static inline void rotateXYVector(xyVector * vector, double degrees) +{ + double xComponent = vector->xComponent, yComponent = vector->yComponent; + vector->xComponent = (cos(degrees * 0.01745329) * xComponent) - (sin(degrees * 0.01745329) * yComponent); + vector->yComponent = (sin(degrees * 0.01745329) * xComponent) + (cos(degrees * 0.01745329) * yComponent); +} + +// Add vector B to vector A: +static inline void addXYVector(xyVector * vectorA, xyVector * vectorB) +{ + vectorA->xComponent += vectorB->xComponent; + vectorA->yComponent += vectorB->yComponent; +} + +// Add vector B to vector A, scaled for units per frame: +static inline void addXYVectorDeltaScaled(xyVector * vectorA, xyVector * vectorB, double deltaTime) +{ + vectorA->xComponent += vectorB->xComponent * (0.001 * deltaTime) * 60; + vectorA->yComponent += vectorB->yComponent * (0.001 * deltaTime) * 60; +} + +// Multiply a vector by a scalar constant: +static inline void multiplyXYVector(xyVector * vector, double scalar) +{ + vector->xComponent *= scalar; + vector->yComponent *= scalar; +} + +#endif