Created
April 2, 2024 08:06
-
-
Save ArnCarveris/ff3fc75889123ad3866ef54ae3a72f69 to your computer and use it in GitHub Desktop.
Revisions
-
ArnCarveris created this gist
Apr 2, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,318 @@ #include <https://raw.githubusercontent.com/SanderMertens/flecs/master/flecs.h> #include <https://raw.githubusercontent.com/SanderMertens/flecs/master/flecs.c> #include <https://gist.github.com/ArnCarveris/535cf7c25007271bfa75d6396853a4a3/raw/99b57783a906995b4b89c4fb8d053c0ed2981603/flecs_godbolt.h> typedef struct { float x, y; } Position, Velocity; typedef struct { float time; } Timer; typedef struct { ecs_query_t *q; ecs_entity_t parent; ecs_iter_t it; int i; int j; char n; } ecs_enum_t; // Forward declare component so we can use it from functions other than main ECS_COMPONENT_DECLARE(Position); ECS_COMPONENT_DECLARE(Velocity); ECS_COMPONENT_DECLARE(Timer); ECS_TAG_DECLARE(IsAction); ECS_TAG_DECLARE(IsRunning); ECS_TAG_DECLARE(IsFailed); ECS_TAG_DECLARE(IsSucceeded); ecs_enum_t ecs_enum_new( ecs_world_t *ecs, ecs_query_t *q, ecs_entity_t e) { ecs_enum_t self; self.q = q; self.parent = e; self.it = ecs_query_iter(ecs, self.q); ecs_query_set_group(&self.it, e); self.i = 0; self.j = 0; self.n = 1; return self; } void ecs_enum_reset(ecs_enum_t* self) { self->it = ecs_query_iter(self->it.world, self->q); ecs_query_set_group(&self->it, self->parent); self->i = 0; self->j = 0; self->n = 1; } int ecs_enum_next(ecs_enum_t* self) { if (self->n) { self->n = 0; self->j = 0; if (!ecs_query_next(&self->it)) return 0; } self->i = self->j++; if (self->i < self->it.count) return 1; self->n = 1; return ecs_enum_next(self); } ecs_entity_t ecs_enum_entity(ecs_enum_t* self) { return self->it.entities[self->i]; } void print_tab(int tab) { for(int i = 0; i <= tab; ++i) printf(" "); } void print_entity(int tab, ecs_world_t *ecs, ecs_entity_t e) { char *path_str = ecs_get_fullpath(ecs, e); char *type_str = ecs_type_str(ecs, ecs_get_type(ecs, e)); print_tab(tab); printf("#%d %s [%s] ", e, path_str, type_str); ecs_os_free(type_str); ecs_os_free(path_str); } void print_tree(int tab, ecs_world_t *ecs, ecs_query_t* q, ecs_entity_t e) { // Print hierarchical name of entity & the entity type print_entity(tab, ecs, e); printf("\n"); ++tab; // Iterate children recursively for (ecs_enum_t i = ecs_enum_new(ecs, q, e); ecs_enum_next(&i);) { print_tree(tab, ecs, q, ecs_enum_entity(&i)); } } void ecs_bt_remove_states(ecs_world_t *world, ecs_entity_t target, ecs_entity_t action) { ecs_remove_pair(world, target, IsRunning, action); ecs_remove_pair(world, target, IsFailed, action); ecs_remove_pair(world, target, IsSucceeded, action); } void ecs_bt_change_state(ecs_world_t *world, ecs_entity_t target, ecs_entity_t state) { ecs_entity_t action = ecs_get_target(world, target, IsRunning, 1); if (action == 0) action = ecs_get_target(world, target, IsRunning, 0); if (action == 0) return; ecs_remove_pair(world, target, IsRunning, action); ecs_add_pair(world, target, state, action); //printf("ecs_bt_change_state: #%d action: ", target); print_entity_name(world, action); //printf(" state: "); print_entity_name(world, state); printf("\n"); } int ecs_bt_first(ecs_enum_t* self, ecs_world_t *world, ecs_entity_t target) { if (!ecs_enum_next(self)) return 0; ecs_entity_t action = ecs_enum_entity(self); ecs_add_pair(world, target, EcsIsA, action); ecs_add_pair(world, target, IsRunning, action); return 1; } int ecs_bt_next(ecs_enum_t* self, ecs_world_t *world, ecs_entity_t target, ecs_entity_t action) { ecs_remove_pair(world, target, EcsIsA, action); ecs_bt_remove_states(world, target, action); if (!ecs_enum_next(self)) return 0; action = ecs_enum_entity(self); ecs_add_pair(world, target, EcsIsA, action); ecs_add_pair(world, target, IsRunning, action); return 1; } void ecs_bt_parent(ecs_enum_t* self, ecs_world_t *world, ecs_entity_t target, ecs_entity_t state) { ecs_bt_remove_states(world, target, self->parent); ecs_add_pair(world, target, state, self->parent); } ecs_entity_t ecs_bt_sequence(ecs_enum_t* self, ecs_world_t *world, ecs_entity_t target) { ecs_entity_t state = IsFailed; if (self->n) { if (ecs_bt_first(self, world, target)) state = IsRunning; } else { ecs_entity_t action = ecs_enum_entity(self); if (ecs_has_pair(world, target, EcsIsA, action)) { if (ecs_has_pair(world, target, IsRunning, action)) state = IsRunning; else if (ecs_has_pair(world, target, IsSucceeded, action)) if (ecs_bt_next(self, world, target, action)) state = IsRunning; else state = IsSucceeded; } else { if (ecs_bt_first(self, world, target)) state = IsRunning; } } ecs_bt_parent(self, world, target, state); if (state == IsSucceeded) ecs_enum_reset(self); return state; } void print_bt(int tab, ecs_world_t* ecs, ecs_query_t* q, ecs_entity_t behaviour, ecs_entity_t agent, int ticks, float dt) { ecs_enum_t bt = ecs_enum_new(ecs, q, behaviour); for (int i = 0; i < ticks; ++i) { printf("\n -~> %d/%d \n", i+1, ticks); ecs_bt_sequence(&bt, ecs, agent); print_entity(tab, ecs, agent); ecs_progress(ecs, dt); } } void Move(ecs_iter_t *it) { Position *p = ecs_field(it, Position, 1); Velocity *v = ecs_field(it, Velocity, 2); for (int i = 0; i < it->count; i++) { p[i].x += v[i].x; p[i].y += v[i].y; printf("Move(%f, %f)\n", p[i].x, p[i].y); ecs_bt_change_state(it->real_world, it->entities[i], IsSucceeded); } } void Wait(ecs_iter_t *it) { Timer *t = ecs_field(it, Timer, 1); for (int i = 0; i < it->count; i++) { t[i].time -= it->delta_time; printf("Wait(%f)\n", t[i].time); if (t[i].time > 0) continue; ecs_bt_change_state(it->world, it->entities[i], IsSucceeded); //FIXME: it should be automatically removed on (IsA) bc `Timer` component is overriden ecs_remove(it->world, it->entities[i], Timer); } } int main(int argc, char *argv[]) { ecs_world_t *ecs = ecs_init_for_godbolt(argc, argv); ECS_COMPONENT_DEFINE(ecs, Position); ECS_COMPONENT_DEFINE(ecs, Velocity); ECS_COMPONENT_DEFINE(ecs, Timer); ECS_TAG_DEFINE(ecs, IsAction); ECS_TAG_DEFINE(ecs, IsRunning); ECS_TAG_DEFINE(ecs, IsFailed); ECS_TAG_DEFINE(ecs, IsSucceeded); ECS_SYSTEM(ecs, Move, EcsOnUpdate, Position, Velocity); ECS_SYSTEM(ecs, Wait, EcsOnUpdate, Timer); ecs_query_t* q = ecs_query(ecs, { .filter.terms = { { .id = ecs_pair(EcsChildOf, EcsWildcard) }, { .id = EcsPrefab, .oper = EcsOptional } }, .group_by_id = EcsChildOf, .order_by = flecs_entity_compare, }); ecs_entity_t seq = ecs_new_prefab(ecs, "Seq"); { ecs_entity_t move = ecs_new_prefab(ecs, "1Move"); ecs_add_pair(ecs, move, EcsChildOf, seq); ecs_add_pair(ecs, Move, IsAction, move); ecs_set(ecs, move, Velocity, {1, 1}); } { ecs_entity_t wait = ecs_new_prefab(ecs, "2Wait"); ecs_add_pair(ecs, wait, EcsChildOf, seq); ecs_add_pair(ecs, Wait, IsAction, wait); ecs_set(ecs, wait, Timer, {1}); ecs_override(ecs, wait, Timer); } { ecs_entity_t move = ecs_new_prefab(ecs, "3Move"); ecs_add_pair(ecs, Move, IsAction, move); ecs_add_pair(ecs, move, EcsChildOf, seq); ecs_set(ecs, move, Velocity, {-3, 3}); } printf("actions: \n"); print_tree(0, ecs, q, Move); print_tree(0, ecs, q, Wait); printf("behaviours: \n"); print_tree(0, ecs, q, seq); printf("agents: \n"); ecs_entity_t agent = ecs_new_entity(ecs, "Agent"); ecs_set(ecs, agent, Position, {10, 20}); print_bt(0, ecs, q, seq, agent, 20, 0.5); printf("\nfini: \n"); return ecs_fini(ecs); }