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
update
function parameters) - Always fully processes macros, even if
display
is 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
components
andresources
, all logic is written inprocessors
components
only contain data, and belong to entities- only one type of each component can exist per entity
resources
only contain data, and belong to the universe- only one type of each resource can exist per universe, these are akin to "global" values
entities
are a unique ID number coupled with an array ofcomponents
phases
groupprocessors
together in logical units (updating, rendering, etc)universes
groupentities
andphases
- Components and resources are stored in an
IntMap
(rather than aStringMap
like in edge)- Components have
typeIDs
which 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 profiling
to 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
View
variables, 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
ResourceView
variables, with types referring to theResource
s 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,
universes
can 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 turnip
to generate aturnip.json
file, which contains definitions of all the components and processors available in your game. turnip then can load theturnip.json
to 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 |