Map in helm station

This commit is contained in:
2025-10-14 08:46:02 +02:00
parent c79e016503
commit 63d6a67d97
15 changed files with 301 additions and 11 deletions

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=14 format=3 uid="uid://didt2nsdtbmra"]
[gd_scene load_steps=17 format=3 uid="uid://didt2nsdtbmra"]
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/ship/builder/module.gd" id="1_nqe0s"]
[ext_resource type="PackedScene" uid="uid://bho8x10x4oab7" path="res://scenes/ship/builder/pieces/hullplate.tscn" id="2_foqop"]
@ -10,9 +10,12 @@
[ext_resource type="Resource" uid="uid://c4wyouanvf86c" path="res://scenes/ship/computer/panels/button_panel.tres" id="7_vmx8o"]
[ext_resource type="Resource" uid="uid://57y6igb07e10" path="res://scenes/ship/computer/panels/readout_screen.tres" id="8_83bu1"]
[ext_resource type="Resource" uid="uid://dcyr6utrk376h" path="res://scenes/ship/computer/panels/throttle_lever.tres" id="9_ixntg"]
[ext_resource type="Resource" uid="uid://dl7g67mtqkfx2" path="res://scenes/ship/computer/panels/sensor_panel.tres" id="9_xwy4s"]
[ext_resource type="Resource" uid="uid://bx7wgunvy5hfa" path="res://scenes/ship/computer/shards/helm_ship_status.tres" id="11_83bu1"]
[ext_resource type="PackedScene" uid="uid://c0bb77rmyatr0" path="res://scenes/ship/components/hardware/thruster.tscn" id="12_vmx8o"]
[ext_resource type="Resource" uid="uid://g4ho63f30vjm" path="res://scenes/ship/computer/shards/nav_selection_databank.tres" id="12_wkxbw"]
[ext_resource type="PackedScene" uid="uid://dvpy3urgtm62n" path="res://scenes/ship/components/hardware/spawner.tscn" id="13_83bu1"]
[ext_resource type="Resource" uid="uid://b0suy3sxjwhtv" path="res://scenes/ship/computer/shards/sensor_databank.tres" id="13_xwy4s"]
[node name="Module" type="Node2D"]
script = ExtResource("1_nqe0s")
@ -95,8 +98,8 @@ mass = 1.0
[node name="Station" parent="." instance=ExtResource("5_nqe0s")]
position = Vector2(0, -10)
panels = Array[ExtResource("6_oqcn4")]([ExtResource("7_vmx8o"), ExtResource("8_83bu1"), ExtResource("9_ixntg")])
installed_databanks = Array[ExtResource("6_ft4kn")]([ExtResource("7_dmrms"), ExtResource("11_83bu1")])
panels = Array[ExtResource("6_oqcn4")]([ExtResource("7_vmx8o"), ExtResource("8_83bu1"), ExtResource("9_ixntg"), ExtResource("9_xwy4s")])
installed_databanks = Array[ExtResource("6_ft4kn")]([ExtResource("7_dmrms"), ExtResource("11_83bu1"), ExtResource("12_wkxbw"), ExtResource("13_xwy4s"), null])
[node name="Thruster" parent="." instance=ExtResource("12_vmx8o")]
position = Vector2(-95, -130)
@ -120,6 +123,7 @@ main_thruster = false
[node name="MainEngine" parent="." instance=ExtResource("12_vmx8o")]
position = Vector2(0, 195)
max_thrust = 10.0
[node name="Spawner" parent="." instance=ExtResource("13_83bu1")]
position = Vector2(0, 27)

View File

@ -112,6 +112,8 @@ func _connect_internals(panel_instances: Array, shard_instances: Array):
var lever_panel
var button_panel
var readout_screen
var map_panel
var sensor_shard: SensorSystemShard
var helm_shard: HelmLogicShard
var status_shard: ShipStatusShard
@ -123,15 +125,20 @@ func _connect_internals(panel_instances: Array, shard_instances: Array):
if panel is ReadoutScreenUI:
print("Panel is ReadoutScreen: %s" % panel)
readout_screen = panel
if panel is SensorPanel: # Look for the new map panel class
map_panel = panel
for shard in shard_instances:
print(shard)
if shard is HelmLogicShard:
helm_shard = shard
if shard is ShipStatusShard:
print("Shard is Ship Status Shard: %s" % shard)
status_shard = shard
if shard is SensorSystemShard: # Look for the new sensor shard class
sensor_shard = shard
if lever_panel and helm_shard:
lever_panel.lever_value_changed.connect(helm_shard.set_throttle_input)
@ -149,3 +156,9 @@ func _connect_internals(panel_instances: Array, shard_instances: Array):
print("Wired: Status Shard -> Readout Screen")
status_shard.connect("status_updated", readout_screen.update_display)
if map_panel and sensor_shard:
# Connect the shard's "sensor_feed_updated" signal (blue wire)
# to the map's "update_sensor_feed" socket.
sensor_shard.connect("sensor_feed_updated", map_panel.update_sensor_feed)
print("Wired: Sensor Shard -> Map Panel (Sensor Feed)")

View File

@ -1,4 +1,4 @@
extends PanelContainer
extends BoxContainer
## This UI provides one "socket": a function to update its text.
class_name ReadoutScreenUI
@ -10,4 +10,3 @@ class_name ReadoutScreenUI
func update_display(text: String):
if display:
display.text = text
self.reset_size()

View File

@ -2,16 +2,17 @@
[ext_resource type="Script" uid="uid://laeom8fvlfkf" path="res://scenes/ship/computer/UI/readout_screen_panel.gd" id="1_w2pab"]
[node name="DisplayText" type="PanelContainer"]
[node name="DisplayText" type="VBoxContainer"]
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_right = 1.0
offset_right = 553.0
grow_vertical = 0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_w2pab")
[node name="RichTextLabel" type="RichTextLabel" parent="."]
layout_mode = 2
size_flags_horizontal = 4
bbcode_enabled = true
fit_content = true

View File

@ -0,0 +1,200 @@
# space_simulation/scripts/map_controller.gd
class_name SensorPanel
extends Control
signal body_selected_for_planning(body: RigidBody2D)
@export var map_icon_scene: PackedScene
const LABEL_CULLING_PIXEL_THRESHOLD = 65.0
const ICON_CULLING_PIXEL_THRESHOLD = 40.0
var map_scale: float = 0.001
var map_offset: Vector2 = Vector2.ZERO
var focal_body: RigidBody2D
var icon_map: Dictionary = {}
var followed_body: RigidBody2D = null
var map_tween: Tween
# The starting point for our lerp animation.
var follow_start_offset: Vector2
# The progress of the follow animation (0.0 to 1.0), animated by a tween.
var follow_progress: float = 0.0:
set(value):
follow_progress = value
# We must redraw every time the progress changes.
queue_redraw()
# This is now the primary input for the map. It receives the "sensor feed".
func update_sensor_feed(all_bodies: Array):
# This function replaces the old _populate_map logic.
# We'll check which bodies are new and which have been removed.
var bodies_in_feed = all_bodies.duplicate()
focal_body = bodies_in_feed[0]
# Remove icons for bodies that are no longer in the feed
for body in icon_map.keys():
if not body in bodies_in_feed:
if is_instance_valid(icon_map[body]):
icon_map[body].queue_free()
icon_map.erase(body)
# Add icons for new bodies
for body in bodies_in_feed:
if not body in icon_map:
var icon = map_icon_scene.instantiate() as MapIcon
add_child(icon)
icon.initialize(body)
icon_map[body] = icon
icon.selected.connect(_on_map_icon_selected)
icon.follow_requested.connect(_on_follow_requested)
func _process(_delta: float) -> void:
_update_icon_positions()
func _draw() -> void:
var map_center = get_rect().size / 2.0
var system_data = GameManager.get_system_data()
if system_data and system_data.belts:
for belt in system_data.belts:
var radius = belt.centered_radius * map_scale
draw_circle(map_center + map_offset, radius, Color(Color.WHITE, 0.1), false)
for body in icon_map:
if body is Asteroid: continue
var icon = icon_map[body]
if not icon.visible: continue
var path_points = []
if body is CelestialBody: path_points = OrbitalMechanics._calculate_relative_orbital_path(body)
elif body is OrbitalBody2D: path_points = OrbitalMechanics._calculate_n_body_orbital_path(body)
else: continue
var scaled_path_points = PackedVector2Array()
for point in path_points:
# Ensure path is drawn relative to the main focal body (the star)
var path_world_pos = point + focal_body.global_position
var relative_pos = path_world_pos - focal_body.global_position
var scaled_pos = (relative_pos * map_scale) + map_offset + map_center
scaled_path_points.append(scaled_pos)
if scaled_path_points.size() > 1:
draw_polyline(scaled_path_points, Color(Color.WHITE, 0.2), 1.0, true)
func _populate_map():
for child in get_children():
child.queue_free()
icon_map.clear()
var all_bodies = GameManager.get_all_trackable_bodies()
for body in all_bodies:
if not is_instance_valid(body): continue
var icon = map_icon_scene.instantiate() as MapIcon
add_child(icon)
icon.initialize(body)
icon_map[body] = icon
icon.selected.connect(_on_map_icon_selected)
icon.follow_requested.connect(_on_follow_requested)
func _update_icon_positions():
if not is_instance_valid(focal_body): return
var map_center = get_rect().size / 2.0
# --- MODIFIED: Continuous follow logic ---
if is_instance_valid(followed_body):
# Calculate the ideal offset to center the followed body.
var relative_target_pos = followed_body.global_position - focal_body.global_position
var target_offset = -relative_target_pos * map_scale
# During the initial pan, interpolate from the start to the target.
# When follow_progress reaches 1.0, this just becomes target_offset.
map_offset = follow_start_offset.lerp(target_offset, follow_progress)
# It will now use the dynamically updated map_offset.
var icon_data_for_frame = []
for body in icon_map:
var icon = icon_map[body]
icon.visible = true
icon.name_label.visible = true
var relative_pos = body.global_position - focal_body.global_position
var final_screen_pos = (relative_pos * map_scale) + map_offset + map_center
icon_data_for_frame.append({
"screen_pos": final_screen_pos,
"body": body,
"icon": icon
})
icon.position = final_screen_pos - (icon.size / 2)
for i in range(icon_data_for_frame.size()):
var data_a = icon_data_for_frame[i]
if not data_a.icon.visible:
continue
for j in range(i + 1, icon_data_for_frame.size()):
var data_b = icon_data_for_frame[j]
if not data_b.icon.visible: continue
var distance = data_a.screen_pos.distance_to(data_b.screen_pos)
if distance < ICON_CULLING_PIXEL_THRESHOLD:
if data_a.body.mass > data_b.body.mass:
data_b.icon.visible = false
else:
data_a.icon.visible = false
elif distance < LABEL_CULLING_PIXEL_THRESHOLD:
if data_a.body.mass > data_b.body.mass:
data_b.icon.name_label.visible = false
else:
data_a.icon.name_label.visible = false
# Request a redraw at the end of the update
queue_redraw()
func _gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_WHEEL_UP or event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
var zoom_factor = 1.25 if event.button_index == MOUSE_BUTTON_WHEEL_UP else 1 / 1.25
var mouse_pos = get_local_mouse_position()
var map_center = get_rect().size / 2.0
var point_under_mouse_world = (mouse_pos - map_center - map_offset) / map_scale
map_scale *= zoom_factor
var point_under_mouse_new_screen = (point_under_mouse_world * map_scale) + map_center + map_offset
map_offset += mouse_pos - point_under_mouse_new_screen
if event is InputEventMouseMotion and event.button_mask & MOUSE_BUTTON_MASK_LEFT:
# --- MODIFIED: Break the lock and reset progress ---
if is_instance_valid(followed_body):
print("Map lock disengaged by manual pan.")
followed_body = null
follow_progress = 0.0 # Reset progress
if map_tween:
map_tween.kill()
map_offset += event.relative
func _on_map_icon_selected(body: RigidBody2D):
emit_signal("body_selected_for_planning", body)
func _on_follow_requested(body: RigidBody2D):
print("Map view locking on to: ", body.name)
follow_progress = 0.0
followed_body = body
if map_tween:
map_tween.kill()
# Store the offset at the exact moment the follow begins.
follow_start_offset = map_offset
# --- REVISED: We now tween the 'follow_progress' property instead of 'map_offset' ---
map_tween = create_tween().set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN_OUT)
map_tween.tween_property(self, "follow_progress", 1.0, 1.5)

View File

@ -0,0 +1 @@
uid://bat1cxo15fnl7

View File

@ -0,0 +1,20 @@
[gd_scene load_steps=3 format=3 uid="uid://rd1c22nsru8y"]
[ext_resource type="Script" uid="uid://bat1cxo15fnl7" path="res://scenes/ship/computer/UI/sensor_panel.gd" id="1_5yxry"]
[ext_resource type="PackedScene" uid="uid://c2imrmgjthfdm" path="res://scenes/UI/MapIcon.tscn" id="2_kvnmq"]
[node name="SensorPanel" type="Control"]
layout_mode = 3
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -350.0
offset_top = -180.0
offset_right = 350.0
offset_bottom = 180.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_5yxry")
map_icon_scene = ExtResource("2_kvnmq")

View File

@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="ControlPanel" load_steps=3 format=3 uid="uid://dl7g67mtqkfx2"]
[ext_resource type="Script" uid="uid://cskf26i7vnxug" path="res://scenes/ship/computer/control_panel.gd" id="1_f0h3m"]
[ext_resource type="PackedScene" uid="uid://rd1c22nsru8y" path="res://scenes/ship/computer/UI/sensor_panel.tscn" id="2_kyhrs"]
[resource]
script = ExtResource("1_f0h3m")
ui_scene = ExtResource("2_kyhrs")
metadata/_custom_type_script = "uid://cskf26i7vnxug"

View File

@ -0,0 +1,12 @@
extends Node
class_name NavLogicShard
# --- INPUT SOCKETS ---
# This function will be connected to the map's "body_selected_for_planning" signal.
func on_body_selected(body: Node2D):
if not is_instance_valid(body): return
print("NAV SHARD: Target selected - ", body.name)
# Later, this is where we would enable maneuver calculation buttons
# and feed this target data to other datashards.

View File

@ -0,0 +1 @@
uid://t12etsdx2h38

View File

@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="Databank" load_steps=3 format=3 uid="uid://g4ho63f30vjm"]
[ext_resource type="Script" uid="uid://osk1l75vlikn" path="res://scenes/ship/computer/databank.gd" id="1_d0eru"]
[ext_resource type="Script" uid="uid://t12etsdx2h38" path="res://scenes/ship/computer/shards/nav_selection_databank.gd" id="1_mt7ap"]
[resource]
script = ExtResource("1_d0eru")
logic_script = ExtResource("1_mt7ap")
metadata/_custom_type_script = "uid://osk1l75vlikn"

View File

@ -0,0 +1,12 @@
extends Node
class_name SensorSystemShard
## This shard emits all trackable bodies as a "sensor feed" every frame.
signal sensor_feed_updated(bodies: Array)
func _physics_process(delta):
# In a more advanced game, this shard might have its own power requirements
# or could be affected by radiation, etc. For now, it just gets all bodies.
var all_bodies = GameManager.get_all_trackable_bodies()
sensor_feed_updated.emit(all_bodies)

View File

@ -0,0 +1 @@
uid://diu2tgusi3vmt

View File

@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="Databank" load_steps=3 format=3 uid="uid://b0suy3sxjwhtv"]
[ext_resource type="Script" uid="uid://osk1l75vlikn" path="res://scenes/ship/computer/databank.gd" id="1_nbqt3"]
[ext_resource type="Script" uid="uid://diu2tgusi3vmt" path="res://scenes/ship/computer/shards/sensor_databank.gd" id="1_uxkgc"]
[resource]
script = ExtResource("1_nbqt3")
logic_script = ExtResource("1_uxkgc")
metadata/_custom_type_script = "uid://osk1l75vlikn"

View File

@ -1,5 +1,4 @@
# space_simulation/scripts/map_controller.gd
class_name MapController
extends Control