# Godot - Offscreen Target Indicator

I have a crosshair image that will lock onto enemies that are visible in the camera and will stay on the edge of the screen when the enemy is offscreen. This works until you face more than 90º away from the enemy in either direction. If facing exactly 180º from the enemy, the indicator will appear as thought the enemy were directly in front of the camera but I would like it to stick to the closest edge of the screen instead. The red crosshair is drawn onto a 2d space and positioned within the camera view.

On screen:

Slightly offscreen:

Very offscreen:

        var enemy_pos:Vector3 = enemy.global_transform.origin
var screen_pos:Vector2 = camera.unproject_position(enemy_pos)
var lock:TextureRect = \$TargetLock
var lock_size:Vector2 = lock.texture.get_size()
var crosshair_center:Vector2 = crosshair.rect_position + crosshair.rect_size * 0.5

var direction_to_enemy := (enemy_pos - camera.global_transform.origin).normalized()
var direction_facing := -camera.global_transform.basis.z

# currently unused, > 0 = target within 90º rotation
# var facing_target = direction_facing.dot(direction_to_enemy)

var screen_width = ProjectSettings.get_setting("display/window/size/width")
var screen_height = ProjectSettings.get_setting("display/window/size/height")

screen_pos -= lock_size / 2
screen_pos.x = clamp(screen_pos.x, 0, screen_width - lock_size.x)
screen_pos.y = clamp(screen_pos.y, 0, screen_height - lock_size.y)

lock.set_position(screen_pos)


I can understand the issue, but my vector math in 3d space is not good enough to solve this issue.

The dot product should tell you if the camera is looking roughly at the enemy or away from it. You have it in comments:

var facing_target = direction_facing.dot(direction_to_enemy)


Now, if that is less than 0, it means the camera is looking away from the enemy. In that case, take screen_pos and scale it, such that when you clamp it it will be on the edge of the screen.

Compute the center of the screen:

var screen_center = Vector2(screen_width * 0.5, screen_height * 0.5);


Then take the position form the center, scaled up (I'm using screen_width as scale factor), and offset by the center (to have it back from the top-left corner):

screen_pos = (screen_pos - screen_center) * screen_width + screen_center;


Clamp that as usual, and it should give you a position on the edge of the screen. Except when screen_pos and screen_center are equal. Hopefully that is acceptable.