WIP Persistent panels
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=23 format=3 uid="uid://didt2nsdtbmra"]
|
||||
[gd_scene load_steps=22 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"]
|
||||
@ -9,7 +9,6 @@
|
||||
[ext_resource type="Resource" uid="uid://dghg3pbws42yu" path="res://scenes/ship/computer/shards/helm_logic_databank.tres" id="7_dmrms"]
|
||||
[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="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"]
|
||||
@ -27,8 +26,8 @@
|
||||
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")]
|
||||
@ -110,10 +109,17 @@ base_mass = 0.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"), ExtResource("9_xwy4s")])
|
||||
panel_scenes = Array[PackedScene]([ExtResource("10_px2ne"), ExtResource("11_erhv3"), ExtResource("12_q1rtr"), ExtResource("13_rsa1x")])
|
||||
panels = Array[ExtResource("6_oqcn4")]([ExtResource("8_83bu1"), ExtResource("8_83bu1"), ExtResource("9_xwy4s"), ExtResource("7_vmx8o")])
|
||||
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")])
|
||||
grid_size_x = 1
|
||||
grid_size_y = 1
|
||||
attachment_type = 0
|
||||
physics_mode = 2
|
||||
base_mass = 1.0
|
||||
linear_velocity = Vector2(0, 0)
|
||||
angular_velocity = 0.0
|
||||
inertia = 1.0
|
||||
|
||||
[node name="Thruster" parent="." instance=ExtResource("12_vmx8o")]
|
||||
position = Vector2(-95, -130)
|
||||
|
||||
@ -9,8 +9,7 @@ signal occupancy_changed(is_occupied: bool)
|
||||
@export var panel_scenes: Array[PackedScene]
|
||||
@export var installed_databanks: Array[Databank]
|
||||
|
||||
@onready var panel_frame = $PanelFrame
|
||||
|
||||
@onready var panel_frame: PanelFrame = $PanelFrame
|
||||
|
||||
# --- State ---
|
||||
var occupants: Array[PilotBall] = []
|
||||
@ -30,21 +29,17 @@ func _ready():
|
||||
push_error("Station could not find its root module!")
|
||||
return
|
||||
|
||||
|
||||
var panel_world: World2D = World2D.new()
|
||||
for panel_scene in panel_scenes:
|
||||
if not panel_scene: continue
|
||||
|
||||
var panel_instance = panel_scene.instantiate()
|
||||
if not panel_instance is BasePanel:
|
||||
panel_instance.queue_free()
|
||||
continue
|
||||
|
||||
panel_frame.add_child(panel_instance)
|
||||
persistent_panel_instances.append(panel_instance)
|
||||
|
||||
# Make the panels invisible in the main game world
|
||||
#panel_instance.visible = false
|
||||
panel_frame.populate_panels(panel_scenes)
|
||||
#for panel_scene in panel_scenes:
|
||||
#if not panel_scene: continue
|
||||
#
|
||||
#var panel_instance = panel_scene.instantiate()
|
||||
#if not panel_instance is BasePanel:
|
||||
#panel_instance.queue_free()
|
||||
#continue
|
||||
#
|
||||
#panel_frame.add_child(panel_instance)
|
||||
#persistent_panel_instances.append(panel_instance)
|
||||
|
||||
for shard_resource in installed_databanks:
|
||||
if not shard_resource or not shard_resource.logic_script: continue
|
||||
@ -58,6 +53,7 @@ func _ready():
|
||||
shard_instance.initialize(root_module)
|
||||
|
||||
_connect_internals(persistent_panel_instances, active_shard_instances)
|
||||
|
||||
# Future: Connections wbetween shards and other hardware would be made here.
|
||||
|
||||
func _process(_delta):
|
||||
@ -82,7 +78,7 @@ func occupy(character: PilotBall):
|
||||
character.global_position = global_position # Move character to the station
|
||||
|
||||
# --- FIX: Launch UI for THIS character only ---
|
||||
launch_interfaces_for_occupant(character)
|
||||
on_player_interact(character)
|
||||
|
||||
occupancy_changed.emit(true)
|
||||
|
||||
@ -100,49 +96,18 @@ func disengage(character: PilotBall):
|
||||
|
||||
# --- UI MANAGEMENT ---
|
||||
|
||||
func launch_interfaces_for_occupant(character: PilotBall):
|
||||
print("foo")
|
||||
var ui_container = character.get_ui_container()
|
||||
if not ui_container is Control: return
|
||||
print("bar")
|
||||
var viewports = []
|
||||
# This function is called when a player character interacts with the station.
|
||||
func on_player_interact(player: PilotBall):
|
||||
# 1. Ask our PanelWorld for a new window view.
|
||||
var window_view = await panel_frame.create_window_view()
|
||||
|
||||
# 1. Create a container for our render setup
|
||||
var viewport_container = SubViewportContainer.new()
|
||||
viewport_container.stretch = true
|
||||
viewport_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
viewport_container.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
ui_container.add_child(viewport_container)
|
||||
# 2. Pass this fully-formed window to the player.
|
||||
var player_ui_container = player.get_ui_container()
|
||||
if is_instance_valid(player_ui_container):
|
||||
player_ui_container.add_child(window_view)
|
||||
window_view.popup_centered()
|
||||
|
||||
# 2. Create the SubViewport
|
||||
var sub_viewport = SubViewport.new()
|
||||
sub_viewport.world_2d = get_world_2d() # Render the same world
|
||||
sub_viewport.size = panel_frame.size # Match the panel's size
|
||||
viewport_container.add_child(sub_viewport)
|
||||
|
||||
# 3. Create a camera to look at the panel
|
||||
var camera = Camera2D.new()
|
||||
|
||||
# This camera will ONLY see Layer 2 ("UI_Panels").
|
||||
camera.set_cull_mask_value(1, false) # Hide Layer 1 (Default World)
|
||||
camera.set_cull_mask_value(2, true) # Show Layer 2 (UI_Panels)
|
||||
|
||||
camera.global_position = panel_frame.global_position
|
||||
var panel_max_dim = max(panel_frame.size.x, panel_frame.size.y)
|
||||
var viewport_min_dim = min(sub_viewport.size.x, sub_viewport.size.y)
|
||||
if panel_max_dim > 0 and viewport_min_dim > 0:
|
||||
camera.zoom = Vector2.ONE * (panel_max_dim / viewport_min_dim) * 1.1
|
||||
sub_viewport.add_child(camera)
|
||||
|
||||
# 4. Connect input forwarding
|
||||
viewport_container.gui_input.connect(
|
||||
func(event): sub_viewport.push_input(event)
|
||||
)
|
||||
|
||||
viewports.append(viewport_container)
|
||||
|
||||
occupant_panel_map[character] = viewports # We now store the viewports to clean up
|
||||
|
||||
occupant_panel_map[player] = window_view # We now store the viewports to clean up
|
||||
|
||||
func close_interfaces_for_occupant(character: PilotBall):
|
||||
if occupant_panel_map.has(character):
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://2n42nstcj1n0"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://2n42nstcj1n0"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://2reyxkr78ra0" path="res://scenes/ship/components/hardware/system_station.gd" id="1_8usqu"]
|
||||
[ext_resource type="Script" uid="uid://cgryue4aay4oa" path="res://scenes/ship/computer/panels/panel_world.gd" id="2_3288w"]
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_8usqu"]
|
||||
|
||||
@ -15,8 +16,6 @@ mass = 1.0
|
||||
shape = SubResource("CircleShape2D_8usqu")
|
||||
debug_color = Color(0, 0.551549, 0.918484, 0.42)
|
||||
|
||||
[node name="PanelFrame" type="GridContainer" parent="."]
|
||||
visibility_layer = 2
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
columns = 12
|
||||
[node name="PanelFrame" type="Node" parent="."]
|
||||
script = ExtResource("2_3288w")
|
||||
metadata/_custom_type_script = "uid://cgryue4aay4oa"
|
||||
|
||||
88
scenes/ship/computer/panels/panel_world.gd
Normal file
88
scenes/ship/computer/panels/panel_world.gd
Normal file
@ -0,0 +1,88 @@
|
||||
# scripts/panel_world.gd
|
||||
class_name PanelFrame
|
||||
extends Node
|
||||
|
||||
# This PanelWorld owns a separate world just for its UI panels.
|
||||
var ui_world: World2D = World2D.new()
|
||||
|
||||
# The root node for all panels within the UI world.
|
||||
var panel_root: Control
|
||||
var grid_container: GridContainer
|
||||
|
||||
func _ready():
|
||||
# We need a SubViewport to host our separate world and keep it running.
|
||||
var viewport = SubViewport.new()
|
||||
viewport.world_2d = ui_world
|
||||
add_child(viewport)
|
||||
|
||||
# Create the root node for the panels inside the new world.
|
||||
panel_root = Control.new()
|
||||
panel_root.name = "PanelRoot"
|
||||
|
||||
# We add the panel_root to the scene tree via the viewport to make it active.
|
||||
viewport.add_child(panel_root)
|
||||
|
||||
## The station calls this to populate the world with its panels.
|
||||
func populate_panels(panel_scenes: Array[PackedScene]):
|
||||
if not is_instance_valid(panel_root): return
|
||||
|
||||
# Add the GridContainer to the panel_root to manage the layout.
|
||||
grid_container = GridContainer.new()
|
||||
panel_root.add_child(grid_container)
|
||||
|
||||
for panel_scene in panel_scenes:
|
||||
if not panel_scene: continue
|
||||
var panel_instance = panel_scene.instantiate()
|
||||
grid_container.add_child(panel_instance)
|
||||
# Any other setup for the panels would go here.
|
||||
|
||||
## The station calls this to get a view for a player.
|
||||
func create_window_view() -> Window:
|
||||
# Create a draggable Window for the player's UI.
|
||||
var window = Window.new()
|
||||
window.title = get_parent().name # Title the window after the station
|
||||
window.unresizable = true
|
||||
window.size = grid_container.size # Give it a default minimum size
|
||||
window.close_requested.connect(window.queue_free)
|
||||
|
||||
# Create the SubViewport setup to render the view.
|
||||
var vp_container = SubViewportContainer.new()
|
||||
window.add_child(vp_container)
|
||||
vp_container.stretch = true
|
||||
vp_container.anchors_preset = Control.LayoutPreset.PRESET_FULL_RECT
|
||||
vp_container.size = grid_container.size
|
||||
|
||||
var sub_viewport = SubViewport.new()
|
||||
sub_viewport.world_2d = ui_world # IMPORTANT: Point to our private UI world
|
||||
sub_viewport.size = Vector2(400,300)
|
||||
sub_viewport.transparent_bg = true
|
||||
vp_container.add_child(sub_viewport)
|
||||
|
||||
# Wait for the next idle frame. By this time, the GridContainer will have
|
||||
# calculated its size based on the panels added to it.
|
||||
await get_tree().process_frame
|
||||
|
||||
# Create a camera for this specific view.
|
||||
var camera = Camera2D.new()
|
||||
|
||||
# Center the camera on the panel layout.
|
||||
#camera.position = panel_root.size / 2
|
||||
# 2. Calculate the correct zoom to fit all the panels in the view.
|
||||
var bounds = panel_root.get_rect()
|
||||
var zoom_x = bounds.size.x / sub_viewport.size.x
|
||||
var zoom_y = bounds.size.y / sub_viewport.size.y
|
||||
# 2. Set the OFFSET to be the center of the panel grid.
|
||||
# This shifts the camera's VIEW to be centered on the panels.
|
||||
sub_viewport.add_child(camera)
|
||||
camera.offset = grid_container.size
|
||||
|
||||
# Center the camera on the grid of panels.
|
||||
#camera.position = panel_root.size / 2.0
|
||||
|
||||
# Use the larger zoom factor to ensure everything fits, and add a 10% margin.
|
||||
#camera.zoom = Vector2.ONE * max(zoom_x, zoom_y) * 1.1
|
||||
|
||||
# Forward input from the screen overlay to the world-space panel.
|
||||
vp_container.gui_input.connect(func(event): sub_viewport.push_input(event.duplicate()))
|
||||
|
||||
return window
|
||||
1
scenes/ship/computer/panels/panel_world.gd.uid
Normal file
1
scenes/ship/computer/panels/panel_world.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cgryue4aay4oa
|
||||
@ -6,60 +6,37 @@ extends Node
|
||||
var active_panels: Dictionary = {}
|
||||
|
||||
## The main entry point for the system.
|
||||
func request_popup(panel_scene: PackedScene, context_object: Node, player: Node):
|
||||
var panel_instance: Control
|
||||
|
||||
# 1. Check if a panel for this object already exists.
|
||||
if active_panels.has(context_object):
|
||||
panel_instance = active_panels[context_object]
|
||||
else:
|
||||
# 2. If not, create the single, persistent UI panel.
|
||||
panel_instance = panel_scene.instantiate()
|
||||
add_child(panel_instance) # Add it to the PopupManager to keep it in the scene tree
|
||||
|
||||
# Assign it to the "UI_Panels" render layer (Project Settings -> Layer Names -> 2D Render)
|
||||
panel_instance.layer = 2
|
||||
|
||||
# Initialize it with the context object
|
||||
if panel_instance.has_method("initialize"):
|
||||
panel_instance.initialize(context_object)
|
||||
|
||||
active_panels[context_object] = panel_instance
|
||||
|
||||
# 3. Create a viewport "window" for the specific player who requested it.
|
||||
_create_viewport_for_player(panel_instance, player)
|
||||
|
||||
func _create_viewport_for_player(panel_instance: Control, player: Node, world: World2D):
|
||||
# Get the player's personal UI container (e.g., from PilotBall.gd)
|
||||
var ui_container = player.get_ui_container()
|
||||
if not ui_container: return
|
||||
|
||||
# Create a draggable Window for the UI
|
||||
var window = Window.new()
|
||||
window.title = panel_instance.name
|
||||
window.size = panel_instance.size + Vector2(20, 40) # Add space for title bar
|
||||
window.close_requested.connect(window.queue_free) # Close button works automatically
|
||||
ui_container.add_child(window)
|
||||
|
||||
# Create the SubViewport setup
|
||||
var vp_container = SubViewportContainer.new()
|
||||
vp_container.stretch = true
|
||||
vp_container.anchors_preset = Control.PRESET_FULL_RECT
|
||||
window.add_child(vp_container)
|
||||
|
||||
var sub_viewport = SubViewport.new()
|
||||
sub_viewport.world_2d = world
|
||||
sub_viewport.size = panel_instance.size
|
||||
sub_viewport.transparent_bg = true
|
||||
vp_container.add_child(sub_viewport)
|
||||
|
||||
# Create and configure the camera
|
||||
var camera = Camera2D.new()
|
||||
camera.set_cull_mask_value(1, false) # Don't see the default world
|
||||
camera.set_cull_mask_value(2, true) # ONLY see the "UI_Panels" layer
|
||||
camera.global_position = panel_instance.global_position
|
||||
# You can add zoom logic here if needed, similar to the station implementation
|
||||
sub_viewport.add_child(camera)
|
||||
|
||||
# Forward input from the screen overlay to the world-space panel
|
||||
vp_container.gui_input.connect(func(event): sub_viewport.push_input(event.duplicate()))
|
||||
#func request_popup(panel_world: World2D, player: PilotBall):
|
||||
## Get the player's personal UI container (e.g., from PilotBall.gd)
|
||||
#var ui_container = player.get_ui_container()
|
||||
#if not ui_container: return
|
||||
#
|
||||
## Create a draggable Window for the UI
|
||||
#var window = Window.new()
|
||||
#window.title = panel_instance.name
|
||||
#window.size = panel_instance.size + Vector2(20, 40) # Add space for title bar
|
||||
#window.close_requested.connect(window.queue_free) # Close button works automatically
|
||||
#ui_container.add_child(window)
|
||||
#
|
||||
## Create the SubViewport setup
|
||||
#var vp_container = SubViewportContainer.new()
|
||||
#vp_container.stretch = true
|
||||
#vp_container.anchors_preset = Control.PRESET_FULL_RECT
|
||||
#window.add_child(vp_container)
|
||||
#
|
||||
#var sub_viewport = SubViewport.new()
|
||||
#sub_viewport.world_2d
|
||||
#sub_viewport.size = panel_instance.size
|
||||
#sub_viewport.transparent_bg = true
|
||||
#vp_container.add_child(sub_viewport)
|
||||
#
|
||||
## Create and configure the camera
|
||||
#var camera = Camera2D.new()
|
||||
#camera.set_cull_mask_value(1, false) # Don't see the default world
|
||||
#camera.set_cull_mask_value(2, true) # ONLY see the "UI_Panels" layer
|
||||
#camera.global_position = panel_instance.global_position
|
||||
## You can add zoom logic here if needed, similar to the station implementation
|
||||
#sub_viewport.add_child(camera)
|
||||
#
|
||||
## Forward input from the screen overlay to the world-space panel
|
||||
#vp_container.gui_input.connect(func(event): sub_viewport.push_input(event.duplicate()))
|
||||
|
||||
Reference in New Issue
Block a user