From 99ab9bd22be2506c23d1e379f35583ddab4eadf6 Mon Sep 17 00:00:00 2001 From: zlago Date: Fri, 4 Oct 2024 21:38:14 +0200 Subject: map transitions --- src/main.c | 290 ++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 208 insertions(+), 82 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index 2d3e89d..c48deef 100644 --- a/src/main.c +++ b/src/main.c @@ -19,6 +19,8 @@ SDL_Window *window = NULL; SDL_Renderer *renderer = NULL; +enum game_state game_state = STATE_PLAYING; +char *game_next_level; #define WINDOW_WIDTH 160 #define WINDOW_HEIGHT 90 @@ -34,13 +36,134 @@ SDL_Scancode keybinds[] = { SDL_SCANCODE_S, }; -struct entity player[1] = {0}; +struct entities entities = {{{0}}, {{0}}, 0, {{0}}, 0}, next_entities = {{{0}}, {{0}}, 0, {{0}}, 0}; -struct entity *player_new(void); -int player_property(struct entity *const restrict entity, char const *const restrict property, char const *const restrict value); +void *player_new(struct entities *entities); +int player_property(void *const restrict entity, char const *const restrict property, char const *const restrict value); void funs_init(void); +void entities_free(struct entities *entities) { + for (int i = 0, e = 0; i < 64 && e < entities->enemies; i++) { + if (entities->enemy[i].state) { + e++; + if (entities->enemy[i].free != NULL) { + entities->enemy[i].free(entities->enemy + i); + } + } + } + entities->enemies = 0; + #if 0 + for (int i = 0; i < entities.warps; i++) { + entities.warp[i].update(entities.warp + i); + } + #endif + entities->warps = 0; +} + +int entities_load(struct entities *entities, char *data, size_t size, size_t input_bytes) { + entities->enemies = 0; + entities->warps = 0; + data += input_bytes; + size -= input_bytes; + while (size) { + size_t len; + if ((len = strnlen(data, size)) == size) { + return 1; + } + char *name = data; + struct funs fun = res_get_fun(name); + data += len + 1; + size -= len + 1; + if (fun.newfun) { + struct entity *entity = fun.newfun(&next_entities); + while (1) { + if ((len = strnlen(data, size)) == size) { + return 1; + } else if (len == 0) { + data++; + size--; + break; + } + char *key = data; + data += len + 1; + size -= len + 1; + if ((len = strnlen(data, size)) == size) { + return 1; + } + char *value = data; + data += len + 1; + size -= len + 1; + if (fun.setfun(entity, key, value)) { + puts(key); puts(value); + return 1; + } + } + } else { + fprintf(stderr, "warn: unknown entity %s\n", name); + while (1) { + if ((len = strnlen(data, size)) == size) { + return 1; + } else if (len == 0) { + data++; + size--; + break; + } + data += len + 1; + size -= len + 1; + if ((len = strnlen(data, size)) == size) { + return 1; + } + data += len + 1; + size -= len + 1; + } + } + } + return 0; +} + +int game_update(void) { + if (entities.player[0].update(entities.player)) { + return 1; + } + + for (int i = 0, e = 0; i < 64 && e < entities.enemies; i++) { + if (entities.enemy[i].state) { + e++; + entities.enemy[i].update(entities.enemy + i); + } + } + + for (int i = 0; i < entities.warps; i++) { + entities.warp[i].update(entities.warp + i); + } + + return 0; +} + +void game_render(SDL_Texture *framebuffer, int x, int y) { + SDL_SetRenderTarget(renderer, framebuffer); + tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT); + entities.player[0].draw(entities.player, x, y); + for (int i = 0, e = 0; i < 64 && e < entities.enemies; i++) { + if (entities.enemy[i].state) { + e++; + entities.enemy[i].draw(entities.enemy + i, x, y); + } + } + tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT); + //SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); +} + +void game_render_flush(SDL_Texture *framebuffer) { + SDL_SetRenderTarget(renderer, NULL); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}); + // then we wait for the next video frame + SDL_RenderPresent(renderer); +} + int main(int const argc, char *const *const argv) { struct option opts[] = { {"help", 0, NULL, 'h'}, @@ -176,60 +299,19 @@ int main(int const argc, char *const *const argv) { optind++; } } - struct blob map = res_get_map("untitled"); - tilemap = tilemap_load(map.data, map.size); - char *a = (char *) map.data + tilemap->input_bytes; - map.size -= tilemap->input_bytes; - while (map.size) { - size_t len; - if ((len = strnlen(a, map.size)) == map.size) { - return 1; // hack - } - char *name = a; - puts(name); - struct funs fun = res_get_fun(name); - a += len + 1; - map.size -= len + 1; - if (fun.newfun) { - struct entity *entity = fun.newfun(); - while (1) { - if ((len = strnlen(a, map.size)) == map.size) { - return 1; // hack - } else if (len == 0) { - a++; - map.size--; - break; - } - char *key = a; - a += len + 1; - map.size -= len + 1; - if ((len = strnlen(a, map.size)) == map.size) { - return 1; // hack - } - char *value = a; - a += len + 1; - map.size -= len + 1; - if (fun.setfun(entity, key, value)) { - return 1; // hack - } - } - } else { - while (1) { // hack - if ((len = strnlen(a, map.size)) == map.size) { // hack - return 1; // hack - } else if (len == 0) { - a++; - map.size--; - break; - } - a += len + 1; - map.size -= len + 1; - } - } + + struct blob blob = res_get_map("untitled"); + next_tilemap = tilemap_load(blob.data, blob.size); + if (next_tilemap == NULL) { + fputs("failed to load initial tilemap\n", stderr); + goto end; } - //memmem(map.data + tilemap->byte_count, map.size - tilemap->byte_count, (char []) {0, 0}, 2); - printf("load_tilemap %p\n", (void *) tilemap); - SDL_SetRenderTarget(renderer, NULL); + if (entities_load(&entities, blob.data, blob.size, next_tilemap->input_bytes)) { + tilemap_free(next_tilemap); + fputs("failed to load initial tilemap\n", stderr); + goto end; + } + tilemap = next_tilemap; } /* unsigned error; // identical variable is declared higher up */ @@ -251,10 +333,11 @@ int main(int const argc, char *const *const argv) { SDL_ShowWindow(window); - int x = 0, y = 0; - player_new(); - player_property(player, "x", "40"); - player_property(player, "y", "64"); + int x = 0, y = 0, fade = 0; + player_new(&next_entities); + player_property(next_entities.player, "x", "40"); + player_property(next_entities.player, "y", "64"); + memcpy(&entities, &next_entities, sizeof (entities)); while (1) { SDL_Event evt; while (SDL_PollEvent(&evt)) { @@ -352,29 +435,72 @@ int main(int const argc, char *const *const argv) { } } - //SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); - if (player[0].update(player)) { - break; // TODO: game over state + switch (game_state) { + case STATE_PLAYING: + //SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); + if (game_update()) { + goto end; // TODO: game over state + } + + x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2); + y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2); + if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;} + if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;} + + game_render(framebuffer, x, y); + game_render_flush(framebuffer); + break; + + case STATE_FADE_IN: + fade += 15; + SDL_SetRenderTarget(renderer, NULL); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, fade); + SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}); + SDL_RenderPresent(renderer); + if (fade == 255) { + struct blob blob = res_get_map(game_next_level); + next_tilemap = tilemap_load(blob.data, blob.size); + if (next_tilemap != NULL) { + if (entities_load(&next_entities, blob.data, blob.size, next_tilemap->input_bytes)) { + tilemap_free(next_tilemap); + } else { + tilemap_free(tilemap); + tilemap = next_tilemap; + entities_free(&entities); + memcpy(&entities, &next_entities, sizeof (entities)); + } + } + game_state = STATE_FADE_OUT; + + x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2); + y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2); + if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;} + if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;} + + game_render(framebuffer, x, y); + SDL_SetRenderTarget(renderer, NULL); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); + } + break; + + case STATE_FADE_OUT: + fade -= 15; + SDL_SetRenderTarget(renderer, NULL); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, fade); + SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}); + SDL_RenderPresent(renderer); + if (fade == 0) { + game_state = STATE_PLAYING; + } + break; } - - //x += input_right(input_now) - input_left(input_now); - //y += input_down(input_now) - input_up(input_now); - x = (player[0].x / 16) - (WINDOW_WIDTH / 2); - y = (player[0].y / 16) - (WINDOW_HEIGHT / 2); - if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;} - if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;} - - SDL_SetRenderTarget(renderer, framebuffer); - tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT); - player[0].draw(player, x, y); - tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT); - //SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90}); - SDL_SetRenderTarget(renderer, NULL); - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}); - // then we wait for the next video frame - SDL_RenderPresent(renderer); } end: -- cgit 1.4.1-2-gfad0