diff --git a/src/draw.c b/src/draw.c index 0734a5e..9fe519e 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1,6 +1,7 @@ #include "draw.h" #include "game.h" #include +#include #include Vect viewport_pos; @@ -280,7 +281,7 @@ void new_update_viewport(Body const * const pl) { static double dirchange = 0; static Vect last_plpos = {}; if (last_plpos.x == 0 && last_plpos.y == 0) - last_plpos = player.physics->position; + last_plpos = pl->position; static Vect lmove = {}; @@ -296,15 +297,16 @@ void new_update_viewport(Body const * const pl) { Vect screen_dist = vect_add(in_view(pl->position), vect_scalar(lmove, -1)); + static double swap = 0; if (iv.x > width || (iv.x < 0 || iv.y > height || iv.y < 0)) recover = true; - Vect delta = vect_add(vect_scalar(player.physics->position, -1), last_plpos); + Vect delta = vect_add(vect_scalar(pl->position, -1), last_plpos); double dist_change = vect_mag(delta); - if (true || (recover) //|| vect_mag((Vect){pl->vel.x, 0}) > 0.4 + if ((recover) //|| vect_mag((Vect){pl->vel.x, 0}) > 0.4 || (dist_change > width / 100)) { if (iv.x < width / 6) { target = right_pos; @@ -313,7 +315,7 @@ void new_update_viewport(Body const * const pl) { } lmove = target; - last_plpos = player.physics->position; + last_plpos = pl->position; } if (recover) @@ -352,11 +354,11 @@ void new_update_viewport(Body const * const pl) { v = -v; // move towards target a set proportion - Vect urgency = vect_add(target, vect_scalar(player.physics->position, -1)); + Vect urgency = vect_add(target, vect_scalar(pl->position, -1)); Vect p = vect_add(target, vect_scalar(viewport_pos, -1)); double proportion = (sigmoid(time_delta) / 100); - proportion = 2 * player.physics->vel.x / (width); + proportion = 2 * (pl->vel.x * pl->vel.x / (width)); proportion = proportion < 0 ? -proportion : proportion; proportion > 0.4 ? proportion = 0.4 : 0; @@ -496,7 +498,7 @@ void draw_text(SDL_Renderer *rend, Vect pos, struct colour colour, char *text) { static SDL_Renderer *ren = NULL; static TTF_Font* font = NULL; if (!font) { - font = TTF_OpenFont("TerminusTTF.ttf", 18); + font = TTF_OpenFont("TerminusTTF.ttf", 22); const char *err = SDL_GetError(); if (err) { printf("%s\n", err); @@ -521,10 +523,45 @@ void draw_text(SDL_Renderer *rend, Vect pos, struct colour colour, char *text) { } +int draw_end_screen(SDL_Renderer *ren) { + struct environment scene = get_scene_at(viewport_pos, level); + + struct colour bg = scene.colours.bg; + struct colour colour = scene.colours.fg1; + + SDL_SetRenderDrawColor(ren, bg.r, bg.g, bg.b,255); + SDL_RenderClear(ren); + + int margin = height / 10; + // Vect position = {.x = width - width / 10, .y = height - margin}; + + int minutes = level_time / 60000; + float seconds = level_time * 0.001; + char time_string[250]; + snprintf(time_string, 250, "TIME: %d:%.4f", minutes, seconds); + char * end_str = "Level over."; + char * ct_str = "Press any key to continue."; + char qual_str[250]; + snprintf(qual_str, 250, "Physics quality: %d", quality); + + Vect position = {.x = width/3, .y = height / 4}; + draw_text(ren, position, colour, end_str); + position.y += 40; + draw_text(ren, position, colour, time_string); + position.y += 40; + draw_text(ren, position, colour, qual_str); + position.y += 40; + draw_text(ren, position, colour, ct_str); + + SDL_RenderPresent(ren); + return 0; +} + + void draw_level_time(SDL_Renderer *ren, struct environment * e) { int margin = height / 10; - Vect position = {.x = margin, .y = height - margin}; + Vect position = {.x = width - width / 10, .y = height - margin}; struct colour colour = e->colours.fg1; @@ -558,8 +595,7 @@ void redraw_buffer(SDL_Renderer * ren) { if (SDL_LockMutex(player.physics->lock) == 0){ lplayer = *player.physics; - new_update_viewport(&lplayer); - SDL_UnlockMutex(player.physics->lock); + update_viewport(&lplayer); } else { return; } @@ -577,6 +613,7 @@ void redraw_buffer(SDL_Renderer * ren) { struct environment scene = get_scene_at(viewport_pos, level); draw_environment(ren, &scene); draw_level_time(ren, &scene); + SDL_UnlockMutex(player.physics->lock); for (int i=0; i < world.items.size; i++) { world_thing thing; diff --git a/src/draw.h b/src/draw.h index 3180d7a..ded3047 100644 --- a/src/draw.h +++ b/src/draw.h @@ -37,5 +37,6 @@ extern int width, height; void draw_text(SDL_Renderer *ren, Vect pos, struct colour colour, char *text); +int draw_end_screen(SDL_Renderer *ren); #endif diff --git a/src/game.c b/src/game.c index e3c774e..e64c8db 100644 --- a/src/game.c +++ b/src/game.c @@ -6,6 +6,7 @@ #define FLOOR_THICKNESS 200 #define MAX_ROPE_GRAB_LEN 80000 +#define MIN_PHYSICS_STEP 2.0 #define BREAKPOINT *(int *)0 = 1; @@ -14,9 +15,14 @@ GlobWorld world; player_st *glob_player; SDL_Renderer *debug_ren; +bool in_game; +bool game_paused; int level; +int quality = 100; long level_time; +int get_floor_ceiling(); + /* array of all the things in the world and their kinds */ //world_thing *world; @@ -26,7 +32,6 @@ void process_keydown(SDL_Keysym key); void process_keyup(SDL_Keysym key); void add_to_world(world_thing thing); -void step(int interval); void set_motor_timeout(Body *thing, int motorID, uint32_t timeout); void set_motor_status(Body *thing, int motorID, bool run); void stop_pull_rope(void); @@ -553,8 +558,9 @@ void destroy_physics_collection(struct physics_collection *s) { free(s->items); } -int get_floor_ceiling(); + void next_level() { + SDL_LockMutex(player.physics->lock); Vect v; v.x = 0; v.y = 0; @@ -588,6 +594,9 @@ void next_level() { player.physics->position = v; player.physics->next_position = v; + quality = 100; + level_timer_update(true); + SDL_UnlockMutex(player.physics->lock); } @@ -1081,15 +1090,22 @@ void advance_thing(Body * thing) { } time_delta *= 0.000001; // convert to ms from ns - thing->last_advance_time = now; // cap the time delta: simulatino will slow down // printf("delta: %f\n", time_delta); if (time_delta > 19) { printf("ERROR too slow: %f\n", time_delta); time_delta = 19; + quality--; } + if (time_delta < MIN_PHYSICS_STEP) { + SDL_Delay(MIN_PHYSICS_STEP); + advance_thing(thing); + return; + } + thing->last_advance_time = now; + // collisions if ((numcols = process_collisions(thing, &translation))) { /*double check = vect_scalar_projection(translation, thing->vel);*/ @@ -1266,15 +1282,16 @@ void advance_thing(Body * thing) { (*thing).vel.y = 0; } + if (thing->lock) { + SDL_LockMutex(thing->lock); + } + thing->position = thing->next_position; + double oldx = thing->position.x; double oldy = thing->position.y; thing->next_position.x += (thing->vel.x * 1/2 * (double)time_delta); thing->next_position.y += (thing->vel.y * 1/2 * (double)time_delta); - if (thing->lock) { - SDL_LockMutex(thing->lock); - } - thing->position = thing->next_position; if (!thing->collision_poly[0].y) { thing->updateCollisionPoly(thing); @@ -1316,7 +1333,6 @@ void get_projectile(Projectile** proj) { void advance_things(void) { int numcols; Vect translation; - level_timer_update(false); for (int i = 0; i < world.items.size; i++) { switch (world.get(i).kind) { case PLAYER_W : @@ -1458,6 +1474,7 @@ void startgame(SDL_Renderer * ren) { viewport_pos.y = 0; level_timer_update(true); + game_paused = 0; //get_room(); } @@ -1548,17 +1565,21 @@ int get_rand(int seed) { } -void step(int interval) { +int step(void) { if (player.physics->position.x > world.uniques_index[ROOM_W]->room ->floor.items[world.uniques_index[ROOM_W]->room->floor.numItems - 1]->position.x) { - SDL_Delay(1000); - next_level(); - level_timer_update(true); + return 1; + } + if (player.physics->position.x > world.uniques_index[ROOM_W]->room + ->floor.items[3]->position.x) { + level_timer_update(false); + } else { } - advance_things(); + if (in_game && !game_paused) { + advance_things(); + } + return 0; } - - diff --git a/src/game.h b/src/game.h index aed6d9a..122e9a7 100644 --- a/src/game.h +++ b/src/game.h @@ -12,6 +12,8 @@ extern GlobWorld world; extern int level; +extern bool in_game; +extern int quality; void handle_input_event(SDL_Event event); @@ -22,12 +24,17 @@ bool get_motor_active(Body *thing, int i); int get_rand(int seed); +void next_level(); + +int step(void); + /* array of all the things in the world and their kinds */ + extern void startgame(SDL_Renderer * ren) ; extern void process_keydown(SDL_Keysym key); extern void process_keyup(SDL_Keysym key); -extern void step(int interval); extern player_st player; extern long level_time; +extern bool game_paused; #endif diff --git a/src/main.c b/src/main.c index 68ce80b..938dfd1 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -15,6 +16,19 @@ const int screen_width = 800; const int screen_height = 600; +SDL_sem *resume; + +long int *times; + +struct sg_times_list { + long *times; + int size; + int capacity; + void (*sort)(void); +}; + +struct sg_times_list save_times_lst; + struct SDL_Window* make_window(void) { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { printf("error initializing SDL: %s\n", SDL_GetError()); @@ -30,18 +44,30 @@ struct SDL_Window* make_window(void) { void redraw(struct SDL_Renderer * ren) { - // check time - // redraw if 1/60th of second passed - SDL_RenderClear(ren); redraw_buffer(ren); SDL_RenderPresent(ren); } int physics_loop(void *ptr) { - while (true) { - step(10); - SDL_Delay(10); + game_paused = 1; + SDL_Delay(1000); + game_paused = 0; + while (1) { + if (step()) { + // display end level screen + game_paused = true; + SDL_Delay(1000); + in_game = false; + SDL_SemWait(resume); + SDL_LockMutex(player.physics->lock); + game_paused = true; + in_game = true; + next_level(); + SDL_UnlockMutex(player.physics->lock); + SDL_Delay(1000); + game_paused = 0; + } } } @@ -50,7 +76,7 @@ int game(void) { LOGLEVEL = DEBUG; STDOUTLEVEL = DEBUG; - SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "2" ); + //SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "2" ); logwrite(INFO, "Starting\n"); SDL_Window * win = make_window(); @@ -60,12 +86,16 @@ int game(void) { queue_for_cleanup(win, WINDOW); queue_for_cleanup(ren, RENDERER); + in_game = true; + resume = SDL_CreateSemaphore(0); + // IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG); if (ren == NULL) { SDL_DestroyWindow(win); SDL_Quit(); } + TTF_Init(); int close = 0; @@ -75,10 +105,9 @@ int game(void) { SDL_Thread *physics_thread; int ignore; - bool once = true; startgame(ren); -// physics_thread = SDL_CreateThread(physics_loop, "Physics", (void *)NULL); + physics_thread = SDL_CreateThread(physics_loop, "Physics", (void *)ren); while (!close) { @@ -92,6 +121,9 @@ int game(void) { if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) { return 0; } + if (!SDL_SemValue(resume)) { + SDL_SemPost(resume); + } case SDL_KEYUP: case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: @@ -99,14 +131,84 @@ int game(void) { } } /* Redraw Screen */ - step(10); - redraw(ren); +// step(10); + + if (!in_game) { + draw_end_screen(ren); + } else { + redraw(ren); + } } +} + + +int long_comparator(const void *a, const void *b, void *non) { + long A = *(long *)a; + long B = *(long *)b; + + return A - B; +} + +void sort_times(void) { + qsort_r(save_times_lst.times, save_times_lst.size, sizeof(long), long_comparator, NULL); +} + +int load_score_times(char *filename) { + FILE *f = fopen(filename, "r"); + + if (f) { + // get file size + fseek(f, 0L, SEEK_END); + long sz = ftell(f); + fseek(f, 0L, SEEK_SET); + char *text = malloc((sz + 1) * (sizeof(char))); + + // read file + fread(text,sizeof(char),sz, f); + fclose(f); + + int count = 1; + for (int i = 0; i < strlen(text); i++) { + if (text[i] == '\n') { + count++; + } + } + + long *times = malloc(count * sizeof(long)); + char *saveptr; + + // extract times + char * token = strtok_r(text, "\n", &saveptr); + int i = 0; + while (token != NULL) { + if (strlen(token) > 2) { + times[i] = atol(token); + i++; + } + token = strtok_r(NULL, "\n", &saveptr); + } + save_times_lst = (struct sg_times_list){.size=i, .capacity = count, .times=times, .sort=sort_times}; + save_times_lst.sort(); + } else { + perror("loading times"); + save_times_lst = (struct sg_times_list){.size=0, .capacity = 5, .times=calloc(5, sizeof(long)), .sort=sort_times}; + } + for (int i = 0; i < save_times_lst.size; i++) { + printf("%ld\n", save_times_lst.times[i]); + } + + return 0; +} + +long get_best_time(void) { + save_times_lst.sort(); + return save_times_lst.times[0]; } int main (int argc, char** argv) { + load_score_times("savegame"); game(); SDL_Quit(); //empty_cleanup_queue(); diff --git a/src/types.h b/src/types.h index 574c5cc..1190f6d 100644 --- a/src/types.h +++ b/src/types.h @@ -220,10 +220,9 @@ typedef struct world GlobWorld; enum { // E_ROOM_WIDTH = 100000, - E_ROOM_WIDTH = 40000, + E_ROOM_WIDTH = 10000, E_ROOM_RES = 500, E_ROOM_TILES = E_ROOM_WIDTH / E_ROOM_RES, }; - #endif