diff --git a/src/colour.h b/src/colour.h deleted file mode 100644 index 756bec9..0000000 --- a/src/colour.h +++ /dev/null @@ -1,9 +0,0 @@ -typedef union { - unsigned packed; - struct { - unsigned char a; - unsigned char b; - unsigned char g; - unsigned char r; - }; -} Colour; diff --git a/src/error_codes.h b/src/error_codes.h deleted file mode 100644 index 26a7ad2..0000000 --- a/src/error_codes.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -enum { - SUCCESS = 0, - FAILURE = -1, - - FAILURE_STD = 1 << 0, // 1 : marks a generic C library error - FAILURE_MEMORY = FAILURE_STD | (1 << 1), // 3 : marks a memory related error - - // SDL ERRORS - FAILURE_SDL = 1 << 1, // 2 : marks a generic SDL error - FAILURE_SDL_INIT = FAILURE_SDL | (1 << 2), // 6 : marks an error during SDL initialisation - FAILURE_SDL_WINDOW = FAILURE_SDL | (1 << 3), // 10 : marks an error with the window - FAILURE_SDL_RENDERER = FAILURE_SDL | (1 << 4), // 18 : marks an error with the renderer - - // GAME ERRORS - FAILURE_GAME = 1 << 2, // 4 : marks a generic game error -}; \ No newline at end of file diff --git a/src/level.c b/src/level.c deleted file mode 100644 index 6db0b3b..0000000 --- a/src/level.c +++ /dev/null @@ -1,162 +0,0 @@ -#include "level.h" - -#include -#include -#include "vector2.h" -#include "constants.h" -#include "renderer.h" - -//prepares the level to be in a playable state -void level_init(Level* level) { - level->stop = false; - - // initialize bouncer - level->bouncer.pos.x = (SCREEN_WIDTH / 2) - (BOUNCER_WIDTH_DEFAULT / 2); - level->bouncer.pos.y = SCREEN_HEIGHT - (BOUNCER_HEIGHT * 2); - level->bouncer.width = BOUNCER_WIDTH_DEFAULT; - - // initialize ball - level->ball.pos.x = (SCREEN_WIDTH / 2) - (BALL_SIZE_DEFAULT / 2); - level->ball.pos.y = level->bouncer.pos.y - BOUNCER_HEIGHT - BALL_SIZE_DEFAULT; - level->ball.size = BALL_SIZE_DEFAULT; - level->ball.direction = (Vector2){ 0, -BALL_SPEED }; - - // initialize bricks - // define the colours of the brick rows - const Colour colours[BRICK_COLUMNS] = { - {0x5BCEFAFF}, - {0xF5A9B8FF}, - {0xFFFFFFFF}, - {0xF5A9B8FF}, - {0x5BCEFAFF} - }; - - int brick_width = BRICK_WIDTH + BRICK_PADDING; - int brick_height = BRICK_HEIGHT + (BRICK_PADDING / 2); - float level_padding_left = ((float)SCREEN_WIDTH - ((SCREEN_WIDTH / brick_width) * brick_width)) / 2.0F; //for centering - - // store bricks in the level - for (int x = 0; x < BRICK_COLUMNS; x++) { - for (int y = 0; y < BRICK_ROWS; y++) { - Brick* brick = &level->bricks[x][y]; - brick->colour = colours[y]; - brick->pos.x = (x * brick_width) + level_padding_left; - brick->pos.y = (y * brick_height) + BRICK_PADDING_TOP; - brick->destroyed = false; - } - } -} - -// updates the player's "bouncer" -static void update_player(Bouncer* bouncer, Ball* ball, const Uint8* keys) { - // if move bouncer LEFT - if (keys[SDL_SCANCODE_A] || keys[SDL_SCANCODE_LEFT]) { - if (((bouncer->pos.x) < 0) == false) { - bouncer->pos.x -= BOUNCER_SPEED; - - if (ball->moving == false) - ball->pos.x -= BOUNCER_SPEED; - } - } - - // if move bouncer RIGHT - if (keys[SDL_SCANCODE_D] || keys[SDL_SCANCODE_RIGHT]) { - if (((bouncer->pos.x + bouncer->width) > SCREEN_WIDTH) == false) { - bouncer->pos.x += BOUNCER_SPEED; // increase the bouncer pos - - if (ball->moving == false) - ball->pos.x += BOUNCER_SPEED; - } - } - - // ball launching - if (ball->moving == false && keys[SDL_SCANCODE_SPACE]) { - ball->moving = true; - } -} - -// updates the player's ball -static void update_ball(Level* level, Ball* ball, Bouncer* bouncer) { - // update ball position - ball->pos.x += ball->direction.x; - ball->pos.y += ball->direction.y; - - - // check X axis out of bounds collisions - if ((ball->pos.x + ball->size) > SCREEN_WIDTH || ball->pos.x < 0) { - ball->direction.x *= -1; - } - - // check Y axis out of bounds collisions - if (ball->pos.y < 0) { - ball->direction.y *= -1; - } - - - // check bouncer collisions - if ((ball->pos.x + ball->size) > bouncer->pos.x && ball->pos.x < (bouncer->pos.x + bouncer->width) && - (ball->pos.y + ball->size) > bouncer->pos.y && ball->pos.y < (bouncer->pos.y + BOUNCER_HEIGHT)) { - float x = ball->pos.x - bouncer->pos.x + (ball->size / 2) + 2; // get the X axis relative to the bouncer (add 2, see below) - unsigned max = bouncer->width + 4; // get the maxiumum of this X axis (add 4 to make it feel more accurate) - float angle = (x - (max / 2.0F)) / max * (PI / 1.5F); // calculate the angle in radians where the bouncer X axis falls on -60° to 60° - - // change the ball direction - ball->direction.x = SDL_sinf(angle) * BALL_SPEED; - ball->direction.y = -SDL_cosf(angle) * BALL_SPEED; - } - - // check brick collisions - bool collided = false; - for (int x = 0; x < BRICK_COLUMNS; x++) { - for (int y = 0; y < BRICK_ROWS; y++) { - const Brick* brick = &level->bricks[x][y]; - - if (brick->destroyed == true) { - continue; - } - - const float max_brick_x = brick->pos.x + BRICK_WIDTH; - const float brick_max_y = brick->pos.y + BRICK_HEIGHT; - if (ball->pos.x < max_brick_x && (ball->pos.x + ball->size) > brick->pos.x && - ball->pos.y < brick_max_y && (ball->pos.y + ball->size) > brick->pos.y) { - level->bricks[x][y].destroyed = true; - - // skip changing direction of we already did - if (collided == true) { - continue; - } - - //float ball_centre_x = ball->pos.x + (ball->size / 2.0F); - float ball_centre_y = ball->pos.y + (ball->size / 2.0F); - - // manage ball bounce direction; only bounce along the X axis if the ball's Y centre is in between dthe top and bottom of the block - if (brick->pos.y < ball_centre_y && ball_centre_y < brick_max_y) { - ball->direction.x *= -1; - } - else { - ball->direction.y *= -1; - } - - collided = true; - } - } - } -} - -//updates the level -void level_update(Level* level, const Uint8* keys) { - Bouncer* bouncer = &level->bouncer; - Ball* ball = &level->ball; - - update_player(bouncer, ball, keys); - - if (ball->moving == true) - update_ball(level, ball, bouncer); - - - // check lose condition - if ((ball->pos.y + ball->size) > SCREEN_HEIGHT) { - level->stop = true; - ball->moving = false; - } -} diff --git a/src/level.h b/src/level.h deleted file mode 100644 index 2953b64..0000000 --- a/src/level.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include -#include -#include "vector2.h" -#include "constants.h" -#include "colour.h" - -typedef struct { - Vector2 pos; - Vector2 direction; - unsigned size; - bool moving; -} Ball; - -typedef struct { - Vector2 pos; - unsigned width; -} Bouncer; - -typedef struct { - Vector2 pos; - Colour colour; - bool destroyed; -} Brick; - -typedef struct { - bool stop; - Ball ball; - Bouncer bouncer; - Brick bricks[BRICK_COLUMNS][BRICK_ROWS]; -} Level; - - -void level_init(Level* level); -void level_update(Level* level, const Uint8* keys); diff --git a/src/main.c b/src/main.c index 7f85c45..59d8280 100644 --- a/src/main.c +++ b/src/main.c @@ -1,105 +1,93 @@ -#include -#include -#include -#include -#include "error_codes.h" -#include "renderer.h" -#include "level.h" - -#ifdef __EMSCRIPTEN__ -#include -#endif - -#define UPDATES_PER_SEC 50 -#define CLOCKS_PER_UPDATE (CLOCKS_PER_SEC / UPDATES_PER_SEC) -#define CLOCKS_PER_UPDATE_F (((float)CLOCKS_PER_SEC) / UPDATES_PER_SEC) - -Level level = { 0 }; // stores the game's state -SDL_Window* window = NULL; // the window that is given to the OS -SDL_Renderer* renderer = NULL; // the renderer used to draw to the window - -// initializes the game -static int init(void) { - level_init(&level); - return renderer_init(&window, &renderer); -} - - -// called on each game update -static bool update(void) { - const clock_t clock_start = clock(); - - //update the event keys - { - SDL_Event e; - while (SDL_PollEvent(&e)) { - switch (e.type) { - case SDL_QUIT: - return false; - break; - } - } - } - - RenderData render_data = { window, renderer, &level }; //contains the data which is used to render the game - const Uint8* keys = SDL_GetKeyboardState(NULL); - - // preform updates - { - level_update(&level, keys); //update the level - renderer_update(&render_data); //update the render - } - - const clock_t clock_end = clock(); - - // provide a delay if needed, otherwise log a warning - const clock_t clock_diff = clock_end - clock_start; // difference / how long the operations took - const int remaining_ms = (int)((CLOCKS_PER_UPDATE_F - clock_diff) / CLOCKS_PER_SEC) * 1000; - - if (remaining_ms < 0) { - (void)printf("delay between updates was %dms too long.", -remaining_ms); - } - else { - SDL_Delay(remaining_ms); // wait the time in ms - } - - return true; -} - -#ifdef __EMSCRIPTEN__ -static void update_game(void) { - // stop updating if update returns false - if (update() == false) { - emscripten_cancel_main_loop(); - } -} -#endif - -// cleans up resources -static void close(SDL_Window* window, SDL_Renderer* renderer) { - renderer_destroy(window, renderer); -} - -// entry-point of the application -int main(int argc, char *argv[]) { - // initialize - { - const int code = init(); - if (code != SUCCESS) - exit(code); - } - - // TEMP: tell me that the program has been initialized - (void)printf("initialized!\n"); - -#ifdef __EMSCRIPTEN__ - emscripten_set_main_loop(update_game, 0, 1); // don't utilise setting the FPS, as we already do this -#else - while (update() && (level.stop == false)); -#endif - - // frees media and shuts down SDL - close(window, renderer); - (void)printf("finished!\n"); - return 0; -} \ No newline at end of file +#include "main.h" + +#include +#include +#include +#include + +#include "errors.h" +#include "game/level.h" +#include "window/audio.h" +#include "window/renderer.h" + +#ifdef __EMSCRIPTEN__ // for web builds +#include +#endif + + +bool playing = true; + +SDL_Window* window = NULL; +SDL_Renderer* renderer = NULL; +Level* level = NULL; + +// handles game application initialisation +static void init(void) { + // initialize SDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { + error(FAILURE_SDL_INIT, "SDL could not initialize! SDL Error: %s", SDL_GetError()); + return; + } + + // initialize the renderer + if (renderer_init(&window, &renderer) < 0) { + error(FAILURE_SDL_RENDERER, SDL_GetError()); + return; + } + + // initialize level + level = malloc(sizeof(Level)); + level_init(level); + + // initialize audio + level->audio_device = audio_device_init(32000, AUDIO_S16, 1, 4096); + level->bounce_sfx = audio_load_wav(level->audio_device, "./assets/bounce.wav"); +} + +// handles game application updating +static void update(void) { + // update the input + { + SDL_Event e; + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: + exit(SUCCESS); + break; + } + } + } + + // preform updates + level_update(level, SDL_GetKeyboardState(NULL)); + renderer_update(&(RenderData){window, renderer, level}); +} + +// handles game application quitting +void stop(void) { + playing = false; + +#if __EMSCRIPTEN__ + emscripten_cancel_main_loop(); +#endif +} + +// entry point of the application +int main(int argc, char** argv) { + init(); + +#if __EMSCRIPTEN__ + emscripten_set_main_loop(update, 0, 1); +#else + while (playing) + update(); +#endif + + // cleanup of resources + SDL_FreeWAV(level->bounce_sfx.buffer); + SDL_CloseAudioDevice(level->audio_device->id); + free(level); + SDL_Quit(); + + return 0; +} diff --git a/src/renderer.c b/src/renderer.c deleted file mode 100644 index 0f3d5f5..0000000 --- a/src/renderer.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "renderer.h" - -#include -#include -#include "error_codes.h" -#include "level.h" -#include "constants.h" - -// initializes the window and renderer -int renderer_init(SDL_Window** window, SDL_Renderer** renderer) { - // initialize SDL - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - (void)printf("SDL Failed to initialize! SDL_Error: %s\n", SDL_GetError()); - return FAILURE_SDL_INIT; - } - - // init the window - *window = SDL_CreateWindow("Quinn's Breakout Clone", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); - if (*window == NULL) { - (void)printf("Window failed to be created! SDL_Error: %s\n", SDL_GetError()); - return FAILURE_SDL_WINDOW; - } - - // create a renderer - *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_PRESENTVSYNC); - - if (*renderer == NULL) { - (void)printf("Renderer failed to be created! SDL_Error: %s\n", SDL_GetError()); - return FAILURE_SDL_RENDERER; - } - - return SUCCESS; -} - -// renders the screen -void renderer_update(RenderData* render_data) { - SDL_Renderer* renderer = render_data->renderer; - Level* level = render_data->level; - - int success = 0; // if an error occurs, this value is <0 - - // render background - success |= SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); - success |= SDL_RenderClear(renderer); - - // draw player components - success |= SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); - success |= SDL_RenderFillRectF(renderer, &(SDL_FRect) {level->bouncer.pos.x, level->bouncer.pos.y, level->bouncer.width, 5}); // draw bouncer - success |= SDL_RenderFillRectF(renderer, &(SDL_FRect) {level->ball.pos.x, level->ball.pos.y, level->ball.size, level->ball.size}); // draw ball - - // draw bricks - for (int x = 0; x < BRICK_COLUMNS; x++) { - for (int y = 0; y < BRICK_ROWS; y++) { - Brick* brick = &level->bricks[x][y]; - - if (brick->destroyed == true) { - continue; - } - - success |= SDL_SetRenderDrawColor(renderer, brick->colour.r, brick->colour.g, brick->colour.b, brick->colour.a); - success |= SDL_RenderFillRectF(renderer, &(SDL_FRect) {brick->pos.x, brick->pos.y, BRICK_WIDTH, BRICK_HEIGHT}); // draw brick - } - } - - if (success < 0) { - printf("something went wrong whilst rendering: %s\n", SDL_GetError()); - exit(FAILURE_SDL_RENDERER); - } - - // present the result to the renderer - SDL_RenderPresent(renderer); -} - -void renderer_destroy(SDL_Window* window, SDL_Renderer* renderer) { - SDL_DestroyWindow(window); - SDL_DestroyRenderer(renderer); - SDL_Quit(); -} \ No newline at end of file diff --git a/src/renderer.h b/src/renderer.h deleted file mode 100644 index 8adbc19..0000000 --- a/src/renderer.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include "level.h" - -typedef struct { - SDL_Window* window; - SDL_Renderer* renderer; - Level* level; -} RenderData; - -int renderer_init(SDL_Window** window, SDL_Renderer** renderer); -void renderer_update(RenderData* render_data); -void renderer_destroy(SDL_Window* window, SDL_Renderer* renderer); diff --git a/src/vector2.h b/src/vector2.h deleted file mode 100644 index 39f68bc..0000000 --- a/src/vector2.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#define VECTOR2_UP ((Vector2){ 0, 1 }) -#define VECTOR2_DOWN ((Vector2){ 0, -1 }) -#define VECTOR2_LEFT ((Vector2){ -1, 0 }) -#define VECTOR2_RIGHT ((Vector2){ 1, 0 }) -#define VECTOR2_ZERO ((Vector2){ 0, 0 }) -#define VECTOR2_ONE ((Vector2){ 1, 1 }) - -#define vec2_add(v1, v2) ((Vector2){v1.x + v2.x, v1.y + v2.y}) -#define vec2_subt(v1, v2) ((Vector2){v1.x - v2.x, v1.y - v2.y}) -#define vec2_mult(v, a) ((Vector2){v.x * a, v.y * a}) -#define vec2_div(v, a) ((Vector2){v.x / a, v.y / a}) - -typedef struct { - float x; - float y; -} Vector2;