EcsBase 1.0.0

dotnet add package EcsBase --version 1.0.0
                    
NuGet\Install-Package EcsBase -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EcsBase" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EcsBase" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="EcsBase" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EcsBase --version 1.0.0
                    
#r "nuget: EcsBase, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EcsBase@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EcsBase&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=EcsBase&version=1.0.0
                    
Install as a Cake Tool

GitHub License NuGet Version

EcsBase

A minimalist starting point for using ECS in C#.

🧠 The Idea

ECS libraries tend to come with a list of features,
which is what the library maintainer(s) deem useful.
However, these lists varying greatly between libraries shows there is no "silver bullet".

Instead, the idea for EcsBase is:

  1. Add this library via NuGet and start developing.
  2. Use it through a wrapper or a replacement for EcsService and start developing.
  3. When reaching EcsBase's limits, copy its files and quickly understand and modify them.

Now, let's go through those steps!

📦 1. Add the Package

dotnet add package EcsBase

🚀 2. Use the Library

2.1 Add the EcsBase namespace 🏷️

using EcsBase;

2.2 Create a world 🌍

var ecsService = EcsService<int>.Create();

This creates a new EcsService, which contains a World, a ChangeBuffer, and a QueryExecutor.
We are using int as the key type here - this is what is usually called the "entity".

2.3 Add an Entity 👤

ecsService
    .ChangeBuffer
    .AddEntity(7)
    .WithComponent(new Transform2D { Position = new Vector2(1.0f, 3.0f) });

ecsService.ChangeBuffer.ApplyChanges();

Identifiers
Note that you are responsible for providing a unique key for each entity
(hardcoded to 7 in this example).

Component Types
Components can be any class or struct, really.
Of course, structs would have a performance advantage,
but see the section about performance further down.

ChangeBuffer
The actual lists of components should not be changed while iterating over it.
⚠️ Note: There are no built-in protections that prevent you from doing this! ⚠️
That is why ChangeBuffer comes with an ApplyChanges() method.
This will actually apply any changes that are requested via its other methods.

So, call ChangeBuffer.ApplyChanges() at the beginning or end of a frame and you're good.

2.4 Execute a query 🚀

public class MyQuery : IQuery<int, Transform2D>
{
	public void Execute(Span<int> e, Span<Transform2D> component1Span)
	{
		for (int i = 0; i < e.Length; i++)
		{
			component1Span[i].Position.X++;
		}
	}
}

var myQuery = new MyQuery();
ecsService.Queries.Execute<MyQuery, Transform2D, ComponentB>(myQuery);

The first generic type parameter of IQuery is the key type,
the rest defines which components an entity needs to have to be part of the query.

🏗️ 3. Modify the Library

🗂️ File Overview

  • Component state
    • Chunk holds a somewhat memory-optimized collection of components
    • ChunkList holds multiple chunks, and creates new chunks when necessary
    • Archetype is basically just a collection of types
    • World manages a ChunkList per Archetype, and keeps track of entities
  • Editing entities
    • EntityBuilder is a fluent interface to create entities
    • ChangeBuffer helps with delaying changes to the start or end of a frame
  • Querying
    • IQuery contains 9 variations (1-9 component parameters) of the query interface
    • QueryExecutor contains 9 methods to run these queries
  • And finalle
    • EcsService ties it all together as a common entry point

"Features"

🦺 Safe

No unsafe code. I have seen this advertised as a bonus.
To be honest, I do not know where that would come into play -
but yeah, there is no direct memory-wrangling involved.

🤏 Minimalism

The entire code is in 9 files, all but one smaller than 200 lines of code.
The library is only 35Kb in size (not that this would be unexpected for, well, 9 files).

It can arguably not even be called an "Entity/Component/System" library,
because there is no system (IQuery hardly qualifies).
It's not an ECS, just an "EC".

Strike that, an entity is not provided either.
You can freely choose what to use as entity via the TKey generic parameter.
int, long, Guid - or just any class.
So it's not an ECS, just a "C"... wouldn't that be a confusing name.

🏎️ Performance

Performance is somewhat of an afterthought here.

Components inside a Chunk are stored contiguously per component,
and which ChunkLists are applicable for a specific combination of components is cached.

I'm simply not making the type of game where I need to process 100 000 entities per frame.

Anyway, 3 different queries over different combinations of components on 100 000 entities
take about 100 microseconds on my machine. (See the EcsBase.Benchmarks project.)

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 113 10/25/2024
0.0.1-alpha 90 10/25/2024