diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 3a32da9..b3bbd80 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -34,6 +34,7 @@ add_library(lib_engine OBJECT entManager.c render_queue.c keymaps.c + timing.c ) target_link_libraries(lib_engine PUBLIC diff --git a/engine/engine.h b/engine/engine.h index 9ef65da..0691706 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -7,6 +7,7 @@ #include "assets.h" #include "particle_sys.h" #include "render_queue.h" +#include "timing.h" typedef struct Scene Scene_t; diff --git a/engine/timing.c b/engine/timing.c new file mode 100644 index 0000000..77c2808 --- /dev/null +++ b/engine/timing.c @@ -0,0 +1,68 @@ +#include "timing.h" +#include "assert.h" + +bool set_counter_period(ManualCounter* counter, float period) +{ + if (period < 0.0f) return false; + + counter->period = period; + return true; +} + +void elapse_counter_time(ManualCounter* counter, float delta) +{ + counter->fractional += delta; + if (counter->fractional > counter->period) + { + counter->fractional -= counter->period; + counter->count++; + } +} +void reset_counter_count(ManualCounter* counter) +{ + counter->count = 0; +} +void reset_counter(ManualCounter* counter) +{ + counter->count = 0; + counter->fractional = 0.0f; +} + +bool set_frame_timings(FrameTimer* timer, float frame_time, int count_period, int max_count) +{ + if (!set_counter_period((ManualCounter*)timer, frame_time)) return false; + if (count_period < 0 || max_count < 0) return false; + + timer->frame_count_period = count_period; + timer->frame_max_count = max_count; + return true; +} +void elapse_frame_time(FrameTimer* timer, float delta) +{ + timer->has_elapsed = false; + if (timer->frame_max_count == 0) return; + + elapse_counter_time((ManualCounter *)timer, delta); + if (timer->counter.count >= timer->frame_count_period) + { + reset_counter_count((ManualCounter*)timer); + if (!timer->pause) + { + timer->frame_count++; + timer->frame_count %= timer->frame_max_count; + timer->has_elapsed = true; + } + } +} + +void reset_frame_count(FrameTimer* timer) +{ + reset_counter_count((ManualCounter*)timer); + timer->frame_count = 0; +} + +void reset_frame_timer(FrameTimer* timer) +{ + reset_counter((ManualCounter*)timer); + timer->frame_count = 0; +} diff --git a/engine/timing.h b/engine/timing.h new file mode 100644 index 0000000..9bd8587 --- /dev/null +++ b/engine/timing.h @@ -0,0 +1,34 @@ +#ifndef ENGINE_TIMING_H +#define ENGINE_TIMING_H +#include +// Proper timer management in next version + +// A periodically-increasing counter +typedef struct ManualCounter { + // How long before increasing a count + // Negative period is not allowed. + float period; + float fractional; + int count; +} ManualCounter; + +bool set_counter_period(ManualCounter* counter, float period); +void elapse_counter_time(ManualCounter* counter, float delta); +void reset_counter_count(ManualCounter* counter); +void reset_counter(ManualCounter* counter); + +// Frame timer, usually for animation +typedef struct FrameTimer { + ManualCounter counter; + int frame_count_period; + int frame_max_count; + int frame_count; + bool pause; + bool has_elapsed; +} FrameTimer; + +bool set_frame_timings(FrameTimer* timer, float frame_time, int count_period, int max_count); +void elapse_frame_time(FrameTimer* timer, float delta); +void reset_frame_count(FrameTimer* timer); +void reset_frame_timer(FrameTimer* timer); +#endif // ENGINE_TIMING_H diff --git a/scenes/components.h b/scenes/components.h index 08d119c..de2761b 100644 --- a/scenes/components.h +++ b/scenes/components.h @@ -155,10 +155,12 @@ typedef struct _CSprite_t { sprite_transition_func_t transition_func; sprite_sfx_func_t sfx_func; unsigned int current_idx; + + // Legacy frame count. Keep for backwards compat and convenience int current_frame; - float fractional; + FrameTimer anim_timer; + float rotation_speed; // Degree / s - int elapsed; Vector2 offset; uint8_t depth; bool pause; diff --git a/scenes/constants.h b/scenes/constants.h index f196917..8e9f463 100644 --- a/scenes/constants.h +++ b/scenes/constants.h @@ -56,4 +56,6 @@ static const uint8_t CONNECTIVITY_TILE_MAPPING[16] = { 7,6,11,10, 4,5,8 ,9 , }; + +#define ANIM_FRAME_RATE (1.0f/24) #endif // __CONSTANTS_H diff --git a/scenes/game_systems.c b/scenes/game_systems.c index f655fd1..37a4a7f 100644 --- a/scenes/game_systems.c +++ b/scenes/game_systems.c @@ -2100,32 +2100,18 @@ void sprite_animation_system(Scene_t* scene) if (reset) { - p_cspr->fractional = 0; - p_cspr->elapsed = 0; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, spr.sprite->speed, spr.sprite->frame_count); + reset_frame_timer(&p_cspr->anim_timer); p_cspr->current_frame = 0; } if (spr.sprite->speed == 0) continue; // Animate it (handle frame count) - p_cspr->fractional += scene->delta_time; - const float ANIM_FRAME_RATE = 1.0f/24; - if (p_cspr->fractional > ANIM_FRAME_RATE) - { - p_cspr->fractional -= ANIM_FRAME_RATE; - p_cspr->elapsed++; - if (p_cspr->elapsed == spr.sprite->speed) - { - p_cspr->elapsed = 0; - if (!p_cspr->pause) - { - p_cspr->current_frame++; - p_cspr->current_frame %= spr.sprite->frame_count; - } - if (p_cspr->sfx_func != NULL) { - p_cspr->sfx_func(scene->engine, p_ent); - } - } + elapse_frame_time(&p_cspr->anim_timer, scene->delta_time); + p_cspr->current_frame = p_cspr->anim_timer.frame_count; + if (p_cspr->anim_timer.has_elapsed && p_cspr->sfx_func != NULL) { + p_cspr->sfx_func(scene->engine, p_ent); } } } diff --git a/scenes/items_ent.c b/scenes/items_ent.c index c64f1ce..4bbce94 100644 --- a/scenes/items_ent.c +++ b/scenes/items_ent.c @@ -76,6 +76,7 @@ Entity_t* create_crate(EntityManager_t* ent_manager, bool metal, ContainerItem_t p_cspr->sprites = item_sprite_map; p_cspr->node.scale = (Vector2){1, 1}; p_cspr->node.colour = WHITE; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, item_sprite_map[p_cspr->current_idx].sprite->speed, item_sprite_map[p_cspr->current_idx].sprite->frame_count); { CContainer_t* p_container = add_component(p_crate, CCONTAINER_T); @@ -129,6 +130,8 @@ Entity_t* create_boulder(EntityManager_t* ent_manager) p_cspr->node.colour = WHITE; p_cspr->depth = 2; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, item_sprite_map[p_cspr->current_idx].sprite->speed, item_sprite_map[p_cspr->current_idx].sprite->frame_count); + return p_boulder; } @@ -153,7 +156,8 @@ Entity_t* create_arrow(EntityManager_t* ent_manager, uint8_t dir) p_cspr->current_idx = 2; p_cspr->node.scale = (Vector2){1, 1}; p_cspr->node.colour = WHITE; - //p_hitbox->boxes[0] = (Rectangle){TILE_SIZE - 5, TILE_SIZE / 2 - 5, 5, 5}; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, item_sprite_map[p_cspr->current_idx].sprite->speed, item_sprite_map[p_cspr->current_idx].sprite->frame_count); + const int HITBOX_LONG_SIDE = 10; const int HITBOX_SHORT_SIDE = 4; const int CENTER_POSITION = (TILE_SIZE - HITBOX_SHORT_SIDE) >> 1; @@ -207,6 +211,7 @@ Entity_t* create_bomb(EntityManager_t* ent_manager, Vector2 launch_dir) p_cspr->current_idx = 6; p_cspr->node.scale = (Vector2){1, 1}; p_cspr->node.colour = WHITE; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, item_sprite_map[p_cspr->current_idx].sprite->speed, item_sprite_map[p_cspr->current_idx].sprite->frame_count); CTransform_t* p_ctransform = add_component(p_bomb, CTRANSFORM_COMP_T); p_ctransform->active = true; @@ -243,6 +248,7 @@ Entity_t* create_explosion(EntityManager_t* ent_manager) p_cspr->node.scale = (Vector2){1, 1}; p_cspr->node.colour = WHITE; p_cspr->depth = 3; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, item_sprite_map[p_cspr->current_idx].sprite->speed, item_sprite_map[p_cspr->current_idx].sprite->frame_count); CLifeTimer_t* p_clifetimer = add_component(p_explosion, CLIFETIMER_T); p_clifetimer->life_time = 0.05f; @@ -285,6 +291,7 @@ Entity_t* create_urchin(EntityManager_t* ent_manager) p_cspr->node.scale = (Vector2){1, 1}; p_cspr->node.colour = WHITE; p_cspr->depth = 2; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, item_sprite_map[p_cspr->current_idx].sprite->speed, item_sprite_map[p_cspr->current_idx].sprite->frame_count); add_component(p_urchin, CSQUISHABLE_T); @@ -317,6 +324,7 @@ Entity_t* create_chest(EntityManager_t* ent_manager) p_cspr->node.scale = (Vector2){1, 1}; p_cspr->node.colour = WHITE; p_cspr->depth = 2; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, item_sprite_map[p_cspr->current_idx].sprite->speed, item_sprite_map[p_cspr->current_idx].sprite->frame_count); return p_chest; @@ -332,6 +340,7 @@ Entity_t* create_level_end(EntityManager_t* ent_manager) p_cspr->current_idx = 20; p_cspr->node.scale = (Vector2){1, 1}; p_cspr->node.colour = WHITE; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, item_sprite_map[p_cspr->current_idx].sprite->speed, item_sprite_map[p_cspr->current_idx].sprite->frame_count); add_component(p_flag, CTILECOORD_COMP_T); return p_flag; diff --git a/scenes/player_ent.c b/scenes/player_ent.c index 4661a43..cdb6dc8 100644 --- a/scenes/player_ent.c +++ b/scenes/player_ent.c @@ -140,6 +140,7 @@ Entity_t* create_player(EntityManager_t* ent_manager) p_cspr->node.colour = WHITE; p_cspr->node.scale = (Vector2){1, 1}; p_cspr->depth = 1; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, player_sprite_map[p_cspr->current_idx].sprite->speed, player_sprite_map[p_cspr->current_idx].sprite->frame_count); CEmitter_t* p_emitter = add_component(p_ent, CEMITTER_T); p_emitter->offset = (Vector2){7,0}; @@ -165,6 +166,7 @@ Entity_t* create_dead_player(EntityManager_t* ent_manager) p_cspr->node.colour = WHITE; p_cspr->node.scale = (Vector2){1, 1}; p_cspr->depth = 3; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, player_sprite_map[p_cspr->current_idx].sprite->speed, player_sprite_map[p_cspr->current_idx].sprite->frame_count); add_component(p_ent, CMOVEMENTSTATE_T); @@ -195,6 +197,7 @@ Entity_t* create_player_finish(EntityManager_t* ent_manager) p_cspr->node.colour = WHITE; p_cspr->node.scale = (Vector2){1, 1}; p_cspr->depth = 1; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, player_sprite_map[p_cspr->current_idx].sprite->speed, player_sprite_map[p_cspr->current_idx].sprite->frame_count); CLifeTimer_t* p_clifetimer = add_component(p_ent, CLIFETIMER_T); p_clifetimer->life_time = 0.9f; diff --git a/scenes/scene_systems.c b/scenes/scene_systems.c index 2655362..651f543 100644 --- a/scenes/scene_systems.c +++ b/scenes/scene_systems.c @@ -70,6 +70,8 @@ void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* t p_cspr->node.scale = (Vector2){1, 1}; p_cspr->node.colour = WHITE; p_cspr->depth = 2; + set_frame_timings(&p_cspr->anim_timer, ANIM_FRAME_RATE, water_sprite_map[p_cspr->current_idx].sprite->speed, water_sprite_map[p_cspr->current_idx].sprite->frame_count); + assert(p_cspr != NULL); data->water_surface_spr_cidx = comp_idx;