This time I tried two things:
- Circle colliders on objects, decorations and characters;
- A little 3D.
Circle colliders
Luxe already have circle colliders, that’s fine. But it took me a lot to modify the game engine to use them. What is the problem?
I lack the capabilities of a standard luxe’s Shape
(eg. I need collisions list, collider owner, bounding box, etc.). There are two options to add more features to standard shape:
- Use
data
field (Shape
has generic data object, where you can store anything you want); - Extend class (eg.
class SimCollider extends Polygon
).
First option looks promising, but it’s inconvenient to use, because type of data
field is Dynamic
. Typical use case:
(cast shape.data : SimColliderData).bbox
So initially I choose second way. And it works well when I use only one shape type – Polygon
.
Shape
|- Circle extends Shape
|- Polygon extends Shape
|- SimCollider extends Polygon
But now I need my custom functions both for Polygon
and Circle
classes. I have following options:
- Copy + paste… What about NO?
- Traits (there are few
macro
-based libraries for this)… Not this time. - Aggregation – move custom code to
SimColliderData
, put it todata
field, and leave inSimPolygonCollider
andSimCircleCollider
simple code that passthrough everything toSimColliderData
… Nope, because of copy + paste (less than in first case, but still bad). - Abstract over
Shape
.
I choose last option:
@:forward
abstract SimCollider(Shape) to Shape {
public var data(get, set) : SimColliderData;
public var type(get, set) : Int;
public var bbox(get, set) : Rectangle;
public var owner(get, set): Dynamic;
... more properties ...
public function new(shape : Shape, type : Int, bbox : Rectangle, owner : Dynamic) {
this = shape;
this.data = new SimColliderData(type, bbox, owner);
}
public inline function get_data() : SimColliderData {
return cast this.data;
}
public inline function set_data(value : SimColliderData) : SimColliderData {
this.data = value;
return value;
}
public inline function get_type() : Int {
return data.type;
}
public inline function set_type(value : Int) : Int {
return (data.type = value);
}
... more code ...
public static function polygon(x : Float, y : Float, vertices : Array<Vector>, type : Int, owner : Dynamic = null) : SimCollider {
var shape = new Polygon(x, y, vertices);
return new SimCollider(shape, type, computeBbox(shape), owner);
}
public static function circle(x : Float, y : Float, radius : Float, type : Int, owner : Dynamic = null) : SimCollider {
var shape = new Circle(x, y, radius);
var bbox = new Rectangle(- radius * 0.5, - radius * 0.5, radius, radius);
return new SimCollider(shape, type, bbox, owner);
}
}
Thanks to abstract
I can use luxe‘s Shape
in convenient way.
P.S. You may notice that in the screenshots circle colliders actually drawn as octagon – it’s is only to speed-up debug draw, actually they are perfect circles.
3D: first try
I wanted to try to add a bit of 3D. First try (you already seen this image at top of the post):
Looks well, but imagine that there are ceiling:
How should the player know that there is a switch there? I don’t want to redraw all levels. So this looks good, but unusable.
3D: second try
Let’s try to put camera on the top:
Switch is visible (not very good, but still visible). But decorations, objects and player are almost invisible. Especially player.
3D: third try
Ok. Let’s try different way:
Looks weird.
GD2D is in 2D. Deal with it 🙂
See you later!