Démarrage rapide
Cette page présente le modèle SIECS. Elle suppose que siecs.h et siecs.c
sont déjà intégrés dans votre application ; consultez Compiler et
intégrer pour les deux parcours supportés.
SIECS utilise C17 pour le runtime et C++20 pour le wrapper typé. Les deux API pilotent le même monde actif.
Le monde possède toutes les entités, composants, requêtes, systèmes, ressources et observateurs. Initialisez-le avant toute opération typée et détruisez-le lorsque l’application s’arrête.
ecs_init();
/* Créer des entités, enregistrer les systèmes, exécuter des frames. */
ecs_fini();ecs::init();
// Créer des entités, enregistrer les systèmes, exécuter des frames.
ecs::fini();Les handles appartiennent à ce monde. Ne conservez ni entité ni pointeur de
composant après ecs_fini().
Entités et composants
Section intitulée « Entités et composants »Une entité est une identité. Les composants sont les données attachées à cette identité. Déclarez les données une fois, enregistrez-les en C, puis ajoutez-les aux entités.
ECS_COMPONENT(Position, { float x; float y; });ECS_COMPONENT(Velocity, { float x; float y; });ECS_TAG(Enemy);
ECS_COMPONENT_REGISTER(Position);ECS_COMPONENT_REGISTER(Velocity);ECS_COMPONENT_REGISTER(Enemy);
ecs_entity_t enemy = ecs_new();ecs_set(enemy, Position, { 10.0f, 20.0f });ecs_set(enemy, Velocity, { 1.0f, 0.0f });ecs_add(enemy, Enemy);struct Position { float x, y; };struct Velocity { float x, y; };struct Enemy {};
auto enemy = ecs::entity::create() .set(Position{ 10.0f, 20.0f }) .set(Velocity{ 1.0f, 0.0f }) .add<Enemy>();set ajoute le composant s’il est absent. get suppose sa présence ; utilisez
try_get lorsqu’une absence est valide.
Systèmes
Section intitulée « Systèmes »Un système est un callback de requête nommé. SIECS l’invoque pour chaque lot non vide d’entités correspondantes lorsque la phase sélectionnée est exécutée.
static void Move(ecs_iter_t *it) { Position *position = ecs_field(it, 0); const Velocity *velocity = ecs_field(it, 1);
for (uint32_t i = 0; i < it->count; i++) { position[i].x += velocity[i].x; position[i].y += velocity[i].y; }}
ecs_system({ .name = "Move", .phase = EcsOnUpdate, .query.components = { ecs_inout(Position), ecs_in(Velocity) }, .callback = Move,});ecs::system("Move") .phase(EcsOnUpdate) .each([](Position &position, const Velocity &velocity) { position.x += velocity.x; position.y += velocity.y; });Exécutez une frame avec ecs_progress() ou ecs::progress(). La requête d’un
système est persistante : c’est le choix normal pour le travail répété.
Requêtes
Section intitulée « Requêtes »Utilisez une requête lorsque vous devez parcourir les données hors d’un système. Les termes expriment des composants obligatoires, optionnels, filtrés, exclus, hérités ou relationnels.
ecs_query_id_t moving = ecs_query({ .components = { ecs_inout(Position), ecs_in_optional(Velocity) },});
ecs_iter_t it = ecs_query_iter(moving);while (ecs_iter_next(&it)) { Position *position = ecs_field(&it, 0); const Velocity *velocity = ecs_field(&it, 1); for (uint32_t i = 0; i < it.count; i++) { if (velocity) position[i].x += velocity[i].x; }}ecs_query_fini(moving);auto moving = ecs::query() .require<Position>() .optional<Velocity>() .build_handle();
moving.each([](Position &position, ecs::optional<const Velocity> velocity) { if (velocity) position.x += velocity->x;});Un champ optionnel est présent ou absent pour tout le lot. Ne gardez pas les
pointeurs de champs à travers un changement structurel comme add ou remove.
Ressources
Section intitulée « Ressources »Une ressource est une valeur typée unique pour tout le monde. Utilisez-la pour le temps, la configuration, l’entrée, le rendu ou tout état partagé.
ECS_RESOURCE(Time, { float dt; });ECS_RESOURCE_REGISTER(Time);
ecs_set_resource(Time, { .dt = 1.0f / 60.0f });const Time *time = ecs_get_resource_read(Time);struct Time { float dt; };
ecs::set_resource(Time{ 1.0f / 60.0f });const Time &time = ecs::resource<Time>();Les ressources ne sont pas des composants d’entité et ne deviennent pas des
champs de requête. Un système C++ peut demander ecs::res<const Time>.
Relations et héritage
Section intitulée « Relations et héritage »Les relations connectent les entités. ChildOf, intégré, modélise une
hiérarchie ; les relations personnalisées modélisent des liens comme GroupOf.
ecs_entity_t parent = ecs_new();ecs_entity_t child = ecs_new();
ecs_relate(child, ChildOf, parent);ecs_entity_t current_parent = ecs_target(child, ChildOf);auto parent = ecs::entity::create();auto child = ecs::entity::create().child_of(parent);
auto current_parent = child.target<ecs::ChildOf>();L’héritage construit des bases abstraites réutilisables avec
IsA. Les requêtes en lecture voient une valeur héritée ; les requêtes en
écriture exigent un remplacement local.
Observateurs
Section intitulée « Observateurs »Les observateurs réagissent à un événement précis au lieu de s’exécuter à chaque frame. Les événements intégrés couvrent l’ajout, le retrait et l’écriture de composants, ainsi que les transitions de relations.
static void OnPositionSet(ecs_observer_event_t *event) { const Position *value = event->trigger_data; printf("x = %f\n", value->x);}
ecs_observer({ .on = EcsOnSet, .query.components = { ecs_in(Position) }, .callback = OnPositionSet,});ecs::observe<ecs::OnSet>().each([](const Position &position) { std::printf("x = %f\n", position.x);});Les payloads d’observateurs sont empruntés pendant le callback. Utilisez-les immédiatement, sans conserver de pointeur vers les données d’événement.