[libGDX] UI above characters' heads

Hello everyone,

I have the following setup in my project: a FillViewport(400, 200) which is used to render the world and now I want to add some UI to the game, so I plugged in a Stage without any custom viewport setup. All is fine for simple HUD like health, etc. - it behaves correctly (i.e. when the player moves, the elements move together with the player). But now I want to have create speech bubbles which will be displayed above the heads (or next to) of the characters I have in my game (please note that I don’t use a Stage for my in-game characters and world).

How could I approach it? I tried using a different Stage for the speech bubbles, but they just kept following the player no matter which viewport configuration I tried. By ‘following the player’ I mean that when the camera moves, the UI moves along. I can share more information if you need.

Thank you,
Patryk

You might want to make use of the Camera project and unproject methods. Take the characters head position in world space - project that to screen space with the world camera. then take that screen space position and unproject it with the ui camera to get a viewport coordinates to draw the widget at (or something like that). I do pretty much the same process in 3d to give characters name tags.

Holy cow, believe me or not, but I’ve actually tried to do that, but I messed up the order. :slight_smile: Thanks so much, it worked!

I have actually noticed a small problem, which I tried to illustrate in this GIF (it might take a moment to load):

If you take a look, you’ll notice that the dialog box is moving - sometimes it’s on the left edge of the small island, sometimes it moves towards the center.

Here’s the code I’m using:


    static Vector2 worldPosToViewport(Vector2 pos, Viewport gameCameraViewport, Viewport screenViewport) {
        Vector2 worldPosInScreenSpace = gameCameraViewport.project(pos);
        worldPosInScreenSpace.y = gameCameraViewport.getScreenHeight() - worldPosInScreenSpace.y;
        return screenViewport.unproject(worldPosInScreenSpace);
    }

Obviously, this method is called each frame.

What could be the problem?

Here’s how I fixed the problem:

    static Vector2 worldPosToViewport(Vector2 pos, Viewport gameCameraViewport, Viewport screenViewport) {
        TempVars tempVars = TempVars.get();

        Vector3 worldPos = tempVars.vect3d1.set(pos, 1.0f);

        Vector3 worldPosInScreenSpace = gameCameraViewport.getCamera().project(worldPos);
        worldPosInScreenSpace.y = gameCameraViewport.getScreenHeight() - worldPosInScreenSpace.y;
        Vector3 screenPosInViewportSpace = screenViewport.getCamera().unproject(worldPosInScreenSpace);
        pos.set(screenPosInViewportSpace.x, screenPosInViewportSpace.y);

        tempVars.release();
        return pos;
    }

Methods in the Viewport class perform some additional changes to the output, which seem to mess up things for me a bit. FYI, TempVars is taken from jMonkeyEngine, but you can freely replace the code with a simple Vector3 field in your class for temporary operations.