Skip to content

Fixed Tick Rate Timer - #2102

Open
jknightdoeswork wants to merge 8 commits into
SanderMertens:masterfrom
jknightdoeswork:feature/multi-tick
Open

Fixed Tick Rate Timer#2102
jknightdoeswork wants to merge 8 commits into
SanderMertens:masterfrom
jknightdoeswork:feature/multi-tick

Conversation

@jknightdoeswork

@jknightdoeswork jknightdoeswork commented May 16, 2026

Copy link
Copy Markdown

Adds a new set of methods allowing a 'fixed interval' timer to be created and managed.

Core new method is

ecs_set_fixed_interval(world, entity_id, fixed_interval)

This PR adjusts tick sources to be able to tick multiple times per pipeline run with a fixed delta time.

Addresses this issue.

I think this should improve the ergonomics of defining a core game loop that requires parts of the pipeline to run at a fixed interval.

I think this test demonstrates the core difference:

void Timer_fixed_interval(void) {
    ecs_world_t *world = ecs_init();

    ecs_entity_t timer = ecs_set_fixed_interval(world, 0, 0.5);

    ecs_progress(world, 10.0);
    const EcsTickSource *src = ecs_get(world, timer, EcsTickSource);
    test_assert(src != NULL);
    test_int(src->ticks, 20.0); // with regular interval, this ticks once
    test_flt(src->time_elapsed, 0.5);   // with regular interval, this is 10.0

    ecs_fini(world);
}

Looking for discussion on this approach.

My understanding of the built in timer mechanism is that if you use it, you expose yourself to perhaps unexpected behavior if you progress a pipeline with a longer duration than 2.0*timer_interval. There is no built in mechanism from what I can tell in flecs that allows a system to be gaurenteed to be called with a fixed delta time.

This PR additively allows this key concept in a simulation loop to be expressed elegantly using the built in flecs pipeline and timers APIs.

My instinct is that this should be the default mechanics of timers, but this is written to be backwards compatible, and does not change timers or systems at all unless the new fixed_interval set of APIs are used.

Let me know if I'm missing something or my understanding is incorrect!

Thanks for the awesome library!

}
ecs_entity_t old_system = flecs_stage_set_system(stage, system);
ecs_entity_t interrupted_by = 0;
for (uint32_t i = 0; i < num_ticks; i++) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference here is that the system is called in a loop, once per num_ticks.

action(&qit);
ecs_iter_fini(&qit);
}
interrupted_by = it->interrupted_by;

@jknightdoeswork jknightdoeswork May 16, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The most recent interrupted_by is returned - not sure if this is precisely the intent of interrupted by.

Comment thread src/addons/timer.c

if (timer[i].single_shot) {
timer[i].active = false;
if (timer[i].fixed_interval) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if fixed_interval is false, the semantics are exactly the same as before.

Comment thread src/addons/timer.c
system_data->tick_source = timer;
}

error:

@jknightdoeswork jknightdoeswork May 16, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Full disclosure: I directly copy'd this error label pattern without precisely tracking where the error can be jumped from. I will review this personally more precisely before merging but requesting comment.

Comment thread src/addons/timer.c
if (system_data) {
system_data->tick_source = timer;
}
error:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above regarding not precisely understanding this error pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant