[2D] Get position at the edge of the viewport pointing to a distant POI

Godot Version

4.2

Question

Hello everyone.
I’ve been experimenting for over 2 days now and I just can’t get it right…
I want to place a Node2D at the edge of the screen, exactly at the point that shows the direction to a POI (as long as the POI is not visible on the screen). Nothing out of the ordinary, it happens in almost every game. But I just can’t figure out the math behind it.
Can you help me please :frowning:
So far I’ve only managed it when the player doesn’t move and there’s no camera, i.e. the position of the viewport 0.0 is the same as that of the world 0.0

I could of course draw a Path2D to the POIs and check when the PathFollower2D leaves the viewport, but of course that is anything but effective/performant

Okay, finally I did it.
But is there perhaps a much simpler/better/more compact solution?

func calculateIntersection(target_position: Vector2) -> Vector2:
	var player_position = position
	var direction = player_position - target_position
	var rect = get_viewport_rect().size / 2.0
	var camera_position = player_position - rect
	var tl = (player_position - rect - target_position).angle()
	var tr = (player_position + Vector2(rect.x, -rect.y) - target_position).angle()
	var bl = (player_position + Vector2(-rect.x, rect.y) - target_position).angle()
	var br = (player_position + rect - target_position).angle()
	var direction_n = (target_position - player_position).normalized()
	var intersection: Vector2
	
	if (direction.angle() > tl and direction.angle() < tr) \
		or (direction.angle() < bl and direction.angle() > br):
		#Target is behind top/bottom edge
		if direction_n.y < 0:
			var x_intersection = player_position.x + (camera_position.y - player_position.y) / direction_n.y * direction_n.x
			intersection = Vector2(x_intersection, camera_position.y + 5)
		elif direction_n.y > 0:
			var x_intersection = player_position.x - (camera_position.y - player_position.y) / direction_n.y * direction_n.x
			intersection = Vector2(x_intersection, player_position.y + rect.y - 5)
	else:
		if direction_n.x < 0:
			var y_intersection = player_position.y + (camera_position.x - player_position.x) / direction_n.x * direction_n.y
			intersection = Vector2(camera_position.x + 5, y_intersection)
		elif direction_n.x > 0:
			var y_intersection = player_position.y - (camera_position.x - player_position.x) / direction_n.x * direction_n.y
			intersection = Vector2(player_position.x + rect.x - 5, y_intersection)
	
	intersection.x = clamp(intersection.x, camera_position.x + 5, player_position.x + rect.x - 5)
	intersection.y = clamp(intersection.y, camera_position.y + 5, player_position.y + rect.y - 5)
	
	return intersection

This tutorial here seems to cover what you need. It’s Godot 3, but it should be similar enough to transfer over!