diff --git a/source/Spacewar-Client b/source/Spacewar-Client new file mode 100755 index 0000000..19b37ac Binary files /dev/null and b/source/Spacewar-Client differ 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