Static function to "translate" a position in 2D space to a position on the CanvasLayer

Godot Version

v4.2.2.stable.mono.official [15073afe3]

Question

I’m trying to create a few effects for my HUD where, for example, during a tutorial, I draw a line from an item on my HUD to a 2D position. For this, I need a function that accepts a Node2D as a parameter, and will convert that Node’s position into a position on the CanvasLayer. If the node is outside of the viewport, I still want it to try and follow the item in 2D, but not go outside of the viewport. I’ve tried a few things so far, for example:

public static Vector2 WorldToViewport(Node2D target)
{
    Window root = target.GetTree().Root;

    Vector2 screenPos = (root.GetFinalTransform()
                         * target.GetGlobalTransformWithCanvas()).Origin + root.Position;

    return screenPos;
}

But unfortunately this did not work at all, and would just give seemingly nonsense positions.

An example of what I’m looking for (But in 2D instead of 3D) is what you can see in Titanfall 2 when you look at a weapon.


If would create a small line between the gun in 3D space and a HUD element that displays what it is. I will figure out the rest later, but for this, I just need to find a way to translate that 2D position into a position on the HUD.

I’m sorry to bump but I just cannot figure this one out.

have a look at this unproject_position function in camera3d:

This is a 2D project. Not 3D.

Oops misunderstood your game, sorry. Cant you just get the position of the object and substract it from the cameras-position?

That’s only the first part of the puzzle, yes. But that only gives me the general position of the camera. I need to be able to make a sprite, for example, on the CanvasLayer, follow an object that is NOT on the canvas layer, but on my “map”.

Isnt this just the solution or am i missing something?

func _physics_process(_delta):
    # offset depends on viewport size
    sprite.position= object.global_position - camera.global_position + offset

I’m sorry, perhaps I should’ve made the post more obvious.
I’m looking for an answer in C#, a function that can translate the position of a Node2D (that isn’t on a canvaslayer) to a position on my main CanvasLayer.

As an example, if I have a Node2D at position 130,130 in the world, but my camera is at position 2000,2000, I want this function to return 0,0, because the position of that Node2D would be outside of my viewport, but I still want it to be ON my viewport.
And when this Node2D is inside my viewport, I want coordinates returned to me that would allow me to move the sprite (for example, but it might be something else) on my CanvasLayer, to always be “above” the Node2D in the world.

Well the logic should be the same. you would get the position of your object and subtract it from the cameras-position. then you can clamp it to a minimun of (0,0) and maximum of (viewportsize) if neccessary. i have no experience in C# so i cant give you code

Unfortunately this approach does not take zoom into consideration as far as I can tell, I’ll try a few more approaches to deal with it, but the problem is a lot more difficult than I first anticipated.

The CanvasItem class has a lot of transform-functions like get_global_transform_with_canvas(). Maybe you’ll find something there:

1 Like

This has helped me a lot, thank you, for anyone looking for something like this in the future, this is made to be a static function, but you can easily modify it to not be one if you prefer, but it does exactly what I needed:

public static Vector2 WorldToViewport(Node2D target)
{
    Vector2 targetCanvasPosition = target.GetScreenTransform()
            .Origin.Clamp(new Vector2(0, 0), target.GetViewportRect().Size);

    return targetCanvasPosition;
}
1 Like