So, in other words, the Turnip Surprise would be… a turnip.
This package is my own ECS, based very heavily on edge. I really like the edge framework, but I keep running into small issues with it:
- It requires
thx.core, which pulls a lot of code I don't need - It hasn't been updated in a long time, and has been superceded by the author by edge2
- Does a little bit too much behind-the-scenes with macros (ex: auto-creating views based on
updatefunction parameters) - Always fully processes macros, even if
displayis defined (when using completion), slowing down completion - Isn't under my control so isn't easily extendable for my personal uses
So, I wrote this library by copying a lot of the basic functionality of edge, but writing it in a way that makes sense for me—so consider this a fork of edge.
The key features of this library include:
- "Pure" ECS philosophy—all data is stored in
componentsandresources, all logic is written inprocessorscomponentsonly contain data, and belong to entities- only one type of each component can exist per entity
resourcesonly contain data, and belong to the universe- only one type of each resource can exist per universe, these are akin to "global" values
entitiesare a unique ID number coupled with an array ofcomponentsphasesgroupprocessorstogether in logical units (updating, rendering, etc)universesgroupentitiesandphases
- Components and resources are stored in an
IntMap(rather than aStringMaplike in edge)- Components have
typeIDswhich are auto-generated by macros at build time. This has the potential to cause issues between release versions, but I'm still exploring this as it has the potential to be faster than StringMaps.
- Components have
- Just about fully behaviour-tested: https://travis-ci.org/hamaluik/baldrick
- Profiling built in
- Add the define
-D profilingto your build process to enable profiling individual processors & overall phases - Still experimental, but seems to work without issue
- Add the define
- Processors work on explicit
views- Processors define
Viewvariables, with anonymous types referring the components that view is interested in - Macros then build the code to populate and manage
views - The processor is then responsible for iterating over
views, which iterates over matched entities with references to the components of interest extracted out - See the samples & API docs for more clarification
- Processors define
- Processors can also access
resource views- Processors define
ResourceViewvariables, with types referring to theResources that view is interested in - Macros then build the code to populate
resource views - See the samples for more details
- Processors define
- Universe-entity serialization
- Using the built-in Haxe serializer / unserializer,
universescan store and load their entity states using strings
- Using the built-in Haxe serializer / unserializer,
- Integration with turnip
- turnip is an addon for Blender which allows you to use Blender as a level editor (so you can be lazy and not write your own level editor / rely on writing levels in code or text)
- Add the define
-D turnipto generate aturnip.jsonfile, which contains definitions of all the components and processors available in your game. turnip then can load theturnip.jsonto enable game-specific level editing in Blender! - This feature is still very much under development (as is turnip itself), so ¯\_(ツ)_/¯
Why "baldrick"? Well, I tend to use an ECS in a lot / most of my projects (as a lot / most of my projects with Haxe are game-related), so this library could be called my dogsbody, so I named it after the best dogsbody in all of history.
API documentation is available here: https://hamaluik.github.io/baldrick/
package components;
import baldrick.Component;
class Position implements Component {
public var x:Float = 0.0;
public var y:Float = 0.0;
public function new(x:Float, y:Float) {
this.x = x;
this.y = y;
}
}package processors;
import baldrick.Processor;
import baldrick.View;
import components.Position;
class PrintProcessor implements Processor {
var prints:View<{pos:Position}> = new View<{pos:Position}>();
public function new(){}
public function process():Void {
for(view in prints) {
trace('Entity ' + view.entity.hashCode() + ' position: (' + view.data.pos.x + ', ' + view.data.pos.y + ')');
}
}
}import baldrick.Universe;
import baldrick.Phase;
import components.*;
import processors.*;
class Main {
public static function main() {
var universe:Universe = new Universe();
var render:Phase = universe.createPhase();
render.addProcessor(new PrintProcessor());
universe.createEntity([
new Position(0, 0)
]);
render.process();
trace('state: ' + universe.saveEntities());
}
}| Target | Entity Creation (µs/entity) | Processor Time (µ/iteration) |
|---|---|---|
| JS | 1.10 | 0.70 |
| HL | 1.80 | 0.11 |
| CPP | 0.15 | 0.13 |
