[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,

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);

        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.