From dc7f5989f757d596100c3f34724f8908351a66d0 Mon Sep 17 00:00:00 2001 From: alistair Date: Fri, 28 Jan 2022 16:56:38 +1000 Subject: [PATCH] code cleanup --- src/audio.c | 27 ++-- src/c-colours | 1 + src/controlscheme.c | 10 ++ src/datastructures | 1 + src/draw.c | 107 ---------------- src/environment.c | 39 +++--- src/game.c | 300 ++++++++++++++++++++++++++++---------------- src/main.c | 15 +-- src/types.h | 10 +- 9 files changed, 254 insertions(+), 256 deletions(-) create mode 120000 src/c-colours create mode 120000 src/datastructures diff --git a/src/audio.c b/src/audio.c index 7be6387..0609261 100644 --- a/src/audio.c +++ b/src/audio.c @@ -9,6 +9,19 @@ struct game_sounds game_sounds; Uint8 big_hum(unsigned int t); Uint8 func0(unsigned int t); + +/** + * ---------------------------------------------------------------------------- + * Audio + * ---------------------------------------------------------------------------- + * + * Sound-effects are generated at startup, and synthesised using 8-bit + * integer overflow a la bytebeat https://arxiv.org/pdf/1112.1368.pdf. + * + * see generate_audio() + * + */ + int mute = false; void fill_audio(void *func, Uint8 *stream, int len) { @@ -30,14 +43,6 @@ void callbackfn3(void *unused, Uint8 *stream, int len) { void start_audio(void) { - //audio_format.callback = callbackfn3; - /* just for playing background music - if (SDL_OpenAudio(&audio_format, NULL)) { - fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); - exit(1); - } - */ - //SDL_PauseAudio(0); if (Mix_OpenAudio(G_AUDIO_SFREQ,AUDIO_U8,1,G_AUDIO_BSIZE) < 0) { fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); exit(1); @@ -71,7 +76,6 @@ pitchshift_hit(unsigned int t, void *arg) hit = 6 - hit; int lower = 10 + 2 * (hit > 6 ? 6 : hit); int higher = 1 + (hit > 6 ? 6 : hit); -// printf("mag %f higher %d lower %d\n", hit, higher, lower); const double R=8000; // sample rate (samples per second) const double C=125; // frequency of middle-C (hertz) @@ -81,8 +85,6 @@ pitchshift_hit(unsigned int t, void *arg) return ((sin(t*2*M_PI/R*(125 + hit))+1)*10 + (sin(t*2*M_PI/R*(250 + hit))+1)*(50 + hit) + (sin(t*2*M_PI/R*(900 + hit))+1)*100 + (sin(t*2*M_PI/R*(150+ hit))+1)*5) ; - return ((t < 3000) * ((t % higher) * (3000 - t % 3000) * 0.00351)); - //+ ((t < 3500) * ((3500 - t % 3500)) * 0.0002 * (t % lower)); } void @@ -196,6 +198,9 @@ Uint8 rope_attach(unsigned int t) { return (((2000 - (t % 2000)))/40 * (t % 20) | (t % 44) + 20) * 1.6; } +/* + * Called by startgame() to initialise sound effects. + */ void generate_audio(void) { const int sfx_len_ms = 1000; unsigned int sfx_len = (G_AUDIO_SFREQ/1000) * G_AUDIO_BSIZE * sfx_len_ms; diff --git a/src/c-colours b/src/c-colours new file mode 120000 index 0000000..e3531de --- /dev/null +++ b/src/c-colours @@ -0,0 +1 @@ +../c-colours \ No newline at end of file diff --git a/src/controlscheme.c b/src/controlscheme.c index f27cde5..d0c3858 100644 --- a/src/controlscheme.c +++ b/src/controlscheme.c @@ -9,6 +9,16 @@ struct InputMap input_map; #define INPUT_MAP_VERSION 0 #define CONTROLS_FNAME "controls.bin" + +/* + * Serialise controlscheme using simple (char *) cast. It is obviously not cross + * platform but it doesnt need to be. Takes a very tentative approach to error + * handling, if something is wrong it resets. + * + * There is no UI for setting controls yet. + * + */ + struct InputMap_Ser { unsigned int id; unsigned int ver; diff --git a/src/datastructures b/src/datastructures new file mode 120000 index 0000000..971126c --- /dev/null +++ b/src/datastructures @@ -0,0 +1 @@ +../datastructures \ No newline at end of file diff --git a/src/draw.c b/src/draw.c index a394b9f..09cd2de 100644 --- a/src/draw.c +++ b/src/draw.c @@ -27,20 +27,6 @@ void render_texture_at(struct SDL_Renderer * ren, struct SDL_Texture * texture,i SDL_RenderCopy(ren, texture, NULL, &destination); } -/*SDL_Texture * load_image(SDL_Renderer * ren, char fname[]) {*/ - /*[> Load an image into a texture <]*/ - - /*SDL_Surface * surface = IMG_Load(fname) ;*/ - /*if(!surface) {*/ - /*printf("IMG_Load: %s\n", IMG_GetError());*/ - /*// handle error*/ - /*}*/ - - /*SDL_Texture * png_image = SDL_CreateTextureFromSurface(ren, surface);*/ - /*cleanup(surface, SURFACE);*/ - /*return (png_image);*/ -/*}*/ - double sigmoid(double x) { return exp(x) / (exp(x) + 1); @@ -321,30 +307,6 @@ void new_update_viewport(Body const * const pl) { if (recover) viewport_pos = target; - // emergency - - /*if (!(iv.x > width / 3 && iv.x < (2 * (width / 3)))) {*/ - /*if (!(iv.y > height / 3 && iv.y < (2 * (height / 3)))) {*/ - - /*if ( true ||*/ - /*( in_view(pl->position).x > xmargin + xrange */ - /*|| in_view(pl->position).x < xmargin)*/ - /*) */ - - /*{*/ - - - /*double m = (width / 2) / (2.0 * x_max);*/ - /*double x = m * v;*/ - /*target.x = pl->position.x - x;*/ - - - /*}*/ - - //target.y = pl->position.y - height/2; // + y; - - /*}*/ - /*}*/ double v = pl->vel.x; if (v > x_max) @@ -452,15 +414,8 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) { struct colour c3 = scene->colours.fg2; struct colour c4 = scene->colours.fg3; - /*c1->r = 255;*/ - /*c2->g = 255;*/ - /*c3->b = 255;*/ - /*c4->g = 255;*/ - /*c4->b = 255;*/ - // background colour SDL_SetRenderDrawColor(ren, c1.r, c1.g, c1.b, 255); - /*SDL_SetRenderDrawColor(ren, 255, 0, 0, 255);*/ SDL_Rect rect; rect.x = 0; @@ -469,20 +424,8 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) { rect.h = height; SDL_RenderFillRect(ren, &rect); -/* - * double m = (double)(right.y - left.y) / (double)(right.x - left.x); - * double c = (double)left.y - ((double)left.x * m); - * - * for (int i = left.x; i <= right.x; i++) { - * int y = (int)(m * i + c); - * if (y > 0) { - * SDL_RenderDrawLine(ren, i, y, i, end); - * } - * } - */ int k = 0; -// printf("from 0 to (room tiles) %d - 1, res %d width %d\n", E_ROOM_TILES, E_ROOM_RES, E_ROOM_WIDTH); for (int i = 0; i < E_ROOM_TILES - 2; i++) { for (int j = 0; j < E_ROOM_RES; j++) { k++; @@ -518,8 +461,6 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) { int y3 = interpolate_h(*left, *right, x) - viewport_pos.y; x = x - viewport_pos.x; - /*printf("x: %d, ", x);*/ - /*printf("y: %d %d %d %d\n", y0, y1, y2, y3);*/ // 3. bg2 to floor SDL_SetRenderDrawColor(ren, c4.r, c4.g, c4.b, 255); @@ -625,7 +566,6 @@ int draw_end_screen(SDL_Renderer *ren) { int margin = height / 10; - // Vect position = {.x = width - width / 10, .y = height - margin}; long fastest = draw_watch.best_time; @@ -654,13 +594,6 @@ int draw_end_screen(SDL_Renderer *ren) { position.y += 40; } - /* - char qual_str[250]; - snprintf(qual_str, 250, "physics quality: %d", quality); - draw_text_default(ren, position, colour, qual_str); - position.y += 40; - */ - minutes = level_time / 60000; seconds = level_time * 0.001; @@ -763,7 +696,6 @@ void draw_pause_screen(SDL_Renderer *ren, struct environment *e) { draw_text_default(ren, p, textc, te[0]); p.y += 60; -// SDL_GetScancodeName(input_map.goto_level); draw_text_default(ren, p, textc, te[1]); p.y += 5; draw_text_default(ren, p, textc, te[2]); @@ -791,7 +723,6 @@ void draw_pause_screen(SDL_Renderer *ren, struct environment *e) { p.y += 40; - //Vect p = {.x = box_x + 10, .y = box_y + 10}; p.x = width / 8; p.y = height / 9; int arlen = sizeof(game_name) / sizeof(game_name[0]); @@ -810,14 +741,6 @@ void redraw_buffer(SDL_Renderer * ren) { static SDL_Point *bgPixels[256]; static int numpixels[256]; - /*if (!width && !height) {*/ - /*for (int i = 0; i < 256; i++) {*/ - /*bgPixels[i] = malloc(sizeof(SDL_Point) * width * height);*/ - /*memset(bgPixels[i], 0, sizeof(SDL_Point) * width * height);*/ - /*memset(numpixels, 0, (sizeof(int) * 256));*/ - /*}*/ - /*}*/ - int col = 0; Body lplayer; @@ -836,8 +759,6 @@ void redraw_buffer(SDL_Renderer * ren) { last = now; - //SDL_GetMouseState(&newmousex, &newmousey); - const struct environment* scene = get_scene_watch(); draw_environment(ren, scene); if (!game_paused) @@ -899,33 +820,5 @@ void redraw_buffer(SDL_Renderer * ren) { draw_text(ren, LARGE, pos, scene->colours.fg1, "Press a Key to Continue"); } - /*if (newmousex != mousex || newmousey != mousey) {*/ /*mousey = newmousey;*/ - /*mousex = newmousex;*/ - /*for (int i = 0; i < 256; i++) {*/ - /*memset(bgPixels[i], 0, sizeof(SDL_Point) * width * height);*/ - /*memset(numpixels, 0, (sizeof(int) * 256));*/ - /*}*/ - /*for (int i=0; i < width; i++) {*/ - /*for (int j = 0; j < height; j++) {*/ - /*col = distance_colour(i, j, mousex, mousey, 10000);*/ - - /*SDL_Point *row = bgPixels[col];*/ - /*SDL_Point point;*/ - /*point.x = i;*/ - /*point.y = j;*/ - /*row[numpixels[col]] = point;*/ - /*numpixels[col] += 1;*/ - - /*}*/ - /*}*/ - /*}*/ - - /*for (int i = 0; i < 255; i++) {*/ - /*SDL_Point *row = bgPixels[i];*/ - /*col = i;*/ - /*SDL_SetRenderDrawColor(ren, col, col, col, 255);*/ - /*SDL_RenderDrawPoints(ren, row, numpixels[i]);*/ - /*}*/ - } diff --git a/src/environment.c b/src/environment.c index 12e491d..b7a74eb 100644 --- a/src/environment.c +++ b/src/environment.c @@ -2,8 +2,28 @@ #include "game.h" #include "types.h" + + struct environment * environment_watch = NULL; + +/* ---------------------------------------------------------------------------- + * Environment / World Generation + * ---------------------------------------------------------------------------- + * + * Worlds have to be shared across threads, since they contain both collision + * bodies and drawing information. Realistically, these should be stored in + * separate datastructures. My solution has been to just store a copy in each + * thread, and lock everything when you move to the next level and need to + * generate a new one. + * + * An 'environment' consists of the cave structure with the collision bodies, + * as well as the colourscheme for drawing it. These are procedurally + * generated. A custom PRNG function is used so the same levels are given on + * every platform. + * + */ + const struct environment* get_scene_watch(void) { return environment_watch; } @@ -13,13 +33,6 @@ double linear_interpolate(double a0, double a1, double w) { } int destroy_environment(struct environment *e) { - /*Vect position;*/ - /*ArrayList ceil; // doubles*/ - /*ArrayList floor; // doubles*/ - /*ArrayList bg1; // doubles*/ - /*ArrayList bg2; // doubles*/ - /*struct colour_pallete colours;*/ - /*struct physics_collection physics;*/ arlst_destroy(&e->ceil); arlst_destroy(&e->floor); @@ -117,6 +130,11 @@ void swap_palletes(struct environment *e) { e->coloursb = b; } +/* + * + * Generate or just return the environment seeded by the current level number. + * + */ struct environment get_scene_at(Vect coordinate, int seed) { // TODO: Environment needs to be shared between threads // - this implementation duplicates it: each thread that calls @@ -178,10 +196,7 @@ struct environment get_scene_at(Vect coordinate, int seed) { int r[4] = {r1, r2, r3, r4}; qsort(r, 4, sizeof(int), comp); - // r[0] == ceiling - // r[3] == floor - //node.y += r[0]; int h[4] = {node.y,node.y,node.y,node.y}; h[0] += r[0]; h[1] = h[0] + r[1]; @@ -189,7 +204,6 @@ struct environment get_scene_at(Vect coordinate, int seed) { h[3] += h[0] + r[3]; qsort(h, 4, sizeof(int), comp); -// node.y = fmod(perlin(bit), 3000); Vect *z = malloc(sizeof(Vect)); *z = node; z->y = h[0]; @@ -198,20 +212,17 @@ struct environment get_scene_at(Vect coordinate, int seed) { z = malloc(sizeof(Vect)); *z = node; -// z->y += r[1]; z->y = h[1]; arlst_add(&e.bg1, z); z = malloc(sizeof(Vect)); *z = node; - //z->y += r[2]; z->y = h[2]; arlst_add(&e.bg2, z); z = malloc(sizeof(Vect)); *z = node; -// z->y += r[3]; z->y = h[3]; arlst_add(&e.ceil, z); diff --git a/src/game.c b/src/game.c index ea9ff66..aa90971 100644 --- a/src/game.c +++ b/src/game.c @@ -1,14 +1,16 @@ -#include "game.h" -#include "draw.h" -#include "audio.h" -#include "environment.h" -#include "types.h" #include #include #include #include #include +#include "game.h" +#include "draw.h" +#include "audio.h" +#include "environment.h" +#include "types.h" + + #define FLOOR_THICKNESS 200 #define MAX_ROPE_GRAB_LEN 80000 #define MIN_PHYSICS_STEP 6.0 @@ -23,6 +25,22 @@ player_st *glob_player; SDL_Renderer *debug_ren; +/* + * + * File containing main game logic, including physics, input handling, + * and user interface. + * + * If multithreading is in use everything in this file will be run in the + * physics thread and communicate with the drawing thread (the main thread) + * using shared heap memory. + * + * At the start of a frame the shared memory is locked + * and copied. + * + * + */ + + bool in_game; bool game_paused = false; extern bool mute; @@ -44,9 +62,6 @@ struct ui_state gameui = {}; struct timespec last_tick; double time_remaining = 0; -/* array of all the things in the world and their kinds */ -//world_thing *world; - void startgame(SDL_Renderer * ren) ; void process_keydown(SDL_Keysym key); @@ -67,6 +82,12 @@ void ratcheted_winch_motor_update(Motor* motor); void winch_motor_update (struct motorstruct *motor); void load_level(); + +/* ----------------------------------------------------------------------------- + * User interface + * ----------------------------------------------------------------------------- + */ + void reset_textbox(struct textbox_info *tb) { tb->text_input_bufpos = 0; memset(tb->text_input, 0, sizeof(tb->text_input)); @@ -111,6 +132,15 @@ void new_level_tb_close_callback(struct textbox_info*textbox, void*callback) { } +/* ----------------------------------------------------------------------------- + * Scoring + * ----------------------------------------------------------------------------- + */ + + +/* + * Update the level timer each frame. + */ void level_timer_update(bool reset) { static int start_point = 0; long now = SDL_GetTicks(); @@ -137,6 +167,9 @@ int win_long_comparator(void *context_unused, const void *a, const void *b) { return A - B; } +/* + * Sort the 'highscores' + */ void sort_times(void) { #ifdef __linux__ qsort_r(save_times_lst.times, save_times_lst.size, sizeof(long), long_comparator, NULL); @@ -153,6 +186,12 @@ long get_best_time(void) { } +/* + * Read and parse highschores list from disk. + * + * Will panic if the folder does not exist. + * + */ int load_score_times(char *filename) { char *fn; @@ -218,6 +257,11 @@ int load_score_times(char *filename) { return 0; } +/* + * + * Dynamically add a recorded run time to the list of saved times. + * + */ int add_time(long time) { if (save_times_lst.capacity == save_times_lst.size + 5) { long newcap = save_times_lst.capacity * 2; @@ -230,6 +274,9 @@ int add_time(long time) { return 0; } +/* + * Write out the saved times list. + */ int write_times(void) { FILE *f = fopen(save_times_lst.filename, "w"); if (!f) { @@ -244,9 +291,38 @@ int write_times(void) { } +/* ---------------------------------------------------------------------------- + * Physics + * ---------------------------------------------------------------------------- + * + * Simple point-mass based physics system. Physics objects are called `Body`s. + * + * Position is calculated by integrating acceleration and velocity, using a + * fixed timestep that is detached from the framerate. Each frame it completes + * as many physics steps as neccessary to catch up to the current time. + * + * Player interactions use forces generated by the 'motor' + * datastructures and functions. Motors can apply a force at a given 'rate': + * they accelerate a body to a maximum velocity and do nothing over that + * velocity. It is posisble to update their output at each physics step. + * + * The grappling hook is controlled by 'string' functions and datastructures, + * which have a parent object (the player) an attachment endpoint position, and + * a motor. Strings can be updated each physics step. + * + * All collisions use convex polygons and the separating axis theorem test. + * They are culled by x-coordinate based on the viewport position, since the + * world is mostly horizontal. + * + */ + -// collision poly size must be 2x shape_size + 1 +/* + * Update an objects collision poly based on its current position smeared over + * its velocity. + */ void cast_update_collision_poly(Body *body) { + // collision poly size must be 2x shape_size + 1 for (int i=0; i < body->collision_shape_size; i++) { double x = body->collision_shape[i].x + body->position.x; double y = body->collision_shape[i].y + body->position.y; @@ -263,29 +339,31 @@ void cast_update_collision_poly(Body *body) { body->collision_poly[k].y = y; } - /*int i=body->collision_shape_size - 1;*/ - /*double x = body->collision_shape[i].x + body->next_position.x;*/ - /*double y = body->collision_shape[i].y + body->next_position.y;*/ - - /*body->collision_poly[body->collision_shape_size - 1 + i].x = x; */ - /*body->collision_poly[body->collision_shape_size - 1 + i].y = y; */ - - - /*body->collision_poly[(body->collision_poly_size - 1) * 2 + 1] = body->collision_poly[(body->collision_poly_size - 1) * 2 + 1];*/ - /*body->collision_poly[(body->collision_poly_size - 1) * 2 + 2] = body->collision_poly[(body->collision_poly_size - 1)];*/ } +/* + * Constant motor velocity curve. + */ void default_motor_curve(Motor *motor) { // constant return; } +/* + * Get the i'th world item. + */ world_thing world_getter(int i) { world_thing *item = arlst_get(&world.items, i); return *item; } +/** + * Random walk to generate the floor based on compiled constant parameters. + * + * \param extend_down: do the polys extend down or up: true => floor, false => ceiling + * + */ FloorPoly* generate_floor_simple(int num_polys, bool extend_down, int st_height) { FloorPoly *floor = calloc(num_polys, sizeof(FloorPoly)); Vect last, next; @@ -333,8 +411,13 @@ FloorPoly* generate_floor_simple(int num_polys, bool extend_down, int st_height) return floor; } -// @param uninitialised Body pointer -// @result: malloc and configure a physics thing pointer +/** + * Get an empty valid physics object. + * + * \param uninitialised Body pointer + * \result: malloc and configure a physics thing pointer + * + */ void get_new_physics(Body **phys) { static int uid = 0; @@ -369,16 +452,19 @@ void get_new_physics(Body **phys) { return; } -/*void updatePlayerCollision(Body *physics) {*/ - /*physics->collision_poly[0].x = physics->x_pos;*/ - /*physics->collision_poly[0].y = physics->y_pos;*/ -/*}*/ - +/* + * noop for static strings. + * + */ int string_update_fixed(String *string) { return 0; } +/* + * Attach the end point of s string to a position in the world. + * + */ int string_set_end(String *string, Vect *setting) { string->end_point = *setting; return 0; @@ -399,8 +485,11 @@ String *get_fixed_strings(int number) { return strings; } +/* + * Create a player object with allocated and zeroed physics at the given + * position in the world. + */ player_st get_player(int x, int y) { - /* creates player at given postion and zeroes physics */ // player player_st player; @@ -459,6 +548,9 @@ player_st get_player(int x, int y) { return (player); } +/* + * Collision test for two points. + */ bool point_point_colcheck(Vect one, Vect two) { if (one.x == two.x && one.y == two.y) { return true; @@ -471,6 +563,9 @@ typedef struct { Vect two; } Collision; +/* + * Collision test for a point and line. + */ bool point_line_colcheck(Vect line[2], Vect point) { // point is outside the rectangle made by the line if ((point.x > line[0].x && point.x > line[1].x) @@ -494,15 +589,17 @@ bool point_line_colcheck(Vect line[2], Vect point) { return false; } +/* + * Projects a body's collision polygon at the origin onto the line through the + * origin described by V. + * + */ double *project_col_poly(Body *shape, Vect V) { double *proj = calloc(shape->collision_poly_size, sizeof(double)); for (int i = 0; i < shape->collision_poly_size; i++) { Vect point; point.x = shape->collision_poly[i].x; point.y = shape->collision_poly[i].y; - //double mag = vect_mag(point); -// printf("point: %f %f mag: %f\n", point.x, point.y, vect_mag(point)); -// printf("Vectp: %f %f mag: %f\n", V.x, V.y, vect_mag(V)); proj[i] = vect_scalar_projection(point, V); } double min, max; @@ -524,6 +621,9 @@ double *project_col_poly(Body *shape, Vect V) { return res; } +/* + * Get the normal of the line described by the start and end points. + */ Vect get_normal(Vect start, Vect end) { Vect norm; double x = (end.x - start.x); @@ -537,13 +637,35 @@ Vect get_normal(Vect start, Vect end) { return norm; } +/** + * Collision test for two convex polygons. + * + * Uses the separating axis theorem test. + * + * P: IFF two convex polygons are intersecting, there will exist a line running + * between them that intersects neither. + * + * Corrolary: IFF two convex polygons are intersecting, there will be an edge + * of one of them where if you extend it and project both shapes onto it, the + * shapes will overlap. + * + * Corrolary: Finding all these overlaps and taking the minimum gives the + * minimum vector to take the shapes out of intersection. + * + * \param one: first body + * \param two: second body + * \param translation: The minimum vector to take `one` and `two` out of intersection. + * \return: they are intersecting + * + */ +bool sat_collision_check(Body *one, Body *two, Vect *translation) { // reference: // http://www.dyn4j.org/2010/01/sat/#sat-inter // // TODO: Maybe avoid calculating the centre of the boxes; have body->position // be the centre and translate the collision box to be around that. It does // make placing a little more complex but no bother. -bool sat_collision_check(Body *one, Body *two, Vect *translation) { + int num_axes = one->collision_poly_size + two->collision_poly_size; Vect *axes = calloc(num_axes, sizeof(Vect)); @@ -637,17 +759,12 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) { two_position.x /= two->collision_poly_size; two_position.y /= two->collision_poly_size; - /*printf("ONE POS: %f %f", one_position.x, one_position.y);*/ - /*printf("TWO POS: %f %f", two_position.x, one_position.y);*/ direction.x = one_position.x - two_position.x; direction.y = one_position.y - two_position.y; double dot = vect_scalar_projection(trans, direction); - /*printf("DIRECTION: %f %f\n\n", direction.x, direction.y);*/ - /*printf("DOT: %f\n\n", dot);*/ - if (dot > 0) { trans = vect_scalar(trans, -1); } @@ -662,6 +779,16 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) { return true; } +/* + * Check collision between two bodies using an appropriate scheme. + * + * + * \param one: first body + * \param two: second body + * \param translation: The minimum vector to take `one` and `two` out of intersection. + * \return: they are intersecting + * + */ bool check_collision(Body *one, Body *two, Vect *translation) { int onesize = one->collision_poly_size; int twosize = two->collision_poly_size; @@ -766,7 +893,6 @@ void load_level() { destroy_physics_collection(&world.uniques_index[ROOM_W]->room->ceil); destroy_physics_collection(&world.uniques_index[ROOM_W]->room->floor); - //destroy_environment(&world.uniques_index[ROOM_W]->room->env); get_floor_ceiling(); draw_watch.best_time = get_best_time(); @@ -1263,7 +1389,10 @@ bool get_motor_active(Body *thing, int i) { return true; } -/* Basic physics works by adding up the acceleratino caused by all the forces on +/* + * Update the physics state for a body. + * + * Basic physics works by adding up the acceleration caused by all the forces on * the object, converting it to velocity, then doing collision detection and * applying various reactive forces (friction etc) and finally adjusting the * object's position. @@ -1288,11 +1417,6 @@ void advance_thing(Body * thing) { // collisions if ((numcols = process_collisions(thing, &translation))) { - /*double check = vect_scalar_projection(translation, thing->vel);*/ - /*if (check >= 0) {*/ - /*translation.x *= -1;*/ - /*translation.y *= -1;*/ - /*}*/ // correct position using translation vector. thing->next_position.x += translation.x; @@ -1345,33 +1469,6 @@ void advance_thing(Body * thing) { } - /*double norm = 9.81 * thing->obj_mass;*/ - /*Vect x;*/ - /*x.y = 0; x.x = 1;*/ - /*if (vect_scalar_projection(thing->vel, translation) > 0) {*/ - /*friction.x = translation.y;*/ - /*friction.y = -translation.x;*/ - /*} else {*/ - /*friction.x = -translation.y;*/ - /*friction.y = translation.x;*/ - /*}*/ - - // force - /*friction.x = friction.x * norm * fric_const;*/ - /*friction.y = friction.y * norm * fric_const;*/ - // printf("friction accel: %e %e\n", friction.x, friction.y); - // printf("velocity: %e %e\n", thing->vel.x, thing->vel.y); - - /*set_motor_newtons(thing, M_FRICTION, friction.x, friction.y);*/ - /*set_motor_max_velocity(thing, M_FRICTION, vect_mag(project_vect(thing->vel, friction)));*/ - - // restitution force - /*rest.x = 0;*/ - /*rest.y = 0;*/ - /*double impulse = thing->obj_mass * vect_mag(thing->vel) * thing->obj_elasticity;*/ - /*rest.x = cos(vect_dir(translation)) * impulse;*/ - /*rest.y = sin(vect_dir(translation)) * impulse;*/ - /*accel_thing(thing, rest.x, rest.y);*/ } // pendulums @@ -1444,21 +1541,6 @@ void advance_thing(Body * thing) { double velocity = sqrt((double)(thing->vel.x * thing->vel.x + thing->vel.y * thing->vel.y)); - // simple air drag - - /*if (velocity > 0.000000000000000) {*/ - /*double dir = atan2((double)thing->y_vel, (double)thing->x_vel) + M_PI;*/ - - /*double absolute_force = 5 * thing->obj_mass * (velocity / time_delta); // 2 * 0.1231 * 5;*/ - /*printf("dir %e %e\n\n", dir, dir - M_PI);*/ - /*printf("force %e\n\n", absolute_force);*/ - - /*double f_x = (cos(dir)) * absolute_force;*/ - /*double f_y = (sin(dir)) * absolute_force;*/ - - /*accel_thing(thing, (float)f_x, (float)f_y);*/ - - /*}*/ if (fabsl((*thing).vel.x) < 0.001) { (*thing).vel.x = 0; @@ -1489,13 +1571,6 @@ void advance_thing(Body * thing) { } -/*void destroy_projectile(Projectile** proj) {*/ - /*for (int i = 0; i < things_in_world; i ++) {*/ - /*if (world[i].projectile == *proj) {*/ - - /*}*/ - /*}*/ -/*}*/ void *default_projectile_step(struct Projectile *self) { advance_thing(self->physics); @@ -1542,16 +1617,8 @@ void advance_things(void) { continue; case FLOOR: continue; - /*for (int k = 0; k < world.get(i).floor->numPolys; k++) {*/ - /*advance_thing(world.get(i).floor->polys[k].physics);*/ - /*}*/ - /*break;*/ case CEILING: continue; - /*for (int k = 0; k < world.get(i).floor->numPolys; k++) {*/ - /*advance_thing(world.get(i).floor->polys[k].physics);*/ - /*}*/ - /*break;*/ case PROJECTILE: if ((numcols = process_collisions(world.get(i).projectile->physics, &translation))) { @@ -1619,8 +1686,6 @@ void get_room(void) { FloorPoly *ceil = generate_floor_simple(floorsize, false, 1000); -// printf("floor: %f %f\n", polys[2].left.x, polys[2].left.y); -// printf("ceil: %f %f\n", ceil[2].left.x, ceil[2].left.y); Floor* ceiling = calloc(1, sizeof(Floor)); ceiling->polys = ceil; @@ -1645,6 +1710,11 @@ GlobWorld create_world() { return c; } +/* + * + * Run once, intialises the game. + * + */ void startgame(SDL_Renderer * ren) { load_fonts(); get_input_map(); @@ -1663,8 +1733,6 @@ void startgame(SDL_Renderer * ren) { SDL_GetRendererOutputSize(ren, &width, &height); -// player = get_player(200,1300); - get_floor_ceiling(); Vect stpos = *world.uniques_index[ROOM_W]->room->ceil.items[2]->collision_poly; player = get_player(stpos.x, stpos.y - 15); @@ -1684,14 +1752,17 @@ void startgame(SDL_Renderer * ren) { game_paused = 0; viewport_pos.x = player.physics->position.x - width / 2; viewport_pos.y = player.physics->position.y - height / 2; - - //get_room(); } double get_abs(double x,double y) { return (sqrt(x*x + y*y)); } +/* + * + * Make a player walk along the ground. Only enabled in debug mode. + * + */ void walk_player(int x, int y) { set_motor_status(player.physics, M_PLAYER_WALK, true); @@ -1704,6 +1775,12 @@ void walk_player(int x, int y) { add_motor_newtons(glob_player->physics, M_PLAYER_WALK, 100 *5* x , 100 * 5 * y); } +/* + * + * Handle non-window events pertaining to the game logic. Window events are + * handled in main. Bindings are defined in controlscheme.c. + * + */ void handle_input_event(SDL_Event event) { SDL_Scancode sc = event.key.keysym.scancode; static bool mouse_down = false; @@ -1804,7 +1881,10 @@ void handle_input_event(SDL_Event event) { } -/* temporary storage variable *n should be initialised to 1 */ +/* + * Basic PRNG for cross-platform consistency. + * + * temporary storage variable *n should be initialised to 1 */ int get_rand(int *n) { const unsigned c = 11; const unsigned m = (1 << 31) - 1; @@ -1816,11 +1896,15 @@ int get_rand(int *n) { } +/* + * + * Entry point for update step. + * + */ int step(void) { static int first_run = 0; if (!first_run) { start_audio(); -// play_game_sound(game_sounds.background, -1, BC_MUSIC); first_run = 1; game_paused = 1; } diff --git a/src/main.c b/src/main.c index 1a8246a..31e050d 100644 --- a/src/main.c +++ b/src/main.c @@ -10,11 +10,12 @@ #include #include #include - -#include "audio.h" // only for mkdirat lol +#include #include #include +#include "audio.h" + #include "game.h" #include "draw.h" #include "types.h" @@ -76,19 +77,19 @@ int physics_loop(void *ptr) { int game(void) { - //SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "2" ); SDL_Window * win = make_window(); - SDL_Renderer * ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED); -// | SDL_RENDERER_PRESENTVSYNC); + SDL_Renderer * ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED +#ifdef USE_VSYNC + | SDL_RENDERER_PRESENTVSYNC +#endif + ); SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND); in_game = true; resume = SDL_CreateSemaphore(0); - // IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG); - if (ren == NULL) { SDL_DestroyWindow(win); SDL_Quit(); diff --git a/src/types.h b/src/types.h index b4fc485..2a1da39 100644 --- a/src/types.h +++ b/src/types.h @@ -105,13 +105,6 @@ typedef struct BodyStruct{ double obj_friction; // between 0 and 1 (fraction of lateral velocity // that is removed) - //float x_vel; - //float y_vel; - - //float x_acc; - //float y_acc; - /*------------------*/ - // collisions Vect *collision_poly; Vect *collision_shape; @@ -123,7 +116,7 @@ typedef struct BodyStruct{ double glob_friction; bool glob_gravity; // t/f -// uint32_t last_advance_time; + // uint32_t last_advance_time; struct timespec last_advance_time; @@ -228,7 +221,6 @@ typedef struct world GlobWorld; // environment enum { -// E_ROOM_WIDTH = 100000, E_ROOM_WIDTH = 10000, E_ROOM_RES = 500, E_ROOM_TILES = E_ROOM_WIDTH / E_ROOM_RES,