78 lines
2.9 KiB
GDScript3
78 lines
2.9 KiB
GDScript3
|
|
class_name ScannerGuidance
|
||
|
|
extends Control
|
||
|
|
|
||
|
|
const PLANET_DEFINITIONS = preload("res://planets/PlanetDefinitions.gd")
|
||
|
|
const EDGE_MARGIN: float = 34.0
|
||
|
|
|
||
|
|
@onready var indicator: Control = $Indicator
|
||
|
|
@onready var target_label: Label = $TargetLabel
|
||
|
|
|
||
|
|
var fleet: Node2D
|
||
|
|
|
||
|
|
|
||
|
|
func _ready() -> void:
|
||
|
|
fleet = get_tree().get_first_node_in_group("player_fleet") as Node2D
|
||
|
|
visible = false
|
||
|
|
|
||
|
|
|
||
|
|
func _process(_delta: float) -> void:
|
||
|
|
var target: Dictionary = GameState.active_scanner_target()
|
||
|
|
if target.is_empty() or GameState.intro_active or _modal_is_open():
|
||
|
|
visible = false
|
||
|
|
return
|
||
|
|
if fleet == null or not is_instance_valid(fleet):
|
||
|
|
fleet = get_tree().get_first_node_in_group("player_fleet") as Node2D
|
||
|
|
if fleet == null:
|
||
|
|
visible = false
|
||
|
|
return
|
||
|
|
|
||
|
|
visible = true
|
||
|
|
var target_world := Vector2(target.world_position)
|
||
|
|
var viewport_size: Vector2 = get_viewport_rect().size
|
||
|
|
var screen_position: Vector2 = get_viewport().get_canvas_transform() * target_world
|
||
|
|
var safe_margin: Vector2 = Vector2.ONE * EDGE_MARGIN + indicator.size * 0.5
|
||
|
|
var safe_rect := Rect2(safe_margin, viewport_size - safe_margin * 2.0)
|
||
|
|
var at: Vector2 = screen_position if safe_rect.has_point(screen_position) \
|
||
|
|
else edge_position(viewport_size, screen_position - viewport_size * 0.5)
|
||
|
|
indicator.position = at - indicator.size * 0.5
|
||
|
|
var toward_target: Vector2 = target_world - fleet.get_centroid()
|
||
|
|
if toward_target.length_squared() > 0.01:
|
||
|
|
indicator.rotation = toward_target.angle() + PI / 2.0
|
||
|
|
|
||
|
|
var definition: Resource = PLANET_DEFINITIONS.get_definition(
|
||
|
|
String(target.definition_id))
|
||
|
|
if definition != null:
|
||
|
|
indicator.glow_color = definition.map_color
|
||
|
|
indicator.queue_redraw()
|
||
|
|
var sectors: float = toward_target.length() / WorldGen.CHUNK_SIZE
|
||
|
|
target_label.text = "%s · %.1f SECTORS" % [
|
||
|
|
String(target.get("name", "SCANNER TARGET")).to_upper(), sectors]
|
||
|
|
_place_label(at, viewport_size)
|
||
|
|
|
||
|
|
|
||
|
|
func edge_position(viewport_size: Vector2, direction: Vector2) -> Vector2:
|
||
|
|
var center: Vector2 = viewport_size * 0.5
|
||
|
|
if direction.length_squared() <= 0.01:
|
||
|
|
return center
|
||
|
|
var half: Vector2 = center - Vector2.ONE * EDGE_MARGIN - indicator.size * 0.5
|
||
|
|
var scale_to_edge: float = minf(half.x / maxf(absf(direction.x), 0.001),
|
||
|
|
half.y / maxf(absf(direction.y), 0.001))
|
||
|
|
return center + direction * scale_to_edge
|
||
|
|
|
||
|
|
|
||
|
|
func _place_label(indicator_center: Vector2, viewport_size: Vector2) -> void:
|
||
|
|
var toward_center: Vector2 = viewport_size * 0.5 - indicator_center
|
||
|
|
if toward_center.length_squared() < 0.01:
|
||
|
|
toward_center = Vector2.DOWN
|
||
|
|
var wanted: Vector2 = indicator_center + toward_center.normalized() * 105.0 \
|
||
|
|
- target_label.size * 0.5
|
||
|
|
target_label.position = Vector2(
|
||
|
|
clampf(wanted.x, EDGE_MARGIN, viewport_size.x - target_label.size.x - EDGE_MARGIN),
|
||
|
|
clampf(wanted.y, EDGE_MARGIN, viewport_size.y - target_label.size.y - EDGE_MARGIN))
|
||
|
|
|
||
|
|
|
||
|
|
func _modal_is_open() -> bool:
|
||
|
|
for menu in get_tree().get_nodes_in_group("modal_menus"):
|
||
|
|
if menu.is_visible_in_tree():
|
||
|
|
return true
|
||
|
|
return false
|