Skip to content

noahspoling/gramarye-ecs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gramarye-ecs

Generic Entity Component System framework for the Gramarye game engine.

Overview

gramarye-ecs provides a flexible, generic ECS framework where games can register their own component types and systems. It's designed to be game-agnostic, allowing different game types (top-down, FPS, etc.) to implement their own components and systems.

Features

  • Generic entity management with UUID-based entity IDs
  • Dynamic component type registration
  • System registration with component requirements
  • Query utilities for entity iteration
  • Arena-based memory management
  • Zero dependencies beyond gramarye-libcore

Usage

Basic Setup

#include "gramarye_ecs/ecs.h"
#include "arena.h"

Arena_T arena = Arena_new();
ECS* ecs = ECS_new(arena);

// Register component types
ComponentTypeId positionType = ECS_register_component_type(ecs, "Position", sizeof(Position));
ComponentTypeId healthType = ECS_register_component_type(ecs, "Health", sizeof(Health));

// Create entities
EntityId player = ECS_create_entity(ecs);
EntityId enemy = ECS_create_entity(ecs);

// Add components
Position pos = {100, 200};
ECS_add_component(ecs, player, positionType, &pos);

Health hp = {100, 100};
ECS_add_component(ecs, player, healthType, &hp);

// Register systems
SystemId movementSystem = ECS_register_system(ecs, "Movement", 
    (ComponentTypeId[]){positionType}, 1,
    movement_update, NULL);

// Update systems
ECS_update_systems(ecs, deltaTime);

Architecture

Entity System

Entities are managed via the EntityRegistry:

  • UUID-based IDs: Entities use 128-bit UUIDs (high/low 64-bit pairs) for unique identification
  • Component Tracking: Each entity tracks its component set as a 64-bit bitmask
  • Lifecycle: Entities are created via Entity_create() and destroyed via Entity_destroy()
  • Existence Checking: Entity_exists() verifies an entity is still valid

Entity IDs are compared and hashed using UUID comparison/hashing functions from gramarye-libcore.

Component System

Components are stored per type in separate ComponentStorage structures:

  • Type Registration: Components are registered with a name and size via ECS_register_component_type()
  • Type IDs: Each component type gets a unique ComponentTypeId (starting at 1, 0 is invalid)
  • Storage: Each component type has its own Table mapping EntityId → component data
  • Name Lookup: Component types can be looked up by name (O(n) operation - consider adding name→ID mapping if needed)
  • Component Sets: Each entity tracks which components it has via a bitmask for fast queries

Important: Component type names must be unique. Duplicate names will return COMPONENT_TYPE_INVALID.

System System

Systems are registered with component requirements and update functions:

  • Component Requirements: Systems specify which components entities must have
  • Priority: Systems can be registered with priorities for execution order
  • Execution Order: Systems are sorted by priority before execution (lower priority = earlier execution)
  • Enabled/Disabled: Systems can be enabled or disabled at runtime
  • Update Function: Each system provides an update function that receives ECS, deltaTime, and userData

System execution uses insertion sort by priority. Systems with the same priority execute in registration order.

Query System

The query system provides utilities for finding entities by component types:

  • AND Queries: Find entities with ALL specified components (ECS_query_entities)
  • OR Queries: Find entities with ANY specified components (ECS_query_entities_any)
  • Exclusion Queries: Find entities WITHOUT specified components (ECS_query_entities_excluding)
  • Iteration: Iterate over entities matching component requirements (ECS_iterate_entities)

Query Behavior:

  • AND/OR queries only check entities that have at least one component
  • Exclusion queries check ALL entities, including those without components
  • Queries use the component bitmask for fast filtering

Memory Management

  • Arena-based: All allocations use the provided Arena
  • No Manual Cleanup: Tables and arenas are managed externally - cleanup is handled by arena deallocation
  • Component Data: Component data is copied when added (not stored by reference)

Dependencies

  • gramarye-libcore (for Table, Arena, UUID hashing, etc.)

Building

mkdir build
cd build
cmake ..
make

Integration

This library is designed to be used as a submodule in game projects. Games register their own component types and systems at initialization, making the ECS framework completely generic and reusable.

About

ECS Implementation for gramarye

Resources

Stars

Watchers

Forks

Packages

No packages published