-
-
Notifications
You must be signed in to change notification settings - Fork 102
Quickstart
I bet you dont wanna read tons of documentations, theory and other boring stuff right ?
Lets just ignore all that deep knowledge and jump in directly.
Entity Component System (ECS) is a software architectural pattern mostly used for the representation of game world objects or data oriented design in general. An ECS comprises entities composed from components of data, with systems or queries which operate on entities' components.
ECS follows the principle of composition over inheritance, meaning that every entity is defined not by a type hierarchy, but by the components that are associated with it.
The world acts as a management class for all its entities, it contains methods to create, destroy and query them and handles all the internal mechanics.
Therefore it is the most important class, you will use the world heavily.
Multiple worlds can be used in parallel, each instance and its entities are completly encapsulated from other worlds. Currently worlds and their content can not interact with each other, however this feature is already planned.
Worlds are created and destroyed like this...
var world = World.Create();
World.Destroy(world);
There can be up to 255 worlds in total.
A entity represents your game entity.
It is a simple struct with some metadata acting as a key to acess and manage its components.
public readonly struct Entity : IEquatable<Entity> {
public readonly int EntityId; // Its id/key in the world
public readonly byte WorldId; // The world the entity lives in
public readonly ushort Version; // Its version, how often the entity or its id was recycled
....
}
Entities are being created by a world and will "live" in the world in which they were created.
When an entity is being created, you need to specify the components it will have. Components are basically the additional data or structure the entity will have. This is called "Archetype".
var archetype = new []{ typeof(Position), typeof(Velocity), ... };
var entity = world.Create(archetype);
world.Destroy(in entity);
Components are data assigned to your entity. With them you define how an entity looks and behaves, they basically define the gamelogic with pure data.
Its recommended to use struct components since they offer better speed.
To ease writing code, you can acess the entity directly to modify its components or to check its metadata.
Lets take a look at the most important methods.
entity.IsAlive(); // True if the entity is still existing in its world
entity.Has<Position>(); // True if the entity has a position component
entity.Set(new Position( x = 10 )); // Replaces the position component and updates it data
entity.Get<Position>(); // Returns a reference to the entity position, can directly acess and update position attributes
entity.GetComponentTypes(); // Returns an array of its component types. Should be treated as readonly
entity.GetComponents(); // Returns an array of all its components, allocates memory.
With those utility methods you are able to implement your game logic.
A small example could look like this...
var archetype = new []{ typeof(Position), typeof(Velocity) };
var entity = world.Create(archetype);
ref var position = ref entity.Get<Position>(); // Get reference to the position
position.x++; // Update x
position.y++; // Update y
if(entity.Has<Position>()) // Make sure that entity has a position ( Optional )
entity.Set(new Position{ x = 10, y = 10 }; // Replaces the old position
Queries aka. Systems are used to iterate over a set of entities to apply logic and behaviour based on their components.
This is performed by using the world ( remember, it manages your created entities ) and by defining a description of which entities we want to iterate over.
// Define a description of which entities you want to query
var query = new QueryDescription {
All = new []{ typeof(Position), typeof(Velocity) }, // Should have all specified components
Any = new []{ typeof(Player), typeof(Projectile) }, // Should have any of those
None = new []{ typeof(AI) } // Should have none of those
};
// Execute the query
world.Query(in query, entity => { /* Do something */ });
// Execute the query and modify components in the same step, up to 10 generic components at the same time.
world.Query(in query, (ref Position pos, ref Velocity vel) => {
pos.x += vel.dx;
pos.y += vel.dy;
});
In the example above we want to move our entities based on their Position
and Velocity
components.
To perform this operation we need to iterate over all entities having both a Position
and Velocity
component (All
). We also want that our entity either is a Player
or a Projectile
(Any
). However, we do not want to iterate and perform that calculation on entities which are controlled by an AI
(None
).
The world.Query
method than smartly searches for entities having both a Position
and Velocity
, either a Player
or Projectile
and no AI
component and executes the defined logic for all of those fitting entities.
Its also important to know that there are multiple different overloads to perform such a query.
The less you query in terms of components and the size of components... the faster the query is !
world.Query(in query, entity => {}); // Passes the fitting entity
world.Query(in query, (ref T1 t1, T2 t2, ...) => {}) // Passes the defined components of the fitting entity, up to 10 components
world.Query(in query, (in Entity en, ref T1 t1, ref T2 t2, ...) => {}) // Passed the fitting entity and its defined components, up to 10 components
var filteredEntities = new List<Entity>();
var filteredArchetypes = new List<Archetype>();
var filteredChunks = new List<Chunk>();
world.GetEntities(query, filteredEntities); // Fills all fitting entities into the passed list
world.GetArchetypes(query, filteredArchetypes); // Fills all fitting archetypes into the list
world.GetChunks(query, filteredChunks); // Fills all fitting chunks into the list
Archetype's and Chunk's are internal structures of the world and store entities with the same component types. You will mostly never use them directly, therefore more on them later.
This is all you need to know, with this little knowledge you are already able to bring your worlds to life.
However, if you want to take a closer look at Arch and performance techniques :