gamestate: add optional Gamestate_Tick function for logic with fixed interval

This commit is contained in:
Sebastian Krzyszkowiak 2018-08-05 02:01:21 +02:00
parent 4c12939afe
commit 9953d3f171
No known key found for this signature in database
GPG key ID: E8F235CF3BDBC3FF
4 changed files with 35 additions and 27 deletions

View file

@ -26,6 +26,7 @@
struct Gamestate_API {
void (*Gamestate_Draw)(struct Game* game, void* data);
void (*Gamestate_Logic)(struct Game* game, void* data, double delta);
void (*Gamestate_Tick)(struct Game* game, void* data);
void* (*Gamestate_Load)(struct Game* game, void (*progress)(struct Game* game));
void (*Gamestate_PostLoad)(struct Game* game, void* data);

View file

@ -42,7 +42,7 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) {
}
struct Gamestate* tmp = game->_priv.gamestates;
if (game->handlers.predraw) {
(*game->handlers.predraw)(game);
game->handlers.predraw(game);
}
while (tmp) {
if ((tmp->loaded) && (tmp->started)) {
@ -51,7 +51,7 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) {
if (game->handlers.compositor) { // don't clear when uncomposited
al_clear_to_color(al_map_rgb(0, 0, 0)); // even if everything is going to be redrawn, it optimizes tiled rendering
}
(*tmp->api->Gamestate_Draw)(game, tmp->data);
tmp->api->Gamestate_Draw(game, tmp->data);
// TODO: save and restore more state for careless gamestating
}
tmp = tmp->next;
@ -71,24 +71,37 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) {
game->handlers.compositor(game, game->_priv.gamestates);
}
if (game->handlers.postdraw) {
(*game->handlers.postdraw)(game);
game->handlers.postdraw(game);
}
}
SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) {
struct Gamestate* tmp = game->_priv.gamestates;
if (game->handlers.prelogic) {
(*game->handlers.prelogic)(game, delta);
game->handlers.prelogic(game, delta);
}
while (tmp) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) {
game->_priv.current_gamestate = tmp;
(*tmp->api->Gamestate_Logic)(game, tmp->data, delta);
tmp->api->Gamestate_Logic(game, tmp->data, delta);
}
tmp = tmp->next;
}
if (game->handlers.postlogic) {
(*game->handlers.postlogic)(game, delta);
game->handlers.postlogic(game, 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->Gamestate_Tick) {
tmp->api->Gamestate_Tick(game, tmp->data);
}
}
tmp = tmp->next;
}
}
@ -99,7 +112,7 @@ SYMBOL_INTERNAL void ReloadGamestates(struct Game* game) {
if (tmp->loaded) {
game->_priv.current_gamestate = tmp;
if (tmp->api->Gamestate_Reload) {
(*tmp->api->Gamestate_Reload)(game, tmp->data);
tmp->api->Gamestate_Reload(game, tmp->data);
}
}
tmp = tmp->next;
@ -111,7 +124,7 @@ SYMBOL_INTERNAL void EventGamestates(struct Game* game, ALLEGRO_EVENT* ev) {
while (tmp) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) {
game->_priv.current_gamestate = tmp;
(*tmp->api->Gamestate_ProcessEvent)(game, tmp->data, ev);
tmp->api->Gamestate_ProcessEvent(game, tmp->data, ev);
}
tmp = tmp->next;
}
@ -215,7 +228,7 @@ SYMBOL_INTERNAL void* GamestateLoadingThread(void* arg) {
struct GamestateLoadingThreadData* data = arg;
data->game->_priv.loading.inProgress = true;
al_set_new_bitmap_flags(data->bitmap_flags);
data->gamestate->data = (*data->gamestate->api->Gamestate_Load)(data->game, &GamestateProgress);
data->gamestate->data = data->gamestate->api->Gamestate_Load(data->game, &GamestateProgress);
if (data->game->_priv.loading.progress != data->gamestate->progressCount) {
PrintConsole(data->game, "[%s] WARNING: Gamestate_ProgressCount does not match the number of progress invokations (%d)!", data->gamestate->name, data->game->_priv.loading.progress);
if (data->game->config.debug) {
@ -268,8 +281,8 @@ SYMBOL_INTERNAL void GamestateProgress(struct Game* game) {
DrawGamestates(game);
double delta = al_get_time() - game->_priv.loading.time;
if (game->_priv.loading.current->showLoading) {
(*game->_priv.loading.gamestate->api->Gamestate_Logic)(game, game->_priv.loading.gamestate->data, delta);
(*game->_priv.loading.gamestate->api->Gamestate_Draw)(game, game->_priv.loading.gamestate->data);
game->_priv.loading.gamestate->api->Gamestate_Logic(game, game->_priv.loading.gamestate->data, delta);
game->_priv.loading.gamestate->api->Gamestate_Draw(game, game->_priv.loading.gamestate->data);
}
game->_priv.loading.time += delta;
DrawConsole(game);
@ -311,6 +324,7 @@ SYMBOL_INTERNAL bool LinkGamestate(struct Game* game, struct Gamestate* gamestat
if (!(gamestate->api->Gamestate_ProcessEvent = dlsym(gamestate->handle, "Gamestate_ProcessEvent"))) { GS_ERROR; }
// optional
gamestate->api->Gamestate_Tick = dlsym(gamestate->handle, "Gamestate_Tick");
gamestate->api->Gamestate_PostLoad = dlsym(gamestate->handle, "Gamestate_PostLoad");
gamestate->api->Gamestate_Pause = dlsym(gamestate->handle, "Gamestate_Pause");
gamestate->api->Gamestate_Resume = dlsym(gamestate->handle, "Gamestate_Resume");

View file

@ -71,6 +71,7 @@ struct ScreenshotThreadData {
void SimpleCompositor(struct Game* game, struct Gamestate* gamestates);
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

@ -344,8 +344,6 @@ SYMBOL_EXPORT int libsuperderpy_run(struct Game* game) {
return 0;
}
bool redraw = false;
SYMBOL_INTERNAL void libsuperderpy_mainloop_exit(struct Game* game) {
libsuperderpy_destroy(game);
free(game);
@ -355,17 +353,13 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop_exit(struct Game* game) {
SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
struct Game* game = (struct Game*)g;
redraw = true;
while (!al_is_event_queue_empty(game->_priv.event_queue) || redraw) {
#else
bool redraw = false;
while (1) {
#endif
do {
ClearGarbage(game);
// TODO: split mainloop to functions to make it readable
ALLEGRO_EVENT ev;
if (game->_priv.draw && (((redraw || true) && al_is_event_queue_empty(game->_priv.event_queue)) || (game->_priv.gamestate_scheduled))) {
if (game->_priv.draw && ((al_is_event_queue_empty(game->_priv.event_queue)) || (game->_priv.gamestate_scheduled))) {
game->_priv.gamestate_scheduled = false;
struct Gamestate* tmp = game->_priv.gamestates;
@ -524,12 +518,13 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
LogicGamestates(game, delta);
DrawGamestates(game);
}
//redraw = true;
DrawConsole(game);
//al_wait_for_vsync();
al_flip_display();
redraw = false;
#ifdef __EMSCRIPTEN__
return;
#endif
} else {
#ifdef __EMSCRIPTEN__
@ -547,10 +542,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
}
if ((ev.type == ALLEGRO_EVENT_TIMER) && (ev.timer.source == game->_priv.timer)) {
/*double delta = al_get_time() - game->_priv.timestamp;
game->_priv.timestamp += delta;
LogicGamestates(game, delta);
redraw = true;*/
TickGamestates(game);
} else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
#ifdef __EMSCRIPTEN__
libsuperderpy_mainloop_exit(game);
@ -638,7 +630,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
}
EventGamestates(game, &ev);
}
}
} while (true);
#ifndef __EMSCRIPTEN__
if (game->handlers.destroy) {