From 1ae6a63f79edd72aa39c7f7e2bca5182a68592b4 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Mon, 10 Jul 2023 23:06:59 +0100 Subject: Draw entities in order This makes a difference on the less powerful machines and helps avoiding flickering. --- src/effect.c | 2 +- src/entities.c | 86 ++++++++++++++++++++++++++++++++++++++++++---------------- src/entities.h | 8 ++++++ src/game.c | 8 ++---- src/pickup.c | 5 +++- 5 files changed, 79 insertions(+), 30 deletions(-) diff --git a/src/effect.c b/src/effect.c index e308054..a2e58c2 100644 --- a/src/effect.c +++ b/src/effect.c @@ -37,6 +37,6 @@ void effect_out_update(Entity *e) e->delay = 0; e->frame++; if (e->frame == MAX_FRAME) - e->used = 0; + e->used = USED_FREE; } } diff --git a/src/entities.c b/src/entities.c index b2ee7fd..65c0bfd 100644 --- a/src/entities.c +++ b/src/entities.c @@ -1,10 +1,12 @@ #include #include +#include #include "vga.h" #include "map.h" #include "data.h" #include "entities.h" +#include "player.h" #include "effect.h" @@ -13,20 +15,28 @@ static Entity entities[MAX_ENTITY]; static uint8_t last; +static uint8_t sort_cnt; +static Entity *sort[MAX_ENTITY + 1]; +static Entity player_ent; + void entities_init() { memset(entities, 0, sizeof(Entity) * MAX_ENTITY); last = 0; + + memset(&player_ent, 0, sizeof(Entity)); + player_ent.used = USED_PLAYER; + sort_cnt = 0; } Entity *entities_new() { for (uint8_t i = 0; i < MAX_ENTITY; i++) { - if (entities[i].used == 0) + if (entities[i].used == USED_FREE) { memset(&entities[i], 0, sizeof(Entity)); - entities[i].used = 1; + entities[i].used = USED_FG; if (i >= last) last = i + 1; @@ -40,40 +50,70 @@ Entity *entities_new() void entities_update() { - Entity *e = entities; - - for (uint8_t i = 0; i < last; i++, e++) - if (e->used) + for (uint8_t i = 0; i < last; i++) + if (entities[i].used) { - e->ox = e->x; - e->oy = e->y; - e->update(e); + entities[i].ox = entities[i].x; + entities[i].oy = entities[i].y; + entities[i].update(&entities[i]); } } +static int cmp_entities(const void *a, const void *b) +{ + const Entity *ea = (const Entity *) a; + const Entity *eb = (const Entity *) b; + + return (ea->y << ea->used) - (eb->y << eb->used); +} + +void entities_sort() +{ + sort_cnt = 0; + + for (uint8_t i = 0; i < last; i++) + if (entities[i].used) + sort[sort_cnt++] = &entities[i]; + + player_ent.y = player_y(); + sort[sort_cnt++] = &player_ent; + + qsort(sort, sort_cnt, sizeof(Entity *), cmp_entities); +} + void entities_draw() { Rect dst = { 0, 0, 16, 16 }; - Entity *e = entities; - for (uint8_t i = 0; i < last; i++, e++) - if (e->erase) + player_erase(); + + for (uint8_t i = 0; i < last; i++) + { + if (entities[i].erase) { - dst.x = e->ox; - dst.y = e->oy + MAP_OFFS_Y; + dst.x = entities[i].ox; + dst.y = entities[i].oy + MAP_OFFS_Y; blit_copy16(&dst); - e->erase = 0; + entities[i].erase = 0; } + } - e = entities; - - for (uint8_t i = 0; i < last; i++, e++) - if (e->used) + /* draw in order to avoid flickering */ + for (uint8_t i = 0; i < sort_cnt; i++) + switch (sort[i]->used) { - dst.x = e->x; - dst.y = e->y + MAP_OFFS_Y; - blitrc(binary_sprites_start, &e->frames[e->dir * 4 + e->frame], &dst); - e->erase = 1; + case USED_FREE: + break; + case USED_FG: + case USED_BG: + dst.x = sort[i]->x; + dst.y = sort[i]->y + MAP_OFFS_Y; + blitrc(binary_sprites_start, &sort[i]->frames[sort[i]->dir * 4 + sort[i]->frame], &dst); + sort[i]->erase = 1; + break; + case USED_PLAYER: + player_draw(); + break; } } diff --git a/src/entities.h b/src/entities.h index 169e582..ca2bb1f 100644 --- a/src/entities.h +++ b/src/entities.h @@ -6,6 +6,11 @@ #define WALK_DELAY 8 +#define USED_FREE 0 +#define USED_BG 1 +#define USED_FG 2 +#define USED_PLAYER 3 + typedef struct entity_s { uint8_t used; @@ -30,6 +35,9 @@ void entities_init(); Entity *entities_new(); void entities_update(); +/* MUST be run before draw */ +void entities_sort(); +/* also erases/draws the player */ void entities_draw(); void entities_warp_out_all(); diff --git a/src/game.c b/src/game.c index 1e376a6..7d64224 100644 --- a/src/game.c +++ b/src/game.c @@ -186,8 +186,8 @@ next_stage: blit_target(TARGET_SCREEN); put_text(136, 100, "READY?", 1); + entities_sort(); entities_draw(); - player_draw(); /* wait some time */ wait_frames(96); @@ -197,7 +197,6 @@ next_stage: blit_copy_all(); entities_draw(); - player_draw(); timer_start(GAME_TIME_MAX, &clock_updated); @@ -264,21 +263,20 @@ next_stage: } if (time && tmonster) { - tmonster->used = 0; + tmonster->used = USED_FREE; tmonster = NULL; } } entities_update(); + entities_sort(); wait_vsync(); /* prevent interrupts so updating the audio doesn't result in sprite * flickering on the less powered machines */ disable(); - player_erase(); entities_draw(); - player_draw(); enable(); if (gameover) diff --git a/src/pickup.c b/src/pickup.c index 7036891..afc5ef2 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -109,6 +109,7 @@ static const Rect *frames_bonuses[] = void pickup_time_init(Entity *e) { + e->used = USED_BG; e->frames = (const Rect *)frames_in; e->flags = PICKUP_TIME; e->counter = MAX_TTL * 2 + (rand() % MAX_TTL); @@ -117,6 +118,7 @@ void pickup_time_init(Entity *e) void pickup_bonus_init(Entity *e) { + e->used = USED_BG; e->frames = (const Rect *)frames_in; e->flags = PICKUP_BONUS; e->counter = MAX_TTL + (rand() % MAX_TTL); @@ -125,6 +127,7 @@ void pickup_bonus_init(Entity *e) void pickup_pickaxe_init(Entity *e) { + e->used = USED_BG; e->frames = (const Rect *)frames_in; e->flags = PICKUP_PICKAXE; e->counter = MAX_TTL / 2 + (rand() % MAX_TTL); @@ -207,7 +210,7 @@ void pickup_update(Entity *e) add_pickaxe(); break; } - e->used = 0; + e->used = USED_FREE; sound_play_efx(EFX_PICKUP); } } -- cgit v1.2.3