(sɛks)
a small ecs, written in c.
small entity-component-system written in C. The purpose of this project is 3-fold:
- brush up on c (again)
- wrap my head around entity-component-systems
- work using github flow
- ensure that make, gcc, pkg-config, libcheck and libyaml are installed
- clone the repo
- run
make components
to generate component c/h file - run
make
to build libs & run unit tests
make install is currently unsupported, but is on the roadmap once the windows build is complete.
to use cecs in your project, you can include the following files:
#include "cecs.h"
#include "cecs_entity.h"
#include "cecs_system.h"
all cecs functions return a cecs_errno
enum, defined in cecs_err.h
components are dumb data structures, added to entities and manipulated by systems.
components can be defined with YAML for fast iteration. only a small subset of YAML is actually supported, but for defining simple data structures (as described below). For example anchors and lists aren't supported, but they aren't really needed. An example of components defined in YAML can be found in components.yml
Since we are defining the data structures themselves as well as the default
data that should fill them when we define our component YAML, we have to
generate some C code to define the data structures. This is done in
comp_gen.c. This is compiled into the components
target with make components
. The components
recipe also cleans up this
target once it has been run, and generated the src/components/components.h
and src/components/components.c
files.
Note that as these files are generated they should not be checked in to git!
For example:
typedef struct {
float x;
float y;
float z;
} PosComponent;
would be registered in cecs like this:
static PosComponent posComp = {0};
cecs_reg_component(cecs, "position", &posComp, sizeof(posComp));
cecs_reg_component
takes four parameters
- a pointer to cecs
- a name to associate the component with
- a pointer to the original var and the size of the original var.
once a component has been registered the original variable and it's associated location in memory are no longer required.
Entities represent discreet object types in-game, and are comprised of one or more components.
Similarly to components, only a subset of YAML is supported in defining entities. An example of entities defined in YAML can be found in entities.yml
entities are clusters of components that represent an object in the game. empty entities are registered with:
int cecs_reg_entity(struct cecs *cecs, char* name, int n_comps, char **comps);
here the name
, n_comps
and comps
parameters are loaded from YAML.
there is also support for adding & removing components from and entity at runtime with:
int cecs_ent_add_component(struct cecs *cecs, uint32_t id, char* name);
and
int cecs_ent_rem_component(struct cecs *cecs, uint32_t id, char* name);
Systems iterate across components that they are interested in and can run per-frame, on init or with a direct call to the system.
Each system is associated with three functions: init
, work
and run
.
These funcitons are loaded dynamically from one of two shared object files.
CECS_SYS_FUNCS is defined and compiled
here, whereas CECS_USR_FUNCS is defined by you and can overwrite the system
functions.
For an example of building a dynamic library and linking it to your application,
please see the $(SYS_TARGET
recipe in the Makefile
Similarly to components, only a subset of YAML is supported in defining systems. An example of systems defined in YAML can be found in systems.yml
systems are currently only loaded into their respective data structure. As an engine to utilise this project is still to be created.