don't use timer for ticking; rely on delta instead

Timer was causing an infinite loop in cases where ticking took
more time than 1/60 sec.
This commit is contained in:
Sebastian Krzyszkowiak 2019-01-08 04:53:13 +01:00
parent 8d4ee68936
commit d0316cd789
No known key found for this signature in database
GPG key ID: E8F235CF3BDBC3FF
5 changed files with 18 additions and 45 deletions

View file

@ -87,12 +87,19 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) {
SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) {
struct Gamestate* tmp = game->_priv.gamestates;
int ticks = floor((game->time + delta) / ALLEGRO_BPS_TO_SECS(60.0)) - floor(game->time / ALLEGRO_BPS_TO_SECS(60.0));
game->time += delta;
if (game->_priv.params.handlers.prelogic) {
game->_priv.params.handlers.prelogic(game, delta);
}
while (tmp) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused) && (!tmp->pending_stop)) {
game->_priv.current_gamestate = tmp;
if (tmp->api->tick) {
for (int i = 0; i < ticks; i++) {
tmp->api->tick(game, tmp->data);
}
}
tmp->api->logic(game, tmp->data, delta);
}
tmp = tmp->next;
@ -102,19 +109,6 @@ SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) {
}
}
SYMBOL_INTERNAL void TickGamestates(struct Game* game) {
struct Gamestate* tmp = game->_priv.gamestates;
while (tmp) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) {
game->_priv.current_gamestate = tmp;
if (tmp->api->tick) {
tmp->api->tick(game, tmp->data);
}
}
tmp = tmp->next;
}
}
SYMBOL_INTERNAL void ReloadGamestates(struct Game* game) {
struct Gamestate* tmp = game->_priv.gamestates;
ReloadShaders(game, true);
@ -576,7 +570,6 @@ SYMBOL_INTERNAL void PauseExecution(struct Game* game) {
return;
}
game->_priv.paused = true;
al_stop_timer(game->_priv.timer);
al_detach_voice(game->audio.v);
FreezeGamestates(game);
PrintConsole(game, "Engine halted.");
@ -612,7 +605,6 @@ SYMBOL_INTERNAL void ResumeExecution(struct Game* game) {
}
UnfreezeGamestates(game);
al_attach_mixer_to_voice(game->audio.mixer, game->audio.v);
al_resume_timer(game->_priv.timer);
game->_priv.paused = false;
game->_priv.timestamp = al_get_time();
PrintConsole(game, "Engine resumed.");

View file

@ -90,7 +90,6 @@ struct ScreenshotThreadData {
void SimpleCompositor(struct Game* game, struct Gamestate* gamestates, ALLEGRO_BITMAP* loading_fb);
void DrawGamestates(struct Game* game);
void LogicGamestates(struct Game* game, double delta);
void TickGamestates(struct Game* game);
void EventGamestates(struct Game* game, ALLEGRO_EVENT* ev);
void ReloadGamestates(struct Game* game);
void FreezeGamestates(struct Game* game);

View file

@ -96,6 +96,8 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
game->_priv.bsod_cond = al_create_cond();
game->_priv.bsod_mutex = al_create_mutex();
game->_priv.speed = ALLEGRO_BPS_TO_SECS(60.0);
game->_priv.mutex = al_create_mutex();
game->config.fullscreen = strtol(GetConfigOptionDefault(game, "SuperDerpy", "fullscreen", "1"), NULL, 10);
@ -338,16 +340,9 @@ SYMBOL_EXPORT int libsuperderpy_start(struct Game* game) {
al_register_event_source(game->_priv.event_queue, &(game->event_source));
al_clear_to_color(al_map_rgb(0, 0, 0));
game->_priv.timer = al_create_timer(ALLEGRO_BPS_TO_SECS(60)); // logic timer
if (!game->_priv.timer) {
FatalError(game, true, "Failed to create logic timer.");
return 1;
}
al_register_event_source(game->_priv.event_queue, al_get_timer_event_source(game->_priv.timer));
ReloadShaders(game, false);
al_flip_display();
al_start_timer(game->_priv.timer);
{
struct Gamestate* tmp = game->_priv.gamestates;
@ -471,7 +466,6 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) {
free(game->_priv.garbage->data);
game->_priv.garbage = game->_priv.garbage->next;
}
al_destroy_timer(game->_priv.timer);
Console_Unload(game);
al_destroy_display(game->display);
al_destroy_user_event_source(&(game->event_source));

View file

@ -195,10 +195,11 @@ struct Game {
char console[5][1024];
unsigned int console_pos;
ALLEGRO_EVENT_QUEUE* event_queue; /*!< Main event queue. */
ALLEGRO_TIMER* timer; /*!< Main LPS (logic) timer. */
bool showconsole; /*!< If true, game console is rendered on screen. */
bool showtimeline;
double speed; /*!< Speed of the game in FPS. 60 == 1x */
struct {
double old_time, fps, time;
int frames_done;

View file

@ -21,12 +21,6 @@
static inline void HandleEvent(struct Game* game, ALLEGRO_EVENT* ev) {
switch (ev->type) {
case ALLEGRO_EVENT_TIMER:
if (ev->timer.source == game->_priv.timer) {
TickGamestates(game);
}
break;
case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING:
PauseExecution(game);
al_acknowledge_drawing_halt(game->display);
@ -155,23 +149,23 @@ static inline void HandleDebugEvent(struct Game* game, ALLEGRO_EVENT* ev) {
}
break;
case ALLEGRO_KEY_F9:
al_set_timer_speed(game->_priv.timer, ALLEGRO_BPS_TO_SECS(60.0));
game->_priv.speed = ALLEGRO_BPS_TO_SECS(60.0);
game->_priv.showconsole = true;
PrintConsole(game, "DEBUG: Gameplay speed: 1.00x");
break;
case ALLEGRO_KEY_F10: {
double speed = ALLEGRO_BPS_TO_SECS(al_get_timer_speed(game->_priv.timer)); // inverting
double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting
speed -= 10;
if (speed < 10) { speed = 10; }
al_set_timer_speed(game->_priv.timer, ALLEGRO_BPS_TO_SECS(speed));
game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed);
game->_priv.showconsole = true;
PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0);
} break;
case ALLEGRO_KEY_F11: {
double speed = ALLEGRO_BPS_TO_SECS(al_get_timer_speed(game->_priv.timer)); // inverting
double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting
speed += 10;
if (speed > 600) { speed = 600; }
al_set_timer_speed(game->_priv.timer, ALLEGRO_BPS_TO_SECS(speed));
game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed);
game->_priv.showconsole = true;
PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0);
} break;
@ -274,16 +268,13 @@ static inline bool MainloopTick(struct Game* game) {
while (tmp) {
if (tmp->pending_unload) {
PrintConsole(game, "Unloading gamestate \"%s\"...", tmp->name);
al_stop_timer(game->_priv.timer);
tmp->loaded = false;
tmp->pending_unload = false;
game->_priv.current_gamestate = tmp;
(*tmp->api->unload)(game, tmp->data);
al_resume_timer(game->_priv.timer);
PrintConsole(game, "Gamestate \"%s\" unloaded successfully.", tmp->name);
}
if (tmp->pending_load) {
al_stop_timer(game->_priv.timer);
if (tmp->show_loading) {
(*game->_priv.loading.gamestate->api->start)(game, game->_priv.loading.gamestate->data);
}
@ -373,7 +364,6 @@ static inline bool MainloopTick(struct Game* game) {
game->loading.shown = false;
}
tmp->show_loading = true;
al_resume_timer(game->_priv.timer);
game->_priv.timestamp = al_get_time();
}
@ -394,13 +384,11 @@ static inline bool MainloopTick(struct Game* game) {
while (tmp) {
if ((tmp->pending_start) && (tmp->loaded)) {
PrintConsole(game, "Starting gamestate \"%s\"...", tmp->name);
al_stop_timer(game->_priv.timer);
game->_priv.current_gamestate = tmp;
tmp->started = true;
tmp->pending_start = false;
(*tmp->api->start)(game, tmp->data);
al_resume_timer(game->_priv.timer);
game->_priv.timestamp = al_get_time();
PrintConsole(game, "Gamestate \"%s\" started successfully.", tmp->name);
}
@ -420,8 +408,7 @@ static inline bool MainloopTick(struct Game* game) {
double delta = al_get_time() - game->_priv.timestamp;
game->_priv.timestamp += delta;
delta *= ALLEGRO_BPS_TO_SECS(al_get_timer_speed(game->_priv.timer) / (1 / 60.f));
game->time += delta;
delta *= ALLEGRO_BPS_TO_SECS(game->_priv.speed / (1 / 60.f));
#ifdef LIBSUPERDERPY_IMGUI
ImGui_ImplAllegro5_NewFrame();