LeoEcsLite Documentation

repository·master·Indexed 18 days ago

https://github.com/leopotam/ecslite

A lightweight C# Entity Component System (ECS) framework designed for high performance, minimal memory allocation, and zero dependencies on game engines. It features a modular architecture using EcsWorld for entity and component management, EcsPool for component storage, and EcsFilter for entity selection. Version 2026.4.25. Note: Support for this project has ended; EcsProto is recommended for new projects.

Tokens
5.1K
Snippets
15
Records
18
Agent score
18%

What's inside LeoEcsLite

  1. Important usage notes for LeoEcsLite

    master

    Before using LeoEcsLite, be aware of the following critical constraints:

    • Maintenance Status: Support for this project has ended. It is in a stable state with no known bugs, but it is recommended to use EcsProto instead.
    • Build Configurations: Use DEBUG builds during development to enable internal checks and exceptions. Use RELEASE builds for production to remove these checks for maximum performance.
    • Thread Safety: LeoEcsLite is not thread-safe. If you require multi-threading, you must implement it yourself and integrate synchronization via an ECS system.
    • Official Sources: The only official working version is at https://github.com/Leopotam/ecslite. Other sources like NuGet or NPM are unofficial clones and should be used at your own risk.
  2. What is a Component in LeoEcsLite?

    master

    A Component is a container for user data. It should ideally be a struct and should not contain main logic (though minimal helpers are allowed). Components are managed through EcsPool.

    struct Component1 {
        public int Id;
        public string Name;
    }
  3. What is a System in LeoEcsLite?

    master

    A System is a user-defined class that contains the logic for processing filtered entities. Systems implement one or more lifecycle interfaces to hook into the EcsSystems execution flow.

    class UserSystem : IEcsPreInitSystem, IEcsInitSystem, IEcsRunSystem, IEcsPostRunSystem, IEcsDestroySystem, IEcsPostDestroySystem {
        public void PreInit (IEcsSystems systems) {
            // Called once during IEcsSystems.Init() before other systems' Init()
        }
        
        public void Init (IEcsSystems systems) {
            // Called once during IEcsSystems.Init() after other systems' PreInit()
        }
        
        public void Run (IEcsSystems systems) {
            // Called once during IEcsSystems.Run()
        }
        
        public void PostRun (IEcsSystems systems) {
            // Called once during IEcsSystems.Run() after all systems' Run()
        }
    
        public void Destroy (IEcsSystems systems) {
            // Called once during IEcsSystems.Destroy() before other systems' PostDestroy()
        }
        
        public void PostDestroy (IEcsSystems systems) {
            // Called once during IEcsSystems.Destroy() after all systems' Destroy()
        }
    }
  4. What is an Entity in LeoEcsLite?

    master

    An Entity is a container for components. It does not exist independently and is implemented simply as an int.

    Key behaviors:

    • Creation: Use world.NewEntity() to create a new entity.
    • Deletion: Use world.DelEntity(entity) to destroy an entity. All components attached to it are automatically removed first.
    • Copying: Use world.CopyEntity(srcEntity, dstEntity) to copy all components from one entity to another.
    • Lifecycle: Entities cannot exist without components; an entity is automatically destroyed if its last component is removed.
    // Create a new entity in the world.
    int entity = _world.NewEntity ();
    
    // Delete an entity (components are removed automatically first).
    world.DelEntity (entity);
    
    // Copy components from one entity to another.
    world.CopyEntity (srcEntity, dstEntity);
  5. How EcsFilter works to select entities

    master

    An EcsFilter is a container used to store and retrieve entities based on the presence or absence of specific components. You define a filter by chaining requirements:

    • .Filter<T>(): Includes entities that have component T.
    • .Inc<T>(): Includes entities that have component T (Include).
    • .Exc<T>(): Excludes entities that have component T (Exclude).
    • .End(): Finalizes the filter definition.

    Important Notes:

    • Filters should be built once and cached; they automatically update when entities change, so you do not need to rebuild them.
    • A single component cannot be present in both the 'include' and 'exclude' lists of the same filter.
    • The filter stores only the entity IDs; the actual component data is accessed via an EcsPool using the entity ID.
    // Example: Filter entities with 'Weapon' but without 'Health'
    _filter = world.Filter<Weapon>().Exc<Health>().End();
    
    // Usage in a system loop
    foreach (int entity in _filter) {
        ref Weapon weapon = ref _weapons.Get(entity);
        // Do something with weapon
    }
  6. Use EcsWorld to manage entities and components

    master

    An EcsWorld instance acts as the primary container for all entities, component pools, and filters. Data within an EcsWorld is unique and isolated from other worlds.

    Lifecycle Management:

    • You must call EcsWorld.Destroy() when the world is no longer needed to prevent memory leaks.
  7. Use EcsSystems to manage and run systems

    master

    The EcsSystems class manages a collection of systems that process the EcsWorld. It provides a structured way to initialize and execute the logic loop.

    Workflow:

    1. Create an EcsSystems instance passing in an EcsWorld.
    2. Use .Add(system) to register your systems.
    3. Call .Init() to initialize all registered systems.
    4. Call .Run() within your engine's main update loop to execute the systems.
    5. Call .Destroy() when finished to clean up the systems.

    Lifecycle Management:

    • You must call IEcsSystems.Destroy() when the system group is no longer needed.
    _world = new EcsWorld();
    _systems = new EcsSystems(_world);
    _systems
        .Add(new WeaponSystem())
        .Init();
    
    // In update loop:
    _systems.Run();
    
    // Cleanup:
    _systems.Destroy();
    _world.Destroy();
  8. How LeoEcsLite differs from LeoECS (Classic)

    master

    LeoEcsLite (the 'lite' version) is a redesigned, lightweight version of the original LeoECS. Key differences include:

    • Architecture: The codebase is significantly smaller and modular. Functionality is split between a core and optional external modules rather than being a stripped-down version of the classic engine.
    • Performance & Memory: It uses int for entities to reduce memory footprint. It removes component caches from filters to increase speed and reduce memory usage. It also avoids reflection in the core, allowing for better compiler code stripping.
    • Access: Provides faster access to any component on any entity, not just those within a filtered set.
    • Data Sharing: Systems share data without reflection (using extensions like ecslite-di is recommended).
    • Multi-world Support: Designed for using multiple EcsWorld instances simultaneously to optimize memory via data separation.
  9. How to share data between systems

    master

    You can provide a custom class instance (shared data) to all systems by passing it to the EcsSystems constructor. Systems can then retrieve this data using systems.GetShared<T>().

    class SharedData {
        public string PrefabsPath;
    }
    
    // Setup
    SharedData sharedData = new SharedData { PrefabsPath = "Items/{0}" };
    IEcsSystems systems = new EcsSystems (world, sharedData);
    systems.Add (new TestSystem1 ()).Init ();
    
    // Usage in a system
    class TestSystem1 : IEcsInitSystem {
        public void Init(IEcsSystems systems) {
            SharedData shared = systems.GetShared<SharedData> (); 
            string prefabPath = string.Format(shared.PrefabsPath, 123);
            // prefabPath = "Items/123"
        }
    }
  10. Integrate LeoECS Lite into a custom engine

    master

    To use LeoECS Lite in a custom C# engine, ensure you are using C# 7.3 or higher. You need to manually manage the lifecycle of the EcsWorld and EcsSystems within your engine's execution flow.

    using Leopotam.EcsLite;
    
    class EcsStartup {
        EcsWorld _world;
        IEcsSystems _systems;
    
        void Init () {
            _world = new EcsWorld ();
            _systems = new EcsSystems (_world);
            _systems
                // .AddWorld (customWorldInstance, "events") // Optional: Register additional worlds
                .Add (new TestSystem1 ())
                .Init ();
        }
    
        void UpdateLoop () {
            _systems?.Run ();
        }
    
        void Destroy () {
            if (_systems != null) {
                _systems.Destroy ();
                _systems = null;
            }
            if (_world != null) {
                _world.Destroy ();
                _world = null;
            }
        }
    }
  11. Store entity references in components using Packed Entities

    master

    Since entities are simple int types, you cannot safely store them directly in components if you need to verify if they still exist. Instead, wrap them in EcsPackedEntity or EcsPackedEntityWithWorld. When unpacking, these containers allow you to check if the entity is still valid.

    EcsWorld world = new EcsWorld ();
    int entity = world.NewEntity ();
    EcsPackedEntity packed = world.PackEntity (entity);
    EcsPackedEntityWithWorld packedWithWorld = world.PackEntityWithWorld (entity);
    
    // Unpacking with EcsPackedEntity
    if (packed.Unpack (world, out int unpacked)) {
        // "unpacked" is a valid entity
    }
    
    // Unpacking with EcsPackedEntityWithWorld
    if (packedWithWorld.Unpack (out EcsWorld unpackedWorld, out int unpackedWithWorld)) {
        // "unpackedWithWorld" is a valid entity
    }
  12. Run different ECS systems in MonoBehaviour.Update and FixedUpdate

    master

    To execute different sets of systems in Unity's Update and FixedUpdate methods, you must create separate IEcsSystems groups for each lifecycle method. Each group should be initialized with the same EcsWorld instance.

    IEcsSystems _update;
    IEcsSystems _fixedUpdate;
    
    void Start () {
        EcsWorld world = new EcsWorld ();
        _update = new EcsSystems (world);
        _update
            .Add (new UpdateSystem ())
            .Init ();
        _fixedUpdate = new EcsSystems (world);
        _fixedUpdate
            .Add (new FixedUpdateSystem ())
            .Init ();
    }
    
    void Update () {
        _update?.Run ();
    }
    
    void FixedUpdate () {
        _fixedUpdate?.Run ();
    }