Entities and Components - Krystian-L-Lis/Stage GitHub Wiki
#Guide #EntitiesAndComponents
The model realizes composition pattern and provide global and iterable access to groups of function blocks implementing I_RawComponent
interface. Each such group is called entity. Each entity is declared as a scope(EntityStart
, EntityEnd
), and components should be declared within this scope. This allows for convenient declaration patterns, where components automagically join entities regardless on how deep they are declared within other structures or function blocks.
Entities are part of global linked list accessed using GetNextEntity
and GetNextEntity
functions. Likewise components are also part of linked list within said entity. This means that both entities and components can be statically extended without providing fixed number of entities and components completely eliminating array overflow errors.
This architecture solves the pain of dependency propagation by offering global access to entities and components, but with access strictly defined through interfaces. Function blocks can discover and use each other without complex wiring or tight coupling. It is a middle ground between passing through layers of encapsulation and exposing to much functionality.
Warning: The code examples provided are intended to illustrate typical use cases for this framework. They focus on demonstrating concepts and usage patterns and may not be syntactically correct.
Entity scopes define where and when components can be registered within an entity. In this framework, components must always be registered inside an active entity scope. This allows for automatic component registration with minimal boilerplate.
An entity scope is a bounded region in which components are associated with an entity. The scope starts with EntityStart
and ends with EntityEnd
. Any components declared within this region are automatically registered to the enclosing entity.
-
EntityStart
: Function block that marks the beginning of an entity scope. -
EntityEnd
: Function block that marks the closure of the entity scope. -
EntityExtend
: Function block that reopens a previously declared entity for modifications(e.g. due to inheritance).
An entity scope starts with EntityStart
and ends with EntityEnd
. Any components declared in between are automatically registered.
_entityStart: EntityStart;
_componentA: SomeComponentA;
_componentB: SomeComponentB;
_entityEnd: EntityEnd;
-
_entityStart
declares a new entity. -
_componentA
and_componentB
are automatically registered to_entityStart
. -
_entityEnd
closes the entity scope, preventing further modifications.
In some cases, you may need to add more components to an existing entity. Instead of redeclaring the entity, use EntityExtend
to reopen its scope. This is especially useful when a Function Block containing given entity needs to be extended and with it, its entity.
_entityExtend: EntityExtend(_entityStart);
_newComponentA: SomeComponentA;
_newComponentB: SomeComponentB;
_entityEnd: EntityEnd;
-
EntityExtend
reopens the_entityStart
scope, allowing additional components to be registered. -
_newComponentA
and_newComponentB
are now part of_entityStart
.
If one EntityStart
is declared inside another entity’s scope, both entities remain separate and equal, even though they appear nested in the code structure.
_entityA: EntityStart;
_componentA: SomeComponentA;
_entityB: EntityStart;
_componentB: SomeComponentB;
_entityBEnd: EntityEnd;
_entityAEnd: EntityEnd;
-
_entityA
and_entityB
are completely independent entities. -
_componentA
belongs to_entityA
, and_componentB
belongs to_entityB
. - The fact that
_entityB
is declared inside_entityA
does not mean_entityB
is a child of_entityA
. -
EntityEnd
closes the scope of the most recently opened entity.
The EntityStart
function block serves as a unique identifier within the EC model, grouping and referencing a collection of components. It offers a flexible structure where the encapsulating function block doesn’t need to implement or extend any specific functionality. Instead, it can act as a raw container for one or more entity instances and their components.
The Component
function block registers a component within the system and associates it with a specific entity during initialization, ensuring that the program structure is fully established upon the completion of the FB_Init
cycle. It implements I_Component
that allows its functionality and also stores some metadata regarding underlying raw I_RawComponent
.
Example Usage:
FUNCTION_BLOCK CustomComponent IMPLEMENTS I_Component
VAR
_component: Component(THIS^);
END_VAR
FUNCTION_BLOCK CustomEntity
VAR
_entityStart: EntityStart;
_myComponent: CustomComponent;
_entityEnd: EntityEnd;
END_VAR
To create new component types they need to extend I_RawComponent
, which extends __SYSTEM.IQueryInterface
. These components can be then casted to various custom interfaces through __QUERYINTERFACE
function.
Example Usage:
INTERFACE I_CustomComponent EXTENDS I_Component
FUNCTION_BLOCK CustomComponent IMPLEMENTS I_CustomComponent
FUNCTION_BLOCK CustomEntity
METHOD GetEntity : I_Entity
GetEntity := self;
END_METHOD
PROGRAM MAIN
VAR
customEntity: CustomEntity;
iEntity: I_Entity := customEntity.GetEntity();
iComp: I_Component;
iCustom: I_CustomComponent;
END_VAR
// Retrieve a component associated with an entity
IF IsOk(iEntity.GetNextEntity(iComp)) THEN
// Cast the I_Component to I_CustomComponent
IF __QUERYINTERFACE(iComp.Raw, iCustom) THEN
// This returns TRUE
END_IF
END_IF
These functions allow you to browse through entities within the system. They accept a reference to the I_Entity
interface. If the passed reference is 0
, then GetNextEntity
will return the first entity, and GetPrevEntity
will return the last entity. Otherwise, they return the next or previous entity in relation to the passed entity.
Example Usage:
FUNCTION_BLOCK CustomEntity
METHOD Init
VAR
iEntity: I_Entity;
iComp: I_Component;
END_VAR
WHILE IsOk(GetNextEntity(iEntity)) DO
WHILE IsOk(iEntity.GetNextComp(iComp)) DO
// Operate on entity components
END_WHILE
END_WHILE
END_METHOD
< Previous | Home | Next >