make behaviors aware of being unpaused

Thu, 09 Oct 2025 19:15:02 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 09 Oct 2025 19:15:02 +0200
changeset 278
634fa2996d4e
parent 277
9988e327176f
child 279
97a1a7fb4f1a

make behaviors aware of being unpaused

demo/snake/snake.c file | annotate | diff | comparison | revisions
src/ascension/behavior.h file | annotate | diff | comparison | revisions
src/behavior.c file | annotate | diff | comparison | revisions
--- a/demo/snake/snake.c	Thu Oct 09 19:03:32 2025 +0200
+++ b/demo/snake/snake.c	Thu Oct 09 19:15:02 2025 +0200
@@ -192,9 +192,7 @@
 }
 
 static void game_over_text_keep_centered(AscBehavior *behavior) {
-    if (!asc_active_window->resized) return;
-
-    // TODO: if we could react on some sort of "unhidden" event, we could pause this behavior while hidden
+    if (!behavior->unpaused && !asc_active_window->resized) return;
 
     AscSceneNode *node = behavior->node;
     // center the "game over" text in the game field viewport
@@ -207,16 +205,16 @@
 
 static AscSceneNode *game_over_create_text(void) {
     AscSceneNode *node = asc_text(
-            .name = "game_over_text",
-            .text = "Game Over\nPress R to Restart",
-            .color = ASC_RGB(1, 1, 1),
-            .font = asc_font(ASC_FONT_REGULAR, 36),
-            .alignment = ASC_TEXT_ALIGN_CENTER,
-            .centered = true,
-        );
+        .name = "game_over_text",
+        .text = "Game Over\nPress R to Restart",
+        .color = ASC_RGB(1, 1, 1),
+        .font = asc_font(ASC_FONT_REGULAR, 36),
+        .alignment = ASC_TEXT_ALIGN_CENTER,
+        .centered = true,
+    );
 
     asc_scene_node_hide(node);
-    asc_behavior_add(node, game_over_text_keep_centered);
+    asc_behavior_add(node, game_over_text_keep_centered, .pause_while_hidden = true);
     asc_ui_add_node(node);
 
     return node;
--- a/src/ascension/behavior.h	Thu Oct 09 19:03:32 2025 +0200
+++ b/src/ascension/behavior.h	Thu Oct 09 19:15:02 2025 +0200
@@ -43,6 +43,9 @@
     asc_behavior_func func;
     asc_behavior_destroy_func destroy_func;
     void *data;
+    /**
+     * Game tick of the last execution (zero when the behavior was not yet executed).
+     */
     uint64_t last_execution;
     uint64_t interval;
     cxmutstr name;
@@ -50,6 +53,10 @@
     bool always_enabled;
     bool enabled;
     bool killed;
+    /**
+     * Indicates whether the next execution is the first execution after the behavior has been disabled temporarily.
+     */
+    bool unpaused;
 };
 
 struct asc_behavior_create_args {
--- a/src/behavior.c	Thu Oct 09 19:03:32 2025 +0200
+++ b/src/behavior.c	Thu Oct 09 19:15:02 2025 +0200
@@ -63,6 +63,7 @@
     behavior->enabled = !args.start_disabled;
     behavior->always_enabled = args.always_enabled;
     behavior->killed = false;
+    behavior->unpaused = false;
     behavior->node = node;
     behavior->func = args.func;
     behavior->destroy_func = args.destroy_func;
@@ -82,11 +83,23 @@
 }
 
 void asc_behavior_trigger(AscBehavior *behavior) {
-    if (!behavior->enabled) return;
-    if (behavior->last_execution + behavior->interval > asc_context.total_nanos) return;
-    if (!behavior->always_enabled && behavior->pause_while_hidden && asc_scene_node_is_hidden(behavior->node)) return;
+    // the behavior is not enabled at the moment
+    if (!behavior->enabled) {
+        behavior->unpaused = true;
+        return;
+    }
+    // the behavior is not scheduled for execution
+    if (behavior->last_execution + behavior->interval > asc_context.total_nanos) {
+        return;
+    }
+    // the behavior is paused while the node is hidden
+    if (!behavior->always_enabled && behavior->pause_while_hidden && asc_scene_node_is_hidden(behavior->node)) {
+        behavior->unpaused = true;
+        return;
+    }
 
     behavior->func(behavior);
+    behavior->unpaused = false;
     behavior->last_execution = asc_context.total_nanos;
 }
 

mercurial