Render of inputs to databanks

This commit is contained in:
olof.pettersson
2025-10-21 17:26:31 +02:00
parent 21bbbacbbe
commit d8055752d5
17 changed files with 228 additions and 85 deletions

View File

@ -1,29 +1,31 @@
[gd_scene load_steps=18 format=3 uid="uid://didt2nsdtbmra"]
[gd_scene load_steps=20 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"]
[ext_resource type="PackedScene" uid="uid://d3hitk62fice4" path="res://scenes/ship/builder/pieces/bulkhead.tscn" id="4_dmrms"]
[ext_resource type="PackedScene" uid="uid://2n42nstcj1n0" path="res://scenes/ship/components/hardware/system_station.tscn" id="5_nqe0s"]
[ext_resource type="Script" uid="uid://osk1l75vlikn" path="res://scenes/ship/computer/databank.gd" id="6_ft4kn"]
[ext_resource type="Resource" uid="uid://dghg3pbws42yu" path="res://scenes/ship/computer/shards/helm_logic_databank.tres" id="7_dmrms"]
[ext_resource type="Script" uid="uid://diu2tgusi3vmt" path="res://scenes/ship/computer/shards/sensor_databank.gd" id="9_ixntg"]
[ext_resource type="PackedScene" uid="uid://dt1t2n7dewucw" path="res://scenes/ship/computer/UI/button_panel.tscn" id="10_px2ne"]
[ext_resource type="Resource" uid="uid://bx7wgunvy5hfa" path="res://scenes/ship/computer/shards/helm_ship_status.tres" id="11_83bu1"]
[ext_resource type="Script" uid="uid://cfbyqvnvf3hna" path="res://scenes/ship/computer/shards/helm_logic_databank.gd" id="10_wkxbw"]
[ext_resource type="PackedScene" uid="uid://cdbqjkgsj02or" path="res://scenes/ship/computer/UI/readout_screen_panel.tscn" id="11_erhv3"]
[ext_resource type="Script" uid="uid://t12etsdx2h38" path="res://scenes/ship/computer/shards/nav_selection_databank.gd" id="11_xwy4s"]
[ext_resource type="Script" uid="uid://ceqdi6jobefnc" path="res://scenes/ship/computer/shards/helm_autopilot_databank.gd" id="12_4epkn"]
[ext_resource type="PackedScene" uid="uid://rd1c22nsru8y" path="res://scenes/ship/computer/UI/sensor_panel.tscn" id="12_q1rtr"]
[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="PackedScene" uid="uid://pq55j75t3fda" path="res://scenes/ship/computer/UI/throttle_lever_panel.tscn" id="13_rsa1x"]
[ext_resource type="Resource" uid="uid://dwhpjwuobcqdu" path="res://scenes/ship/computer/shards/helm_autopilot_databank.tres" id="13_xfp3q"]
[ext_resource type="Resource" uid="uid://b0suy3sxjwhtv" path="res://scenes/ship/computer/shards/sensor_databank.tres" id="13_xwy4s"]
[ext_resource type="Resource" uid="uid://6jj1jd14cdlt" path="res://scenes/ship/computer/shards/nav_hohman_planner.tres" id="15_fll2s"]
[ext_resource type="Script" uid="uid://ctgl5kxyagw0f" path="res://scenes/ship/computer/shards/helm_ship_status.gd" id="13_wkxbw"]
[ext_resource type="Script" uid="uid://ghluwjd5c5ul" path="res://scenes/ship/computer/shards/nav_brachistochrone_planner.gd" id="14_xwy4s"]
[ext_resource type="Script" uid="uid://bghu5lhcbcfmh" path="res://scenes/ship/computer/shards/nav_hohman_planner.gd" id="15_fll2s"]
[ext_resource type="Script" uid="uid://dsbn7ushwqrko" path="res://scenes/ship/computer/shards/nav_intercept_solver.gd" id="16_vufgi"]
[ext_resource type="Script" uid="uid://0f6v6iu3o5qo" path="res://scenes/ship/computer/shards/nav_projection_shard.gd" id="17_34v0b"]
[node name="Module" type="Node2D"]
physics_interpolation_mode = 2
script = ExtResource("1_nqe0s")
physics_mode = 1
mass = 2.0
inertia = 0.5
mass = 1.0
inertia = 0.0
metadata/_custom_type_script = "uid://0isnsk356que"
[node name="Hullplate" parent="." instance=ExtResource("2_foqop")]
@ -106,7 +108,7 @@ base_mass = 0.0
[node name="Station" parent="." instance=ExtResource("5_nqe0s")]
position = Vector2(0, -10)
panel_scenes = Array[PackedScene]([ExtResource("11_erhv3"), ExtResource("11_erhv3"), ExtResource("12_q1rtr"), ExtResource("10_px2ne"), ExtResource("13_rsa1x")])
installed_databanks = Array[ExtResource("6_ft4kn")]([ExtResource("11_83bu1"), ExtResource("7_dmrms"), ExtResource("13_xfp3q"), ExtResource("12_wkxbw"), ExtResource("15_fll2s"), ExtResource("13_xwy4s")])
databank_installations = Array[Script]([ExtResource("10_wkxbw"), ExtResource("12_4epkn"), ExtResource("13_wkxbw"), ExtResource("9_ixntg"), ExtResource("11_xwy4s"), ExtResource("14_xwy4s"), ExtResource("15_fll2s"), ExtResource("16_vufgi"), ExtResource("17_34v0b")])
physics_mode = 2
[node name="Thruster" parent="." instance=ExtResource("12_vmx8o")]

View File

@ -1,4 +1,3 @@
@tool
class_name SystemStation
extends Component
@ -8,6 +7,7 @@ signal occupancy_changed(is_occupied: bool)
var UiWindowScene = preload("res://scenes/UI/ui_window.tscn")
@export var panel_scenes: Array[PackedScene]
@export var databank_installations: Array[Script]
@export var installed_databanks: Array[Databank]
@onready var panel_frame: PanelFrame = $PanelFrame
@ -17,7 +17,7 @@ var wiring_schematic: WiringSchematic
# --- State ---
var occupants: Array[PilotBall] = []
var active_shard_instances: Array[Node] = []
var active_shard_instances: Array[Databank] = []
var persistent_panel_instances: Array[BasePanel] = []
var occupant_panel_map: Dictionary = {}
@ -30,17 +30,29 @@ func _ready():
if not is_instance_valid(root_module):
push_error("Station could not find its root module!")
return
for shard_resource in installed_databanks:
if not shard_resource or not shard_resource.logic_script: continue
for DatabankScript in databank_installations:
if not DatabankScript: continue
var installed_databank = DatabankScript.new()
if installed_databank is not Databank:
installed_databank.queue_free()
continue
add_child(installed_databank)
active_shard_instances.append(installed_databank)
if installed_databank.has_method("initialize"):
installed_databank.initialize(root_module)
# for shard_resource in installed_databanks:
# if not shard_resource or not shard_resource.logic_script: continue
var shard_instance = Node.new()
shard_instance.set_script(shard_resource.logic_script)
add_child(shard_instance) # Add as a permanent child
active_shard_instances.append(shard_instance)
# var shard_instance = Node.new()
# shard_instance.set_script(shard_resource.logic_script)
# add_child(shard_instance) # Add as a permanent child
# active_shard_instances.append(shard_instance)
if shard_instance.has_method("initialize"):
shard_instance.initialize(root_module)
# if shard_instance.has_method("initialize"):
# shard_instance.initialize(root_module)
_connect_internals([], active_shard_instances)
@ -107,11 +119,9 @@ func launch_interfaces_for_occupant(character: PilotBall):
ui_window.close_requested.connect(close_interface)
ui_window.title = "Helm"
# TODO: Add button to switch to wiring mode
var frame: PanelFrame = PanelFrame.new()
frame.build(panel_scenes, self)
frame.databanks = active_shard_instances
ui_window.set_content(frame)
ui_window.flip_button_pressed.connect(frame.toggle_wiring_mode)
@ -206,15 +216,15 @@ func _connect_internals(panel_instances: Array, shard_instances: Array):
if map_panel and nav_selection_shard:
# Connect the shard's "sensor_feed_updated" signal (blue wire)
# to the map's "update_sensor_feed" socket.
map_panel.connect("body_selected_for_planning", nav_selection_shard.on_body_selected)
map_panel.connect("body_selected_for_planning", nav_selection_shard.body_selected)
print("Wired: Sensor Shard -> Map Panel (Sensor Feed)")
if nav_selection_shard and hohman_planner_shard:
nav_selection_shard.target_selected.connect(hohman_planner_shard.on_target_updated)
nav_selection_shard.target_selected.connect(hohman_planner_shard.target_updated)
print("Wired: Nav Selection -> Maneuver Planner")
if hohman_planner_shard and autopilot_shard:
hohman_planner_shard.maneuver_calculated.connect(autopilot_shard.on_maneuver_received)
hohman_planner_shard.maneuver_calculated.connect(autopilot_shard.maneuver_received)
print("Wired: Maneuver Planner -> Autopilot")
if autopilot_shard and helm_shard:

View File

@ -6,6 +6,8 @@ signal body_selected_for_planning(body: OrbitalBody2D)
@export var map_icon_scene: PackedScene
@onready var map_canvas: Control = %MapCanvas
const LABEL_CULLING_PIXEL_THRESHOLD = 65.0
const ICON_CULLING_PIXEL_THRESHOLD = 40.0
@ -27,6 +29,13 @@ var follow_progress: float = 0.0:
# We must redraw every time the progress changes.
queue_redraw()
func get_output_sockets():
return ["body_selected_for_planning"]
func get_input_sockets():
return ["update_sensor_feed"]
# This is now the primary input for the map. It receives the "sensor feed".
func update_sensor_feed(all_bodies: Array[OrbitalBody2D]):
# This function replaces the old _populate_map logic.
@ -45,7 +54,7 @@ func update_sensor_feed(all_bodies: Array[OrbitalBody2D]):
for body in bodies_in_feed:
if not body in icon_map:
var icon = map_icon_scene.instantiate() as MapIcon
add_child(icon)
map_canvas.add_child(icon)
icon.initialize(body)
icon_map[body] = icon
icon.selected.connect(_on_map_icon_selected)
@ -102,9 +111,10 @@ func draw_projected_orbits(bodies_to_project: Array[OrbitalBody2D]):
func _update_icon_positions():
if not is_instance_valid(focal_body): return
var map_center = get_rect().size / 2.0
var map_center = map_canvas.get_rect().size / 2.0
# --- MODIFIED: Continuous follow logic ---
# TODO: Follow logic broke when map_canvas was introduced
# --- 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
@ -163,8 +173,8 @@ 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 mouse_pos = map_canvas.get_local_mouse_position()
var map_center = map_canvas.get_rect().size / 2.0
var point_under_mouse_world = (mouse_pos - map_center - map_offset) / map_scale
map_scale *= zoom_factor

View File

@ -7,7 +7,14 @@
clip_contents = true
layout_mode = 3
anchors_preset = 0
mouse_filter = 1
script = ExtResource("1_5yxry")
map_icon_scene = ExtResource("2_kvnmq")
grid_width = 6
grid_height = 4
[node name="MapCanvas" type="Control" parent="."]
unique_name_in_owner = true
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0

View File

@ -1,14 +1,16 @@
@tool
class_name Databank
extends Resource
extends Node
## The script containing the logic for this shard.
@export var logic_script: Script
var root_module: Module
# --- Initialization ---
func initialize(ship_root: Module):
self.root_module = ship_root
## Describes the functions this shard needs as input.
func get_input_sockets() -> Dictionary:
return {}
func get_input_sockets() -> Array[String]:
return []
## Describes the signals this shard can output.
func get_output_signals() -> Dictionary:
return {}
func get_output_sockets() -> Array[String]:
return []

View File

@ -15,6 +15,9 @@ var start_socket: Socket
var end_socket: Socket
var wiring_mode: bool = false
var databanks: Array[Databank]
var databanks_container: GridContainer
# --- NO CHANGE HERE ---
# This getter is a nice way to access only the BasePanel children.
var installed_panels: Array[BasePanel]:
@ -83,9 +86,14 @@ func build(panel_scenes: Array[PackedScene], station: SystemStation):
func _sort_children():
#print("PanelFrame Sorting children")
for child in get_children():
if child == databanks_container:
print("Databanks container found %s" % child)
fit_child_in_rect(child, Rect2(Vector2(0, rows * Constants.UI_GRID_SIZE), child.size))
continue
# Skip any nodes that aren't a BasePanel.
if not child is BasePanel:
continue
var panel := child as BasePanel
@ -102,7 +110,6 @@ func _sort_children():
fit_child_in_rect(panel, Rect2(start_pos, panel_size))
# TODO: Expose grid to install panels
# TODO: Determine if
func toggle_wiring_mode():
wiring_mode = !wiring_mode
@ -110,16 +117,74 @@ func toggle_wiring_mode():
for panel in installed_panels:
panel.set_wiring_mode(wiring_mode)
if wiring_mode:
_build_databanks(databanks)
pass
if is_instance_valid(databanks_container):
if wiring_mode: databanks_container.show()
else: databanks_container.hide()
class InstalledDatabank:
extends Control
var databank_ref: Databank
var all_sockets: Array[Socket] = []
var SocketScene: PackedScene = preload("res://scenes/ship/computer/wiring/socket.tscn")
var inputs_container: VBoxContainer
var outputs_container: VBoxContainer
func _populate_sockets():
all_sockets.clear()
if not is_instance_valid(inputs_container):
inputs_container = VBoxContainer.new()
add_child(inputs_container)
if not is_instance_valid(outputs_container):
outputs_container = VBoxContainer.new()
add_child(outputs_container)
# Populate Input Sockets
for socket_name in databank_ref.get_input_sockets():
var socket = SocketScene.instantiate()
inputs_container.add_child(socket)
socket.initialize(socket_name, Socket.SocketType.INPUT)
all_sockets.append(socket)
# Populate Output Sockets
for socket_name in databank_ref.get_output_sockets():
var socket = SocketScene.instantiate()
outputs_container.add_child(socket)
socket.initialize(socket_name, Socket.SocketType.OUTPUT)
all_sockets.append(socket)
func _build_databanks(dbs_to_install: Array[Databank]):
if not is_instance_valid(databanks_container):
databanks_container = GridContainer.new()
databanks_container.columns = columns
databanks_container.add_theme_constant_override("h_separation", Constants.UI_GRID_SIZE * 3)
databanks_container.add_theme_constant_override("v_separation", Constants.UI_GRID_SIZE + 16)
add_child(databanks_container)
var installed_databanks = databanks_container.get_children()
for to_install in dbs_to_install:
if installed_databanks.any(func(existing_db): return existing_db.databank_ref == to_install):
continue
var installed_databank = InstalledDatabank.new()
installed_databank.databank_ref = to_install
databanks_container.add_child(installed_databank)
installed_databank._populate_sockets()
func _gui_input(event: InputEvent):
if event is InputEventMouseButton:
# --- Start or End a Wire ---
if event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
print("foo")
var socket = _get_socket_at_pos(event.position)
print(socket)
if socket:
current_state = WiringState.DRAGGING_WIRE
if not start_socket:

View File

@ -1,5 +1,5 @@
# scenes/ship/computer/shards/autopilot_databank.gd
extends Node
extends Databank
class_name AutopilotShard
signal execution_state_changed(is_executing: bool, status: String)
@ -9,8 +9,13 @@ signal request_rotation(r: float)
signal request_rotation_thrust(r: float)
signal request_main_engine_thrust(t: float)
# --- References ---
var root_module: Module
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return ["maneuver_received", "execute_plan", "set_thruster_calibration"]
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["execution_state_changed", "fmt_out", "request_attitude_hold", "request_rotation", "request_rotation_thrust", "request_main_engine_thrust"]
# --- State ---
enum State { IDLE, WAITING_FOR_WINDOW, EXECUTING_BURN }
@ -22,9 +27,6 @@ var is_executing: bool = false
var status: String = ""
var current_timer: SceneTreeTimer
func initialize(ship_root: Module):
self.root_module = ship_root
func _process(delta):
var fmt = ""
var state_name = State.keys()[current_state]
@ -39,7 +41,7 @@ func _process(delta):
# INPUT SOCKET: Connected to the ManeuverPlanner's "maneuver_calculated" signal.
func on_maneuver_received(plan: Array[DataTypes.ImpulsiveBurnPlan]):
func maneuver_received(plan: Array[DataTypes.ImpulsiveBurnPlan]):
current_plan = plan
print("AUTOPILOT: Maneuver plan received.")
status = "Plan Received.\nPress Execute."

View File

@ -1,20 +1,26 @@
extends Node
extends Databank
class_name HelmLogicShard
# --- References ---
var root_module: Module
var thrusters: Array[Thruster] = []
@onready var thrusters: Array[Thruster] = []
# --- PD Controller Constants ---
@export var HOLD_KP: float = 8000.0 # Proportional gain
@export var HOLD_KD: float = 1200.0 # Derivative gain
var target_rotation_rad: float = 0.0
@onready var target_rotation_rad: float = 0.0
var attitude_hold_enabled: bool = false
var thruster_calibration_data: DataTypes.ThrusterCalibration
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return ["shutdown_rcs", "calibrate_rcs_performance", "set_throttle_input", "set_rotation_input", "set_desired_rotation", "set_attitude_hold"]
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["thruster_calibrated"]
# The Station calls this after instantiating the shard.
func initialize(ship_root: Module):
self.root_module = ship_root
@ -28,7 +34,6 @@ func initialize(ship_root: Module):
# Default to holding the initial attitude.
target_rotation_rad = root_module.rotation
func _physics_process(_delta):
if not is_instance_valid(root_module): return
@ -81,7 +86,6 @@ func set_attitude_hold(hold: bool):
# --- LOGIC (Migrated from ThrusterController.gd) ---
func _perform_manual_hold():
var error = shortest_angle_between(root_module.rotation, target_rotation_rad)
if abs(error) > 0.001:
var desired_torque = (error * HOLD_KP) - (root_module.angular_velocity * HOLD_KD)

View File

@ -1,16 +1,22 @@
extends Node
extends Databank
class_name ShipStatusShard
## This shard emits a signal with the formatted ship status text.
signal status_updated(text: String)
var root_module: Module
# Called by the Station when it's created.
func initialize(ship_root: Module):
self.root_module = ship_root
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return []
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["status_updated"]
func _physics_process(delta):
if not is_instance_valid(root_module):
return

View File

@ -1,20 +1,23 @@
# space_simulation/scenes/ship/computer/shards/nav_brachistochrone_planner.gd
extends Node
extends Databank
class_name BrachistochronePlannerShard
## Emitted when a maneuver plan has been successfully calculated.
signal maneuver_calculated(plan: Array[DataTypes.ImpulsiveBurnPlan])
# --- References ---
var root_module: Module
var target_body: OrbitalBody2D = null
# --- Initialization ---
func initialize(ship_root: Module):
self.root_module = ship_root
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return ["target_updated", "calculate_hohmann_transfer"]
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["maneuver_calculated"]
# INPUT SOCKET: Connected to the NavSelectionShard's "target_selected" signal.
func on_target_updated(new_target: OrbitalBody2D):
func target_updated(new_target: OrbitalBody2D):
print("BRACHISTOCHRONE PLANNER: Target received %s." % new_target.name)
target_body = new_target

View File

@ -1,23 +1,27 @@
# scenes/ship/computer/shards/maneuver_planner_databank.gd
extends Node
extends Databank
class_name HohmanPlannerShard
## Emitted when a maneuver plan has been successfully calculated.
signal maneuver_calculated(plan: Array[DataTypes.ImpulsiveBurnPlan])
# --- References ---
var root_module: Module
var selection_shard: NavSelectionShard
var target_body: OrbitalBody2D = null
# --- Configurations ---
var boost_factor: float = 1.0
func initialize(ship_root: Module):
self.root_module = ship_root
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return ["target_updated", "calculate_hohmann_transfer"]
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["maneuver_calculated"]
# INPUT SOCKET: Connected to the NavSelectionShard's "target_selected" signal.
func on_target_updated(new_target: OrbitalBody2D):
func target_updated(new_target: OrbitalBody2D):
print("MANEUVER PLANNER: Target recieved %s." % new_target)
target_body = new_target

View File

@ -1,14 +1,17 @@
# space_simulation/scenes/ship/computer/shards/nav_intercept_solver.gd
extends Node
extends Databank
class_name InterceptSolverShard
signal solution_found(plan: Array[DataTypes.ImpulsiveBurnPlan])
signal solution_impossible
var root_module: Module
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return ["project_n_body_paths"]
func initialize(ship_root: Module):
self.root_module = ship_root
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["solution_found", "solution_impossible"]
# INPUT SOCKET: Planners will call this with a projected path.
func solve_rendezvous_plan(

View File

@ -1,10 +1,18 @@
# space_simulation/scenes/ship/computer/shards/nav_path_projection.gd
extends Node
extends Databank
class_name PathProjectionShard
## Emitted after a requested path has been calculated.
signal projected_system_bus(paths: Array[DataTypes.PathPoint])
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return ["project_n_body_paths"]
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["projected_system_bus"]
## Projects the future paths of an array of bodies interacting with each other.
## Returns a dictionary mapping each body to its calculated PackedVector2Array path.
func project_n_body_paths(

View File

@ -1,5 +1,5 @@
# scenes/ship/computer/shards/nav_selection_databank.gd
extends Node
extends Databank
class_name NavSelectionShard
## Emitted whenever a new navigation target is selected from the map.
@ -7,8 +7,16 @@ signal target_selected(body: OrbitalBody2D)
var selected_body: OrbitalBody2D = null
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return ["body_selected"]
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["target_selected"]
# INPUT SOCKET: This function is connected to the SensorPanel's "body_selected" signal.
func on_body_selected(body: OrbitalBody2D):
func body_selected(body: OrbitalBody2D):
if is_instance_valid(body) and body != selected_body:
print("NAV SELECTION: New target acquired - ", body.name)
selected_body = body

View File

@ -1,4 +1,4 @@
extends Node
extends Databank
class_name SensorSystemShard
signal sensor_feed_updated(bodies: Array[OrbitalBody2D])
@ -7,6 +7,14 @@ signal sensor_feed_updated(bodies: Array[OrbitalBody2D])
@export var projection_steps: int = 500
@export var time_per_step: float = 60.0 # Project at 1-minute intervals
## Describes the functions this shard needs as input.
func get_input_sockets() -> Array[String]:
return []
## Describes the signals this shard can output.
func get_output_sockets() -> Array[String]:
return ["sensor_feed_updated"]
# We use _process instead of _physics_process to avoid slowing down the physics thread.
# This calculation can happen on a separate frame if needed.
func _process(_delta: float):

View File

@ -18,7 +18,8 @@ var socket_type: SocketType
func initialize(s_name: String, s_type: SocketType):
socket_name = s_name
socket_type = s_type
label.text = socket_name
icon.tooltip_text = socket_name
if socket_type == SocketType.INPUT:
icon.color = Color.DODGER_BLUE

View File

@ -34,13 +34,13 @@ func _ready():
# --- PUBLIC FORCE APPLICATION METHODS ---
# This method is called by a component (like Thruster) at its global position.
func apply_force(force: Vector2, position: Vector2 = self.global_position):
func apply_force(force: Vector2, pos: Vector2 = self.global_position):
# This is the force routing logic.
match physics_mode:
PhysicsMode.INDEPENDENT:
_add_forces(force, position)
_add_forces(force, pos)
PhysicsMode.COMPOSITE:
_add_forces(force, position)
_add_forces(force, pos)
## If we are the root, accumulate the force and calculate torque on the total body.
#accumulated_force += force
#
@ -56,7 +56,7 @@ func apply_force(force: Vector2, position: Vector2 = self.global_position):
if p is OrbitalBody2D:
# Recursively call the parent's apply_force method.
# This sends the force (and its original global position) up the chain.
p.apply_force(force, position)
p.apply_force(force, pos)
return # Stop at the first OrbitalBody2D parent
p = p.get_parent()