Giter VIP home page Giter VIP logo

ecslite's Introduction

Translated with Claude AI

LeoEcsLite - Lightweight C# Entity Component System framework

Performance, zero or minimal allocations, memory usage minimization, no dependencies on any game engine - these are the main goals of this framework.

IMPORTANT! Do not forget to use DEBUG builds for development and RELEASE builds for releases: all internal checks/exceptions will work only in DEBUG builds and removed to increase performance in RELEASE builds.

IMPORTANT! The LeoEcsLite framework is not thread safe and will never be! If you need multithreading - you should implement it yourself and integrate synchronization as an ecs system.

Table of Contents

Social Resources

discord

Installation

As Unity Module

Installation as Unity module via git url in PackageManager or directly editing Packages/manifest.json is supported:

"com.leopotam.ecslite": "https://github.com/Leopotam/ecslite.git",

By default the latest release version is used. If you need "in development" version with latest changes - you should switch to develop branch:

"com.leopotam.ecslite": "https://github.com/Leopotam/ecslite.git#develop",

As Source Code

The code can also be cloned or downloaded as archive from releases page.

Other Sources

The official working version is hosted on https://github.com/Leopotam/ecslite, any other versions (including nuget, npm and other repositories) are unofficial clones or 3rd party code with unknown contents.

IMPORTANT! Using these sources is not recommended, only at your own risk.

Core Types

Entity

Does not have any meaning by itself and does not exist, is exclusively a container for components. Implemented as int:

// Create new entity in world.
int entity = _world.NewEntity ();

// Any entity can be destroyed, all components will be automatically removed first and only after that entity will be considered as destroyed.
world.DelEntity (entity); 

// Components from any entity can be copied to another one. If source or destination entities do not exist - exception will be thrown in DEBUG mode.  
world.CopyEntity (srcEntity, dstEntity);

IMPORTANT! Entities can not exist without components and will be automatically destroyed on removal of the last component.

Component

Is a container for user data and should not contain logic (minimal helpers are allowed, but not big pieces of core logic):

struct Component1 {
    public int Id;
    public string Name;
}

Components can be added, requested or removed through component pools.

System

Is a container for core processing logic for filtered entities. Exists as a custom class, implementing one or more of IEcsInitSystem, IEcsDestroySystem, IEcsRunSystem (and other supported) interfaces:

class UserSystem : IEcsPreInitSystem, IEcsInitSystem, IEcsRunSystem, IEcsPostRunSystem, IEcsDestroySystem, IEcsPostDestroySystem {
    public void PreInit (IEcsSystems systems) {
        // Will be called once on IEcsSystems.Init() before IEcsInitSystem.Init() triggered on any system.
    }
    
    public void Init (IEcsSystems systems) {
        // Will be called once on IEcsSystems.Init() after IEcsPreInitSystem.PreInit() triggered on all systems.
    }
    
    public void Run (IEcsSystems systems) {
        // Will be called once on IEcsSystems.Run().
    }
    
    public void PostRun (IEcsSystems systems) {
        // Will be called once on IEcsSystems.Run() after IEcsRunSystem.Run() triggered on all systems.
    }

    public void Destroy (IEcsSystems systems) {
        // Will be called once on IEcsSystems.Destroy() before IEcsPostDestroySystem.PostDestroy() triggered on any system.
    }
    
    public void PostDestroy (IEcsSystems systems) {
        // Will be called once on IEcsSystems.Destroy() after IEcsDestroySystem.Destroy() triggered on all systems.
    }
}

Shared Data

Any custom type (class) instance can be injected into all systems simultaneously:

class SharedData {
    public string PrefabsPath;
}
...
SharedData sharedData = new SharedData { PrefabsPath = "Items/{0}" };
IEcsSystems systems = new EcsSystems (world, sharedData);
systems
    .Add (new TestSystem1 ())
    .Init ();
...
class TestSystem1 : IEcsInitSystem {
    public void Init(IEcsSystems systems) {
        SharedData shared = systems.GetShared<SharedData> ();
        string prefabPath = string.Format (shared.PrefabsPath, 123);
        // prefabPath = "Items/123" at this point. 
    }
}

Special Types

EcsPool

Is a container for components, provides api for adding / requesting / removing components on entities:

int entity = world.NewEntity ();
EcsPool<Component1> pool = world.GetPool<Component1> ();

// Add() adds component to entity. If component already exists - exception will be thrown in DEBUG mode. 
ref Component1 c1 = ref pool.Add (entity);

// Has() checks if entity has component.
bool c1Exists = pool.Has (entity);

// Get() returns existing component on entity. If component does not exist - exception will be thrown in DEBUG mode.
ref Component1 c1 = ref pool.Get (entity); 

// Del() removes component from entity. No errors if component did not exist. If it was last component - entity will be removed automatically.
pool.Del (entity);

// Copy() copies all components from one entity to another. If source or destination entities do not exist - exception will be thrown in DEBUG mode.
pool.Copy (srcEntity, dstEntity);

IMPORTANT! After removal, component will be put to pool for reuse. All component fields will be reset to default values automatically.

EcsFilter

Is container for storing filtered entities by required or excluded components:

class WeaponSystem : IEcsInitSystem, IEcsRunSystem {
    EcsFilter _filter;
    EcsPool<Weapon> _weapons;
    
    public void Init (IEcsSystems systems) {
        // Get default world instance.
        EcsWorld world = systems.GetWorld ();
        
        // We want all entities with "Weapon" component and without "Health" component.
        // Filter stores only entities, data itself resides in "Weapon" component pool.
        // Filter can be rebuilt dynamically each time, but caching is recommended. 
        _filter = world.Filter<Weapon> ().Exc<Health> ().End ();
        
        // Request and cache weapons pool.
        _weapons = world.GetPool<Weapon> ();
        
        // Create new entity for test.
        int entity = world.NewEntity ();
        
        // And add "Weapon" component to it - this entity should appear in filter.
        _weapons.Add (entity);
    }

    public void Run (IEcsSystems systems) {
        foreach (int entity in filter) {
            ref Weapon weapon = ref _weapons.Get (entity);
            weapon.Ammo = System.Math.Max (0, weapon.Ammo - 1); 
        }
    }
}

IMPORTANT! It's enough to build filter once and cache it, rebuild to update entity list is not required.

Additional include/exclude constraints can be added via Inc<>() / Exc<>() methods.

IMPORTANT! Filters support any number of component constraints, but same component can not be in both include and exclude lists.

EcsWorld

Is a container for all entities, component pools and filters, each instance data is unique and isolated from other worlds.

IMPORTANT! EcsWorld.Destroy() should be called on world instance if it's no more needed.

EcsSystems

Is a container for systems that will process EcsWorld instance:

class Startup : MonoBehaviour {
    EcsWorld _world;
    IEcsSystems _systems;

    void Start () {
        // Create environment, connect systems.
        _world = new EcsWorld ();
        _systems = new EcsSystems (_world);
        _systems
            .Add (new WeaponSystem ())
            .Init ();
    }
    
    void Update () {
        // Run all connected systems.
        _systems?.Run (); 
    }

    void OnDestroy () {
        // Destroy connected systems.
        if (_systems != null) {
            _systems.Destroy ();
            _systems = null;
        }
        // Cleanup environment.
        if (_world != null) {
            _world.Destroy ();
            _world = null;
        }
    }
}

IMPORTANT! IEcsSystems.Destroy() should be called on system group instance if it's no more needed.

Engine Integration

Unity

Tested on Unity 2020.3 (not dependent on it) and contains asmdef setup for compilation as separate asm to reduce main project recompilation time.

Unity editor integration provides code templates and world state monitoring.

Custom Engine

C#7.3 or later required for framework usage.

Each part of example below should be correctly integrated in proper execution place of engine code:

using Leopotam.EcsLite;

class EcsStartup {
    EcsWorld _world;
    IEcsSystems _systems;

    // Environment initialization.
    void Init () {        
        _world = new EcsWorld ();
        _systems = new EcsSystems (_world);
        _systems
            // Additional world instances 
            // should be registered here.
            // .AddWorld (customWorldInstance, "events")
            
            // Systems with core logic should
            // be registered here.
            // .Add (new TestSystem1 ()) 
            // .Add (new TestSystem2 ())
            
            .Init ();
    }

    // Method should be called from
    // main update loop of engine. 
    void UpdateLoop () {
        _systems?.Run ();
    }

    // Environment cleanup.
    void Destroy () {
        if (_systems != null) {
            _systems.Destroy ();
            _systems = null;
        }
        if (_world != null) {
            _world.Destroy ();
            _world = null;
        }
    }
}

Articles

LeoECS Lite Based Projects

With Source Code

Without Source Code

Extensions

License

Framework released under two licenses, details here.

In case of MIT-Red licensing do not expect any personal support or guarantees.

FAQ

What is the difference from old LeoECS version?

I prefer calling them lite (ecs-lite) and classic (leoecs). Main lite differences:

  • Framework codebase reduced by 2 times, it became easier to support and extend.
  • Lite is not a stripped down version of classic, all functionality preserved in form of core and external modules.
  • No any static data inside core.
  • No component caches inside filters, it reduces memory usage and increases entity rearrange speed between filters.
  • Fast access to any component on any entity (not only filtered one through filter cache).
  • No limits on component requirements/constraints for filters.
  • Common linear performance close to classic, but component access, entity rearrange between filters became extremely faster.
  • Aiming on multi-world usage - running multiple world instances simultaneously to optimize memory usage by splitting data between them.
  • No reflection inside core, aggressive code stripping by compiler (code stripping, dead code elimination) possible.
  • Shared data injection between systems works without reflection (if allowed, it's recommended to use `ecsl

ecslite's People

Contributors

leopotam avatar alvinsay avatar

ecslite's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.