Blazingly fast Entity-Component-System microframework.
System Information
Definition Index
-
CL-FAST-ECS
- ECS
NOTE: this software is of alpha quality, and the API is subject to change.
cl-fast-ecs
is a Common Lisp library providing an implementation of the Entity-Component-System pattern, primarily focused on speed and interactive development.ECS is an architectural data-oriented design pattern that allows for the effective processing of a large number of in-game objects while keeping the code and data separated. This provides flexibility in the way that game objects are built at runtime.
NOTE: to get the maximum performance, but loose the ability to interactively redefine components in the storage, add
:ECS-UNSAFE
keyword into*FEATURES*
before loading the library.-
EXTERNAL SPECIAL-VARIABLE *COMPONENT-DEFINED-HOOK*
Called when a new component is defined with
DEFCOMPONENT
macro. Arguments for the call are the index in the component registry and the constructor function for component storage (not to be called directly by user).See
HOOK-UP
. -
EXTERNAL SPECIAL-VARIABLE *COMPONENT-REDEFINED-HOOK*
Called when an existing component is redefined with
DEFCOMPONENT
macro. Arguments for the call are the index in the component registry and the constructor function for component storage (not to be called directly by user).See
HOOK-UP
. -
EXTERNAL SPECIAL-VARIABLE *COMPONENT-STORAGE-GROWN-HOOK*
Called after the component storate capacity is increased due to the component being added to the new entity. Arguments for the call are the index in the component registry and the new storage capacity.
Note: this is a good place to call for a full GC cycle to collect old storage arrays.
See
HOOK-UP
. -
EXTERNAL SPECIAL-VARIABLE *ENTITY-STORAGE-GROWN-HOOK*
Called after the entity storate capacity is increased due to new entity being added. Argument for the call is the new storage capacity.
Note: this is a good place to call for a full GC cycle to collect old storage arrays.
See
HOOK-UP
. -
EXTERNAL SPECIAL-VARIABLE *STORAGE*
Global storage instance to be used by virtually all library functions.
NOTE: it is not bound to any value initially.
See also
BIND-STORAGE
. -
EXTERNAL TYPE-DEFINITION ENTITY
An entity type, basically just a
FIXNUM
. -
EXTERNAL FUNCTION BIND-STORAGE
- &KEY
- INITIAL-ALLOCATED
Binds global variable
*STORAGE*
to the newly created storage instance.See also
MAKE-STORAGE
. -
EXTERNAL FUNCTION DELETE-ENTITY
- ENTITY
Delete given
ENTITY
and all of its components in the order they've been defined with DEFCOMPONENT.Complexity: amortized O(m + log p), where m is the number of defined components, and p is the number of deleted entities so far.
-
EXTERNAL FUNCTION ENTITY-VALID-P
- ENTITY
Return
T
if entity is valid.Complexity: O(1).
-
EXTERNAL FUNCTION MAKE-ENTITY
-
EXTERNAL FUNCTION MAKE-OBJECT
- SPEC
Creates and returns a new object (that is, an entity with a set of components) following specification
SPEC
structured as follows:'((:component-name1 :component-slot1 "value1" :component-slot2 2.0) (:component-name2 :component-slot 42) ;; ... )
Complexity: O(m), where m is the number of components in the given
SPEC
.Not recommended for using in a tight loops such as systems, see
DEFCOMPONENT
documentation for alternatives.For a technical reasons, the count of component specifiers in
SPEC
should not exceed 4000 (which is more than enough for any practical usage).See also
MAKE-ENTITY
,DELETE-ENTITY
. -
EXTERNAL FUNCTION MAKE-STORAGE
- &KEY
- INITIAL-ALLOCATED
Creates and returns a new storage instance.
Optional
INITIAL-ALLOCATED
argument sets the initial count of pre-allocated entities and defaults to 32.See also
BIND-STORAGE
. -
EXTERNAL FUNCTION PRINT-ENTITY
- ENTITY
- &OPTIONAL
- STREAM
Prints given
ENTITY
to theSTREAM
in a way that is compatible withMAKE-OBJECT
. To be used in debugging scenarios. -
EXTERNAL FUNCTION RUN-SYSTEMS
- &REST
- ARGUMENTS
Runs all of the systems registered with
DEFSYSTEM
with given optional keywordARGUMENTS
. -
EXTERNAL GENERIC-FUNCTION DELETE-COMPONENT
- INDEX
- ENTITY
Deletes a compionent on a given
ENTITY
in generic fashion.Not recommended for using in a tight loops such as systems, see
DEFCOMPONENT
documentation for alternatives. -
EXTERNAL GENERIC-FUNCTION MAKE-COMPONENT
- INDEX
- ENTITY
- &KEY
- &ALLOW-OTHER-KEYS
Create a component on a given
ENTITY
in generic fashion.Not recommended for using in a tight loops such as systems, see
DEFCOMPONENT
documentation for alternatives. -
EXTERNAL GENERIC-FUNCTION PRINT-COMPONENT
- INDEX
- ENTITY
- &OPTIONAL
- STREAM
Prints component data to the given
STREAM
.See
PRINT-ENTITY
. -
EXTERNAL MACRO DEFCOMPONENT
- NAME*
- &REST
- SLOTS*
Defines component structure with
NAME
andSLOTS
, allowing optional docstring, just likeDEFSTRUCT
.There's extra keyword argument
:INDEX
to the slot definition, which, if set to symbol, creates a hash table-based index for that slot allowing fast (amort. O(1)) lookups in form of "which set of entities have this exact slot value"; that might come in handy when implementing parent/child or other entity relationships. The downside of such index is that component add/delete/update operations take a little bit longer, and addition can trigger expensive table rehashing.Additionally, when
:UNIQUE
is set toT
, such index ensures that entities and given slot values map 1 to 1, at least in value'sSXHASH
sense. This might prove valuable when implementing entity names.To be called from a top-level. Allows redefinition of component with the same
NAME
but different set ofSLOT
s; all necessary storage will be properly reallocated.This macro defines a following set of operations for given
NAME
name:- an internal structure called
name-SOA
with its required internal machinery; - a constant
+name-COMPONENT-INDEX
to reference component data within a storage; - a component data accessors
name-slotName
and(SETF name-slotName)
for every slot on a component, with O(1) complexity (their usage is discouraged though because of poor caching performance, in favour of defining a new system withDEFSYSTEM
); - a component constructor aptly named
MAKE-name
, which adds the component being defined to the givenENTITY
, with O(k) complexity, where k is the number of slots on the component; - specialization of
MAKE-COMPONENT
generic on a component being defined; - a predicate called
HAS-name-P
testing whether givenENTITY
has the component being defined, with O(1) complexity; - a component destructor called
DELETE-name
, removing the component being defined from the givenENTITY
in O(k) complexity,where k is the number of slots on the component; - a convenience macro
WITH-name
akin toWITH-SLOTS
; - an upsert operator
ASSIGN-name
which first ensures the component exists on given entity and then sets its values according to given keyword arguments, but keeps slots that weren't specified to their previous values; - a
REPLACE-name
function which copies the component slot values from one given entity to another; - some internal helper macros;
- if
:INDEX
if set to a symbol for any slot, the function with the name denoted by that symbol is defined, taking slot value as an argument and returning the list of entities having such slot value; - if
:UNIQUE
is specified and set toT
in addition to:INDEX
, the index function returns a single entity having given slot value, or raises a condition if there's no such entity.
Also runs hook
*COMPONENT-DEFINED-HOOK*
or*COMPONENT-REDEFINED-HOOK*
when called, depending on circumstances. -
EXTERNAL MACRO DEFINE-COMPONENT
- NAME
- &REST
- SLOTS
An alias for
DEFCOMPONENT
. -
EXTERNAL MACRO DEFINE-SYSTEM
- NAME
- &KEY
- COMPONENTS-RO
- COMPONENTS-RW
- COMPONENTS-NO
- ARGUMENTS
- INITIALLY
- FINALLY
- WHEN
- ENABLE
- WITH
- &BODY
- BODY
An alias for
DEFSYSTEM
. -
EXTERNAL MACRO DEFSYSTEM
- NAME
- &KEY
- COMPONENTS-RO
- COMPONENTS-RW
- COMPONENTS-NO
- ARGUMENTS
- INITIALLY
- FINALLY
- WHEN
- ENABLE
- WITH
- &BODY
- BODY
Defines a system with a given
NAME
and component setsCOMPONENTS-RO
andCOMPONENTS-RW
with read-only and read-write access to component slots, respectively.COMPONENTS-NO
defines a list of components that should not appear on entities processed by the system.ARGUMENTS
is a two-list of the keyword arguments the system expects to be passed viaRUN-SYSTEMS
, just like inFTYPE
declaration.Can be called from a top-level or embedded into other form. Allows redefinition of system with the same
NAME
but differentBODY
or set of components.Note that requested components should be defined with
DEFCOMPONENT
before defining the system.The
BODY
of forms (with optional docstring) would be run for every entity containing all of the components from the given set, having the following bindings:ENTITY
— the entity being processed;ComponentName-SlotName
for every slot of every component specified.
The forms in
BODY
are enclosed in block namedCURRENT-ENTITY
, so the processing could be skipped to the next entity by calling(RETURN-FROM CURRENT-ENTITY)
.The
INITIALLY
form would be evaluated before the entities loop, and theFINALLY
form would be evaluated after the loop and its value would be returned from the system.The
WHEN
form is evaluated every entity loop iteration to check if that entity should be processed or not.The
ENABLE
form is evaluated before the entity loop to check if the entire loop needs to run or not.The
WITH
form, having lambda list(VARS &KEY OF-TYPE =)
, allows to initialize the local variables once before the loop starts. TheVARS
andOF-TYPE
could be the single symbol or the list, and in latter case the required=
argument should be mutliple values.See also
RUN-SYSTEMS
. -
EXTERNAL MACRO HOOK-UP
- HOOK
- FN
Hooks up the function
FN
on theHOOK
.Complexity: O(m), where m is the number of functions on a given hook.
See also
UNHOOK
. -
EXTERNAL MACRO UNHOOK
- HOOK
- FN
Unhooks the function
FN
from theHOOK
.If the function wasn't registered with
HOOK-UP
on a given hook, this function has no effect.Complexity: O(m), where m is the number of functions on a given hook.