EcsR3 is a reactive take on the common ECS pattern with a well separated design using R3 and adhering to IoC and other sensible design patterns.
This is basically EcsRx but natively using R3 rather than Rx
- Simple ECS interfaces and implementations to use/extend
- Fully reactive architecture
- Favours composition over inheritance
- Adheres to inversion of control
- Lightweight codebase
- Built in support for events (raise your own and react to them)
- Built in Dependency Injection abstraction layer
- Built in support for plugins (wrap up your own components/systems/events and share them with others)
It is advised to look at the setup docs, this covers the 2 avenues to setup the application using it without the helper libraries, or with the helper libraries which offer you dependency injection and other benefits.
However here are some quick code examples:
public class HealthComponent : IComponent
{
public int CurrentHealth { get; set; }
public int MaxHealth { get; set; }
}
You implement the IComponent
interface which marks the class as a component, and you can optionally implement IDisposable
if you want to dispose stuff like so:
public class HealthComponent : IComponent, IDisposable
{
public ReactiveProperty<int> CurrentHealth { get; set; }
public int MaxHealth { get; set; }
public HealthComponent()
{ CurrentHealth = new ReactiveProperty<int>(); }
public void Dispose()
{ CurrentHealth.Dispose; }
}
Any component which is marked with IDisposable
will be auto disposed of by entities.
public class CheckForDeathSystem : IReactToEntitySystem
{
public IGroup TargetGroup => new Group(typeof(HealthComponent)); // Get any entities with health component
public Observable<IEntity> ReactToEntity(IEntity entity) // Explain when you want to execute
{
var healthComponent = entity.GetComponent<HealthComponent>();
return healthComponent.CurrentHealth.Where(x => x <= 0).Select(x => entity);
}
public void Process(IEntity entity) // Logic run whenever the above reaction occurs
{
entity.RemoveComponent<HealthComponent>();
entity.AddComponent<IsDeadComponent>();
}
}
public class SayHelloSystem : IBasicSystem
{
// Triggered every time the IUpdateScheduler ticks (default 60 fps)
public void Execute(ElapsedTime elapsedTime)
{
Console.WriteLine($"System says hello @ {elapsedTime.TotalTime.ToString()}");
}
}
public class ReactToPlayerDeadEventSystem : IReactToEventSystem<PlayerDeadEvent>
{
// Triggered when the IEventSystem gets a PlayerDeadEvent
public void Process(PlayerDeadEvent eventData)
{
Console.WriteLine("Oh no the player has died");
}
}
public class StartGameManualSystem : IManualSystem
{
// Triggered when the system is first registered
public void StartSystem()
{
Console.WriteLine("Game Has Started");
}
// Triggered when the system is removed/stopped
public void StopSystem()
{
Console.WriteLine("Game Has Ended");
}
}
There are many other kinds of systems built in and available via plugins, so check docs for more information on that.
The architecture is layered so you can use the core parts without needing the additional layers if you want to keep things bare bones.
This creates a basic ISystem
convention with an ISystemExecutor
and IConventionalSystemHandler
implementations to provide basic systems interfaces (As shown in quick start above).
While this can be used alone for basic systems you can build your own conventions on top of here, such as EcsR3
which adds an ECS paradigm on top of SystemsRx.
This is layered on top of SystemsR3 and adds the ECS paradigm to the framework as well as adding a couple of systems specifically for entity handling. This also contains an EcsR3.Infrastructure layer which builds off the SystemsR3.Infrastructure layer to provide additional ECS related infrastructure.
There is a book available which covers the main parts which can be found here:
This is basically just the docs folder in a fancy viewer
This can all be found within the docs here