92 lines
3.7 KiB
GDScript
92 lines
3.7 KiB
GDScript
extends Control
|
|
|
|
const DOT_RADIUS := 3.0
|
|
const SCAN_RING_RADIUS := 48.0
|
|
var player: CharacterBody2D
|
|
var targets: Array[Node2D] = []
|
|
var _elapsed := 0.0
|
|
var _previous_player_position := Vector2.ZERO
|
|
var _player_position := Vector2.ZERO
|
|
var _positions: Dictionary = {}
|
|
|
|
func _ready() -> void:
|
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
process_physics_priority = 10
|
|
_player_position = player.global_position
|
|
_previous_player_position = _player_position
|
|
|
|
func _process(delta: float) -> void:
|
|
_elapsed += delta
|
|
queue_redraw()
|
|
|
|
func _physics_process(_delta: float) -> void:
|
|
if not is_instance_valid(player):
|
|
return
|
|
_previous_player_position = _player_position
|
|
_player_position = player.global_position
|
|
if _previous_player_position.distance_to(_player_position) > 600.0:
|
|
_previous_player_position = _player_position
|
|
targets.clear()
|
|
var next_positions: Dictionary = {}
|
|
for group in ["enemies", "exploration_pois", "scanner_planets"]:
|
|
for target in get_tree().get_nodes_in_group(group):
|
|
if player.get_parent().is_ancestor_of(target) and not target.is_queued_for_deletion() and is_target_in_range(target):
|
|
if group == "scanner_planets" and (not bool(target.get("is_protected")) or not bool(player.get_parent().get("system_cleared"))):
|
|
continue
|
|
targets.append(target)
|
|
var current: Vector2 = target.global_position
|
|
var previous: Vector2 = _positions.get(target.get_instance_id(), [current, current])[1]
|
|
if previous.distance_to(current) > 600.0:
|
|
previous = current
|
|
next_positions[target.get_instance_id()] = [previous, current]
|
|
_positions = next_positions
|
|
|
|
func get_scan_range() -> float:
|
|
var transform := get_viewport().get_canvas_transform()
|
|
var half_screen := get_viewport_rect().size * 0.5
|
|
var visible_radius := Vector2(half_screen.x / transform.x.length(), half_screen.y / transform.y.length()).length()
|
|
return maxf(float(player.get("base_scanner_range")), visible_radius + 150.0) + float(player.get("scanner_range")) - float(player.get("base_scanner_range"))
|
|
|
|
func is_target_in_range(target: Node2D) -> bool:
|
|
return player.global_position.distance_to(target.global_position) <= get_scan_range()
|
|
|
|
func _draw() -> void:
|
|
if not is_instance_valid(player) or bool(player.get("_is_destroyed")) or bool(player.get("is_docked")):
|
|
return
|
|
var canvas := get_viewport().get_canvas_transform()
|
|
var to_local := get_global_transform().affine_inverse()
|
|
# Match the rendered ship and targets, rather than their discrete physics positions.
|
|
var fraction := Engine.get_physics_interpolation_fraction()
|
|
var origin: Vector2 = to_local * (canvas * _previous_player_position.lerp(_player_position, fraction))
|
|
var radius := SCAN_RING_RADIUS * canvas.x.length()
|
|
var pulse := (sin(_elapsed * TAU * 0.9) + 1.0) * 0.5
|
|
for target in targets:
|
|
if not is_instance_valid(target) or target.is_queued_for_deletion():
|
|
continue
|
|
var color := Color("ff5555")
|
|
if target.is_in_group("enemies"):
|
|
if float(target.get("hull")) <= 0:
|
|
continue
|
|
elif target.is_in_group("scanner_planets"):
|
|
color = Color("b68aff")
|
|
else:
|
|
if bool(target.get("_claimed")):
|
|
continue
|
|
match str(target.get("kind")):
|
|
"asteroid":
|
|
color = Color("a8adb5")
|
|
"wreck":
|
|
color = Color("b98050")
|
|
"ruin":
|
|
color = Color("6be58b")
|
|
_:
|
|
continue
|
|
var positions: Array = _positions[target.get_instance_id()]
|
|
var target_position: Vector2 = positions[0].lerp(positions[1], fraction)
|
|
var offset: Vector2 = to_local * (canvas * target_position) - origin
|
|
if offset.length_squared() < 0.01:
|
|
continue
|
|
var point := origin + offset.normalized() * radius
|
|
draw_circle(point, DOT_RADIUS + 3.0 + pulse * 2.0, Color(color, 0.08 + pulse * 0.12), true, -1.0, true)
|
|
draw_circle(point, DOT_RADIUS, Color(color, 0.55 + pulse * 0.45), true, -1.0, true)
|