GD2D: dev log #9

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:

  1. Use data field (Shape has generic data object, where you can store anything you want);
  2. 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:

  1. Copy + paste… What about NO?
  2. Traits (there are few macro-based libraries for this)… Not this time.
  3. Aggregation – move custom code to SimColliderData, put it to data field, and leave in SimPolygonCollider and SimCircleCollider simple code that passthrough everything to SimColliderData… Nope, because of copy + paste (less than in first case, but still bad).
  4. 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!

Leave a Reply

Your email address will not be published. Required fields are marked *

*