|
co_ecs 0.9.0
Cobalt ECS
|

co_ecs is a header-only library implementing an Entity Component System.
Compilation requires compiler with C++ 20 support.
Tested compilers:
Before building targets create a build/ directory in the root of the source tree and cd into it:
Generate coverage report:
Coverage reports might be misleading when building in release mode, so make sure you build in debug mode or explicitly pass -DCMAKE_BUILD_TYPE=Debug.
Inside your build directory execute the following to install co_ecs:
This make target will install co_ecs headers into your system include directory.
Using FetchConent:
Component is any C++ type that satisfies the following:
struct or classnoexcept move constructiblenoexcept move assignableViews are used to iterate over entities in the registry with a specified set of components attached:
You don't need to worry about caching a view object returned by registry::view() because it is very inexpensive to create. The actual work of matching archetypes is done only when you start iterating over it using view::each().
Another way to iterate over relevant entities is by using registry::each(), which takes an invocable as a parameter that accepts component reference types:
co_ecs aims to provide a const-correct API. For example, a view with const references can only be created from a const registry reference:
Views are used to iterate over entities in the registry with a specified set of components attached:
You don't need to worry about caching a view object returned by registry::view() because it is very inexpensive to create. The actual work of matching archetypes is done only when you start iterating over it using view::each().
Another way to iterate over relevant entities is by using registry::each(), which takes an invocable as a parameter that accepts component reference types:
This kind of iteration might be even faster and better optimized by the compiler. The function can operate on a chunk that yields two tuples of pointers to the actual data, whereas the each() variant returns an iterator over iterators to the actual data, which is more challenging for the compiler to optimize. Refer to the benchmarks to see the actual performance difference. We look forward to compilers improving their optimization of <ranges> machinery to make the performance of these two variants match.
co_ecs aims to provide a const-correct API. For example, a view with const references can only be created from a const registry reference:
co_ecs aims to provide a safe API. For example, creating an entity and specifying the same component type more than once is ambiguous and causes undefined behavior. The following snippet will fail to compile:
The compiler will generate a static assertion error:
Another example is when mistakenly trying to assign a component of type co_ecs::entity. The co_ecs::entity structure is handled internally in the same way as components, but it is invalid to assign it as a component to an entity. When attempting the following:
The compiler will raise the following static assertion error:
This implies that you cannot have write access to the memory chunk where co_ecs::entity objects are stored.
The same error message appears when trying to create a co_ecs::view with read-write access to co_ecs::entity:
However, querying for const co_ecs::entity& is valid and the correct method to fetch entity IDs together with their components in the view:
Components are referenced internally by IDs. The component ID is generated statically, and the resulting ID is compiler implementation-defined. There should be no logic that relies on a specific ID value. Due to how ID generation works, there is a limitation that restricts placing components inside implementation files (*.cpp) or private headers.
Consider the following two components with the same name defined in two separate compilation units in the global namespace:
foo.cpp:
bar.cpp:
There is a high chance the compiler will generate the same ID for these two different structures, leading to undefined behavior. Therefore, it is recommended to place all components in public header files, or even in a single header file, to avoid name collisions.
co_ecs can be used across binary boundaries. For example, you can create an engine shared library with core components and then use the registry inside another shared library or executable that links to the engine. The core shared library should be compiled with CO_ECS_HOST defined, and the others must define CO_ECS_CLIENT.
engine.h:
engine.cpp:
client.cpp:
co_ecs is distributed under the MIT license.