Skip to content

Lightweight framework for managing game entities and coordination systems. Provides a structured way to register, track, and update entities through a centralized EntityManager, and orchestrate their behavior with modular systems via the Orchestrator. Built to allow traditional inheritance hierarchies while providing structured approach like ECS.

License

Notifications You must be signed in to change notification settings

Lurler/TrimKit.EntityOrchestration

Repository files navigation

TrimKit.EntityOrchestration

TrimKit.EntityOrchestration provides a lightweight, dependency-free way to manage entities and systems in a structured and deterministic manner - bridging the gap between classic OOP approach and modern ECS patterns.

You might ask, But isn't this just another ECS implementation?

Not quite - there's no "C" here. You work with traditional inheritance hierarchies and rich object models, just like in classic OOP design.

The problem with that traditional approach, however, is scalability: once your project grows, reasoning about behavior and dependencies quickly becomes painful. ECS frameworks solve this by enforcing rigid data decomposition - but at the cost of constant micromanagement, boilerplate, and a steep learning curve.

In short, Entity Orchestration aims to strike the balance somewhere in the middle.

It gives you rigid structure, determinism, and modularity of an ECS-style approach - but without forcing your game into hundreds of micro-components. You keep your natural inheritance hierarchies, while gaining predictable update flow and a unified orchestration layer that keeps everything tidy and maintainable.

Features

  • Deterministic and order-based system execution
  • Strict or flexible entity categorization
  • Type-safe queries for entities by registered types
  • Collections can be modified during execution freely
  • No external dependencies

Installation

Use provided nuget package or download the source.

NuGet

🔧 dotnet add package TrimKit.EntityOrchestration

Quick start

First, create the entity manager and register types you want to separate entities into (this also allows you to query them by type).

var entityManager = new EntityManager(strict: true)	
    .RegisterType<Character>()
	.RegisterType<Player>() // inherits from Character
    .RegisterType<Enemy>() // Inherits from Character
	.RegisterType<Prop>();

entityManager.Initialize();

Add and query entities.

// add some entities
entityManager.Add(new Player("Player 1"));
entityManager.Add(new Enemy("Rat"));
entityManager.Add(new Enemy("Orc"));
entityManager.Add(new Prop("Rock"));

// get entities of type Player (in our case just one)
var players = entityManager.GetByType<Player>();

// this will return two enemies
var enemies = entityManager.GetByType<Enemy>();

// this will return both: player AND enemies, since they both inherit from Character
var characters = entityManager.GetByType<Character>();

Now, let's use EntityManager together with Orchestrator.

First, let's create a system.

public class MovementSystem : BaseSystem
{
    public override void OnUpdate(EntityManager em, GameContext ctx)
    {
        // example logic
        var players = em.GetByType<Player>();
        // ...
    }
}

And then register it.

// we create orchestrator with GameContext and pass our existing entityManager into the constructor
var orchestrator = new Orchestrator<GameContext>(entityManager);

// next we can define some systems and initialize
orchestrator.AddSystem<MovementSystem>()
			.AddSystem<CombatSystem>()
			.AddSystem<AnotherSystem>()
			.AddSystem<WhateverSystem>()
		    .Initialize();

Finally, simply call Update in your game loop and pass your game context, so systems can access what they need.

orchestrator.Update(gameContext);

API Overview

EntityManager

Method / Property Description
EntityManager(bool strict = false) Creates a new manager; in strict mode only registered types are allowed.
EntityManager RegisterType<T>() Registers a base entity type for categorization.
void Initialize() Locks registration and enables runtime operations.
void Add(BaseEntity entity) Adds an entity and associates it with matching registered types.
void Remove(BaseEntity entity) Removes an entity from all collections.
void RemoveDeleted() Removes entities marked as deleted.
void RemoveAll() Clears all entities.
IReadOnlyList<BaseEntity> GetAll(bool excludeDeleted = true) Returns all entities.
IReadOnlyList<T> GetByType<T>(bool excludeDeleted = true) Returns all entities of a specific type.
IReadOnlyList<BaseEntity> GetOther(bool excludeDeleted = true) Returns entities that don't match any registered type.
int Count(bool excludeDeleted = true) Returns total entity count.

Orchestrator

Method / Property Description
Orchestrator(EntityManager entityManager) Creates an orchestrator that manages systems sharing the same EntityManager.
Orchestrator<TContext> AddSystem<TSystem>() Registers a new system via reflection.
Orchestrator<TContext> AddSystem(BaseSystem system) Registers a new system with manual instance injection.
Orchestrator<TContext> Initialize() Initializes all registered systems.
void Update(TContext context) Executes all active systems sequentially.
Orchestrator<TContext> SetSystemState<TSystem>(bool active) Enables or disables a specific system.
bool IsInitialized Indicates whether the orchestrator is initialized.

Notes

  • The orchestrator executes systems in the order they are added.
  • You must initialize both EntityManager and Orchestrator before using them.
  • Deactivated systems (Active = false) are automatically skipped.
  • EntityManager strict mode ensures strong type control for clean separation and no entities getting into the "other" bucket.
  • You can actually use EntityManager separately without Orchestrator.

Performance

This library is great for small to medium projects, but the fact of difference in performance compared to pure ECS is not lost on me. If you need to iterate over tens of thousands entities every frame and do that FAST you should stick with ECS. There's a reason ECS paradigm exists and is so popular - you just can't beat it in terms of performance. But for everything else... nah.

Changes

  • v1.0 - Initial release.

TrimKit Collection

This library is part of the TrimKit collection - a set of small, focused C# libraries that make game development more enjoyable by reducing the need for boilerplate code and providing simple reusable building blocks that can be dropped into any project.

Each module is independent and can be used standalone or combined with others for a complete lightweight foundation.

Contribution

Contributions are welcome!

You can start with submitting an issue on GitHub.

License

This library is released under the MIT License.

About

Lightweight framework for managing game entities and coordination systems. Provides a structured way to register, track, and update entities through a centralized EntityManager, and orchestrate their behavior with modular systems via the Orchestrator. Built to allow traditional inheritance hierarchies while providing structured approach like ECS.

Topics

Resources

License

Stars

Watchers

Forks

Languages