# HG changeset patch # User Mike Becker # Date 1751576512 -7200 # Node ID cb2f60f48337e1bcc5192e27196125eb70290cf5 # Parent e5544920377eb5f4f631297df91050a34029ba9f add asc_behavior_remove() diff -r e5544920377e -r cb2f60f48337 src/ascension/behavior.h --- a/src/ascension/behavior.h Wed Jul 02 23:55:50 2025 +0200 +++ b/src/ascension/behavior.h Thu Jul 03 23:01:52 2025 +0200 @@ -44,6 +44,7 @@ uint64_t last_execution; uint64_t interval; bool enabled; + bool killed; // TODO: more useful attributes }; @@ -69,14 +70,39 @@ AscBehavior *asc_behavior_add_(AscSceneNode *node, struct asc_behavior_create_args args); #define asc_behavior_add(node,...) asc_behavior_add_(node, (struct asc_behavior_create_args){__VA_ARGS__}) -// TODO: asc_behavior_remove() +/** + * Removes and destroys a behavior. + * + * If you just want to temporarily pause a behavior, use asc_behavior_disable(). + * + * @param behavior the behavior to remove + * @see asc_behavior_disable() + */ +void asc_behavior_remove(AscBehavior *behavior); +/** + * Used internally. Do not invoke manually. + * + * @param behavior the behavior + */ void asc_behavior_trigger(AscBehavior *behavior); +/** + * Enables a behavior + * + * Has no effect on killed behaviors. + * + * @param behavior the behavior to enable + */ static inline void asc_behavior_enable(AscBehavior *behavior) { - behavior->enabled = true; + behavior->enabled = !behavior->killed; } +/** + * Disables a behavior. + * + * @param behavior the behavior to disable + */ static inline void asc_behavior_disable(AscBehavior *behavior) { behavior->enabled = false; } diff -r e5544920377e -r cb2f60f48337 src/behavior.c --- a/src/behavior.c Wed Jul 02 23:55:50 2025 +0200 +++ b/src/behavior.c Thu Jul 03 23:01:52 2025 +0200 @@ -55,6 +55,7 @@ AscBehavior *behavior = cxListEmplace(node->behaviors); assert(behavior != NULL); behavior->enabled = true; + behavior->killed = false; behavior->node = node; behavior->func = args.func; behavior->destroy_func = args.destroy_func; @@ -64,8 +65,14 @@ return behavior; } +void asc_behavior_remove(AscBehavior *behavior) { + // TODO: implement some sort of ID for behaviors which can also be used for logging + behavior->killed = true; + behavior->enabled = false; +} + void asc_behavior_trigger(AscBehavior *behavior) { - if (!behavior->enabled) return; + assert(behavior->enabled); if (behavior->last_execution + behavior->interval > asc_context.total_nanos) return; behavior->func(behavior); diff -r e5544920377e -r cb2f60f48337 src/context.c --- a/src/context.c Wed Jul 02 23:55:50 2025 +0200 +++ b/src/context.c Thu Jul 03 23:01:52 2025 +0200 @@ -198,8 +198,6 @@ } // compute frame time - // TODO: think about whether frame rate is actually a per-window thing - // the answer is hopefully NO, because that would mean behaviors are also a per-window thing uint64_t frame_nanos, ns; do { ns = asc_nanos(); diff -r e5544920377e -r cb2f60f48337 src/scene.c --- a/src/scene.c Wed Jul 02 23:55:50 2025 +0200 +++ b/src/scene.c Thu Jul 03 23:01:52 2025 +0200 @@ -58,6 +58,7 @@ cxListFree(scene->internal.render_groups[i]); scene->internal.render_groups[i] = NULL; } + // TODO: add names to scenes asc_dprintf("Destroyed scene %"PRIxPTR, (uintptr_t) scene); asc_scene_node_free(scene->root); } @@ -68,9 +69,14 @@ offsetof(AscSceneNode, next) ); cx_foreach(AscSceneNode*, node, iter) { - CxIterator behavior_iter = cxListIterator(node->behaviors); + CxIterator behavior_iter = cxListMutIterator(node->behaviors); cx_foreach(AscBehavior*, behavior, behavior_iter) { - asc_behavior_trigger(behavior); + if (behavior->enabled) { + asc_behavior_trigger(behavior); + } + if (behavior->killed) { + cxIteratorFlagRemoval(behavior_iter); + } } } } diff -r e5544920377e -r cb2f60f48337 src/text.c --- a/src/text.c Wed Jul 02 23:55:50 2025 +0200 +++ b/src/text.c Thu Jul 03 23:01:52 2025 +0200 @@ -125,6 +125,7 @@ return node; } +// TODO: maybe we should prefer a clean signature and molest the caller with the cast void asc_text_printf( AscSceneNode *node, const char *format, diff -r e5544920377e -r cb2f60f48337 test/snake/snake.c --- a/test/snake/snake.c Wed Jul 02 23:55:50 2025 +0200 +++ b/test/snake/snake.c Thu Jul 03 23:01:52 2025 +0200 @@ -105,6 +105,16 @@ asc_ui_add_node(node); } +static void update_score_counter(AscBehavior *behavior) { + AscSceneNode *node = behavior->node; + static unsigned test_score = 0; + test_score += 100; + asc_text_printf(node, "Score: %u", test_score); + if (test_score > 9000) { + asc_behavior_remove(behavior); + } +} + static void create_score_counter(void) { asc_font(ASC_FONT_BOLD, 16); asc_ink_rgb(0, 255, 0); @@ -113,6 +123,8 @@ .x = 10, .y = 10, .text = "Score: 0" ); + // TODO: remove this test behavior + asc_behavior_add(node, .func = update_score_counter, .interval = asc_milliseconds(250)); asc_ui_add_node(node); }