ECX is Entity Component System framework for Haxe
Libraries (work in progress):
- ecx-common: Common utilities
- ecx-scene2d: Scene graph library example
var config = new WorldConfig([...]);
var world = Engine.createWorld(config, ?capacity);
Entity is just integer id value. 0
is reserved as invalid id.
All services are known at world creation. World provides possibility to resolve services. World::resolve
use constant Class<Service>
for resolving. At compile-time these expressions will be translated to lookup array access by constant index with unsafe cast (pseudo example: cast _services[8]
). For hxcpp
poiter trick is used to avoid generating dynamic_cast
.
Each service could have dependencies on different services. With Wire<T:Service>
you could inject your dependencies to instance fields.
For example we need to inject TimeSystem system to our MovementSystem
class MovementSystem extends System {
var _time:Wire<TimeSystem>;
...
override function update() {
var dt = _time.dt;
...
}
}
For all System
types.
For example we need to track all active(live) entities with components: Transform, Node and Renderable.
class MovementSystem extends System {
var _entities:Family<Transform, Node, Renderable>;
...
override function update() {
// Note: typeof _entities is Array<Entity>
for(entity in _entities) {
// only entities with required component will be displayed
trace(entity.id);
}
}
}
Sometimes it could be useful to mark some optional component in Family declaration just for readability.
You can wrap each optional Component type in parentheses ()
and it will be ignored by Family, but
will be notated.
var _entities:Family<Transform, Node, Renderable, (Scissors)>;
IDLE
: System doesn't overrideupdate
method. Should not be updated.CONFIG
: System is defined with@:config
meta. This system is just configurator. It will be deleted after World initialization phase.
Component is a way to associate [data] per Entity
. You could just use component-builders to define your own components.
class Position extends AutoComp<Point> {}
/// later just use it like Point class per entity
_position.get(entity).x = 10;
Or you could create any custom crazy ComponentStorage / ComponentManager.
class Color extends Service implements Component {
// BitmapData is used just to demonstrate that you are not limited to anything to store <component data> per <entity>
// Each pixel is color for entity
var _colors:BitmapData;
...
inline public function get(entity:Entity):Int {
_colors.getPixel32(entity.id % _stride, Std.int(entity.id / _stride));
}
....
}
Injection: World Component
is Service
, so you are able to invoke all messages directly to other services.
Implementation: Component
is just interface, you could iterate all registered components and access their base API per entity. It's handy for automatically cloning or serialization.
ServiceType
, ServiceSpec
, ComponentType
, ClassMacroTools
TypeManager
(WIP)
-D ecx_debug
for debugging
-D ecx_macro_debug
for macro debugging
-D ecx_report
to get and analyse ecx_wires.html
and ecx_matrix.html
report files generated during compilation
- Rethink world initialization:
-
- Are we are ok that instance of service could be created outside by default?
- Rethink system-flags
- Delete configurator services
- Add more information on specific cases of AutoComp
- Pack for dense storage
- Entity Generations