In my project using ECS, currently I have to use two systems, like so (simplified):
var movingShapes:Array<{ displayObject:openfl.display.DisplayObject, position:Position }>;
var movingTiles:Array<{ tile:openfl.display.Tile, position:Position }>;
for(component in movingShapes) {
component.displayObject.x = component.position.x;
component.displayObject.y = component.position.y;
}
for(component in movingTiles) {
component.tile.x = component.position.x;
component.tile.y = component.position.y;
}
I’d like to use single system to deal with both of those, unfortunately they don’t share an interface. So I tried using typedef as @PSvils told me on IRC:
typedef Movable = {
var x:Float;
var y:Float;
};
var moving:Array<{ item:Movable, position:Position }>;
//adding some items here
for(component in movingShapes) {
component.item.x = component.position.x;
component.item.y = component.position.y;
}
Works fine for DisplayObjects, however it throws Cannot create property x on openfl.display.Tile. I peeked into Tile source code, and it seems x and y don’t fit into physical field criteria.
Can I do something more about it, or am I stuck with double implementation?
@:to public inline function toDisplayObject():Null<DisplayObject>
{
return switch this { case Left(v): return v; case Right(v): return null; };
}
@:to public inline function toTile():Null<Tile>
{
return switch this { case Right(v): return v; case Left(v): return null; };
}
It seems due to using Null<T>, the casting doesn’t use my methods. I can’t return only this.Left or something like that, so what would be the correct approach?
I just went with throwing an error if trying to cast to the other type (as I know which type appears where).
One pitfall of all this though: using cast(foobar, DisplayObject) will not call #toDisplayObject, it’s only for implicit casts, otherwise you have to call .toDisplayObject directly.
Right. DisplayObject and Tile are classes, so they’re both nullable.
(As far as I know, you only need to use Null<> for Ints, Floats, and enums. There might be other cases, but you definitely don’t need it for classes.)
Another option:
var tile:Tile = movable;
var displayObject:DisplayObject = movable;