Guide the fleet to the nearest unconquered scan target
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
This commit is contained in:
parent
fd792e8b63
commit
10d19a369b
9 changed files with 311 additions and 38 deletions
78
ui/ScannerGuidance.gd
Normal file
78
ui/ScannerGuidance.gd
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
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
|
||||
32
ui/ScannerGuidance.tscn
Normal file
32
ui/ScannerGuidance.tscn
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
[gd_scene load_steps=3 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/ScannerGuidance.gd" id="1"]
|
||||
[ext_resource type="Script" path="res://ui/IconButton.gd" id="2"]
|
||||
|
||||
[node name="ScannerGuidance" type="Control"]
|
||||
visible = false
|
||||
mouse_filter = 2
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="Indicator" type="Control" parent="."]
|
||||
mouse_filter = 2
|
||||
offset_right = 92.0
|
||||
offset_bottom = 92.0
|
||||
script = ExtResource("2")
|
||||
icon = 4
|
||||
glow_color = Color(0.3, 0.95, 1, 1)
|
||||
round_frame = true
|
||||
|
||||
[node name="TargetLabel" type="Label" parent="."]
|
||||
mouse_filter = 2
|
||||
offset_right = 420.0
|
||||
offset_bottom = 76.0
|
||||
theme_override_colors/font_color = Color(0.55, 0.95, 1, 1)
|
||||
theme_override_colors/font_outline_color = Color(0.02, 0.02, 0.08, 0.95)
|
||||
theme_override_constants/outline_size = 4
|
||||
theme_override_font_sizes/font_size = 27
|
||||
text = "SCANNER TARGET"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
Loading…
Reference in a new issue