Basic example for using h2d.Camera to move the world but keep the HUD in place?

I’ve been trying to wrap my head around using the h2d.Camera but I can’t quite get it just yet. Is there any basic example of using it so that my in-game elements are being followed while the HUD elements do not scroll with the background?

Actually once you’ve seen it it’s quite simple. You split the rendering for the scene that shows your game’s world and the scene that has the HUD/GUI. Like so:

// this method is from the hxd.App class, so override it in the class extending it
override function render(e:Engine) {
        // all here are extending h2d.Scene (or h3d.Scene):
        world.render(e); // your game's world, by default is the s2d scene and which has the camera
        general_user_interface.render(e); // your HUD so to speak
    }

Hope it works for you. Then you should be able to treat them separatedly.

2 Likes

import h3d.Engine;
import h2d.Scene;

class SomeApp extends hxd.App {

    private var hud : h2d.Scene;

    override function render(e:Engine) {
        s2d.render(e);
        hud.render(e);
    }

    override function update(dt:Float) {
        moveCameraAround();
    }

    private function moveCameraAround() {

        var c = s2d.camera;
        if(hxd.Key.isPressed( hxd.Key.MOUSE_WHEEL_UP ))
            c.scale(1.25, 1.25);
        if(hxd.Key.isPressed( hxd.Key.MOUSE_WHEEL_DOWN ))
            c.scale(0.8, 0.8);

        var moveMapSpeed = 10;
        if(hxd.Key.isDown( hxd.Key.RIGHT ))
            c.x += moveMapSpeed / c.scaleX;
        if(hxd.Key.isDown( hxd.Key.LEFT ))
            c.x -= moveMapSpeed / c.scaleX;
        if(hxd.Key.isDown( hxd.Key.DOWN ))
            c.y += moveMapSpeed / c.scaleY;
        if(hxd.Key.isDown( hxd.Key.UP ))
            c.y -= moveMapSpeed / c.scaleY;

    }

    override function init() {

        // world
        var t = new h2d.Text( hxd.res.DefaultFont.get(), s2d );
        t.setPosition( s2d.width/2, s2d.height/2 );
        t.text = 'I´m fixed in the world';
        
        // hud
        this.hud = new MyHUD();
        this.sevents.addScene( hud ); // otherwise the HUD cannot get evented by App.hxd, doesn't receive mouse interaction etc.
    }

    static function main() {
        new SomeApp();
    }
}

class MyHUD extends h2d.Scene {
    public function new() {
        super();
        var ia = new h2d.Interactive( 200, 50, this );
        ia.backgroundColor = 0xFFAAAAAA;
        var t = new h2d.Text( hxd.res.DefaultFont.get(), ia );
        t.text = "Button stays in HUD";
    }
}
2 Likes

Oh, I was going to say that I was using the camera.follow function to focus on the player entity and after I’ve overridden render, it did work but some things like my ScaleMode goes funky and inconsistently behaving

Ok, I see. You could also ask in #Heaps on the discord server for Haxe.

1 Like

late edit: actually when you use heaps buttons (h2d.Interactives) in your UI / HUD you would have to add another camera (just by new h2d.Camera();) and configured like below:

// Second camera for sample controls
		var uiCamera = new Camera();
		// layerVisible allows to filter out layers that camera should not render.
		uiCamera.layerVisible = (idx) -> idx == 2;
		s2d.add(fui, 2);
		// Add UI camera to scene. Note that order of cameras in array matters, as they are rendered in-order.
		s2d.addCamera(uiCamera);
		// Only one camera can handle user input events.
		// When assigning newly-created camera as interactiveCamera - adding it to Scene can be omitted, as it will be added automatically.
		s2d.interactiveCamera = uiCamera;

this is because only one camera can can response to click events.

and of course you use at least two layers like so:

final layer_world_stuff : Int = 0;
final layer_ui_or_hud   : Int = 1; // must be higher value than in-world layer

see full code here!https://github.com/HeapsIO/heaps/blob/98a780ecbcb23772267e3d23b735e7da08fbb57b/samples/Camera2D.hx#L69