From f84073828809a845fdda30a80821221498f761c1 Mon Sep 17 00:00:00 2001 From: Rob Kelly Date: Fri, 27 Jun 2025 17:46:08 -0600 Subject: [PATCH] MP3 UI scrolling --- src/equipment/mp3_player/mp3_controller.tscn | 2 - src/equipment/mp3_player/mp3_player.gd | 7 +- src/equipment/mp3_player/mp3_player.tscn | 2 +- .../mp3_player/retro_selector_list.gd | 52 ++++++- .../mp3_player/retro_selector_list.tscn | 143 +++++++++++++++++- src/world/world.gd | 3 +- 6 files changed, 190 insertions(+), 19 deletions(-) diff --git a/src/equipment/mp3_player/mp3_controller.tscn b/src/equipment/mp3_player/mp3_controller.tscn index faff264..e90d0c6 100644 --- a/src/equipment/mp3_player/mp3_controller.tscn +++ b/src/equipment/mp3_player/mp3_controller.tscn @@ -228,8 +228,6 @@ text = "" [node name="RetroSelectorList" parent="." instance=ExtResource("3_n8ehr")] unique_name_in_owner = true -offset_bottom = 11.0 -options = Array[String](["aaa", "bbb", "ccc", "defghijk"]) [node name="TransitionPlayer" type="AnimationPlayer" parent="."] unique_name_in_owner = true diff --git a/src/equipment/mp3_player/mp3_player.gd b/src/equipment/mp3_player/mp3_player.gd index 12dbcc3..e9ca0c9 100644 --- a/src/equipment/mp3_player/mp3_player.gd +++ b/src/equipment/mp3_player/mp3_player.gd @@ -1,7 +1,8 @@ extends Tool ## Pump up the jamz! -const RUMBLE_INTENSITY = 0.006 +const BIG_RUMBLE = 0.006 +const SMALL_RUMBLE = 0.0009 const RUMBLE_DROPOFF = 0.8 @onready var mp3_controller: MP3Controller = %MP3Controller @@ -20,12 +21,12 @@ func unlocked() -> bool: func fire() -> void: if not firing: firing = true - rumbler.intensity = RUMBLE_INTENSITY + rumbler.intensity = BIG_RUMBLE mp3_controller.select() func switch_mode() -> void: - rumbler.intensity = RUMBLE_INTENSITY + rumbler.intensity = SMALL_RUMBLE mp3_controller.cancel() diff --git a/src/equipment/mp3_player/mp3_player.tscn b/src/equipment/mp3_player/mp3_player.tscn index 22b9bae..8da4bf9 100644 --- a/src/equipment/mp3_player/mp3_player.tscn +++ b/src/equipment/mp3_player/mp3_player.tscn @@ -74,7 +74,7 @@ render_target_update_mode = 4 [node name="ScreenTransform" type="Marker2D" parent="HUDTool/Rumbler/Position/HUDElement/DeviceScreenMask/SubViewportContainer/SubViewport"] texture_filter = 1 -position = Vector2(17.939, -1) +position = Vector2(17.939, -2) rotation = 0.139626 skew = 0.0331613 diff --git a/src/equipment/mp3_player/retro_selector_list.gd b/src/equipment/mp3_player/retro_selector_list.gd index 0336b64..dcfecd6 100644 --- a/src/equipment/mp3_player/retro_selector_list.gd +++ b/src/equipment/mp3_player/retro_selector_list.gd @@ -1,16 +1,17 @@ +@tool class_name RetroSelectorList extends Control -const DEFAULT_HEIGHT := 76.0 +const DEFAULT_HEIGHT := 79.0 const LINE_HEIGHT_PX := 11 const LINE_HEIGHT_OFFSET := 1 const SELECTION_SMOOTHING := 8.0 +const MAX_LINES := 7 const BLINK_INTERVAL := 0.2 @export var options: Array[String] = [] @export var selection_idx := 0: - set(value): - selection_idx = wrapi(value, 0, options.size()) + set = _set_selection_idx @export var expanded := true: set(value): if value != expanded: @@ -22,16 +23,49 @@ const BLINK_INTERVAL := 0.2 @export var tween_scale := 0.24 +@export var debug_rebuild := false: + set(value): + if value: + rebuild_list() + var _active_tween: Tween +var _scroll_line := 0 + @onready var screen_bounds_container: Control = %ScreenBoundsContainer +@onready var scrolling_container: Control = %ScrollingContainer @onready var title_list: VBoxContainer = %TitleList @onready var selection_mask: ColorRect = %SelectionMask +@onready var scroll_arrows: Control = %ScrollArrows +@onready var up_arrow: Label = %UpArrow +@onready var down_arrow: Label = %DownArrow + func _ready() -> void: rebuild_list() +func _set_selection_idx(value: float) -> void: + selection_idx = wrapi(value, 0, options.size()) + + _update_scrolling() + + +func _update_scrolling() -> void: + # Custom scrolling logic + var max_line_idx := MAX_LINES - 1 + var rel_selection := selection_idx - _scroll_line + if rel_selection < 0: + _scroll_line = selection_idx + if rel_selection > max_line_idx: + _scroll_line = selection_idx - max_line_idx + + if up_arrow: + up_arrow.visible = _scroll_line > 0 + if down_arrow: + down_arrow.visible = options.size() - _scroll_line > MAX_LINES + + ## This is a workaround for an issue with the clipping boundary func _hide_unselected() -> void: for i: int in title_list.get_child_count(): @@ -57,6 +91,7 @@ func rebuild_list() -> void: title_list.add_child(item_label) selection_idx = (selection_idx % options.size()) if options else 0 + _update_scrolling() func _new_tween() -> Tween: @@ -83,6 +118,7 @@ func expand() -> Tween: ) _active_tween = tween _show_all() + scroll_arrows.show() selection_mask.show() return tween @@ -103,7 +139,10 @@ func select_and_contract() -> Tween: func contract() -> Tween: var tween := _new_tween() - var container_position := -(selection_idx * LINE_HEIGHT_PX + LINE_HEIGHT_OFFSET) + var container_position := -( + (selection_idx - _scroll_line) * LINE_HEIGHT_PX + LINE_HEIGHT_OFFSET + ) + tween.tween_callback(scroll_arrows.hide) tween.set_parallel(true) ( tween @@ -128,3 +167,8 @@ func _process(delta: float) -> void: selection_mask.position.y = lerpf( selection_mask.position.y, target_position, 1 - exp(-SELECTION_SMOOTHING * delta) ) + + var target_scroll := -_scroll_line * LINE_HEIGHT_PX + scrolling_container.position.y = lerpf( + scrolling_container.position.y, target_scroll, 1 - exp(-SELECTION_SMOOTHING * delta) + ) diff --git a/src/equipment/mp3_player/retro_selector_list.tscn b/src/equipment/mp3_player/retro_selector_list.tscn index 0f48c2c..5129670 100644 --- a/src/equipment/mp3_player/retro_selector_list.tscn +++ b/src/equipment/mp3_player/retro_selector_list.tscn @@ -1,8 +1,70 @@ -[gd_scene load_steps=5 format=3 uid="uid://t11xpl4mtgvf"] +[gd_scene load_steps=9 format=3 uid="uid://t11xpl4mtgvf"] [ext_resource type="Script" uid="uid://qt6hnlakpqob" path="res://src/equipment/mp3_player/retro_selector_list.gd" id="1_kvinm"] [ext_resource type="Theme" uid="uid://drq4sbm3i6uxt" path="res://src/equipment/mp3_player/player_ui_theme.tres" id="2_4rnpc"] [ext_resource type="Shader" uid="uid://b6c7d34uvtssk" path="res://src/shaders/canvas_invert.gdshader" id="3_4rnpc"] +[ext_resource type="FontFile" uid="uid://bgy7odoob7xyl" path="res://assets/fonts/Silkscreen/Silkscreen-Bold.ttf" id="4_wabg6"] + +[sub_resource type="Animation" id="Animation_f6w0q"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("UpArrow:position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(58, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("DownArrow:position") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(58, 63)] +} + +[sub_resource type="Animation" id="Animation_wabg6"] +resource_name = "float" +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("UpArrow:position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.1, 0.4, 0.6, 0.9, 1), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1), +"update": 0, +"values": [Vector2(58, 1), Vector2(58, 0), Vector2(58, 0), Vector2(58, 2), Vector2(58, 2), Vector2(58, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("DownArrow:position") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.1, 0.3, 0.6, 0.8, 1), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1), +"update": 0, +"values": [Vector2(58, 64), Vector2(58, 64), Vector2(58, 66), Vector2(58, 66), Vector2(58, 64), Vector2(58, 64)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_1k8u3"] +_data = { +&"RESET": SubResource("Animation_f6w0q"), +&"float": SubResource("Animation_wabg6") +} [sub_resource type="ShaderMaterial" id="ShaderMaterial_4rnpc"] shader = ExtResource("3_4rnpc") @@ -16,16 +78,18 @@ clip_contents = true layout_mode = 3 anchors_preset = 0 offset_right = 70.0 -offset_bottom = 76.0 +offset_bottom = 79.0 theme = ExtResource("2_4rnpc") script = ExtResource("1_kvinm") +options = Array[String](["one", "two", "three", "four", "five", "six", "seven", "and me too!", "uwoah!"]) +selection_idx = 1 [node name="ScreenBoundsContainer" type="Control" parent="."] unique_name_in_owner = true -custom_minimum_size = Vector2(70, 76) +custom_minimum_size = Vector2(70, 79) anchors_preset = 0 offset_right = 70.0 -offset_bottom = 76.0 +offset_bottom = 79.0 [node name="Background" type="ColorRect" parent="ScreenBoundsContainer"] layout_mode = 1 @@ -36,7 +100,62 @@ grow_horizontal = 2 grow_vertical = 2 color = Color(0.619608, 0.678431, 0.705882, 1) -[node name="TitleList" type="VBoxContainer" parent="ScreenBoundsContainer"] +[node name="MarginContainer" type="MarginContainer" parent="ScreenBoundsContainer"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 2 +theme_override_constants/margin_top = 1 +theme_override_constants/margin_right = 2 +theme_override_constants/margin_bottom = 1 + +[node name="ScrollArrows" type="Control" parent="ScreenBoundsContainer/MarginContainer"] +unique_name_in_owner = true +layout_mode = 2 + +[node name="UpArrow" type="Label" parent="ScreenBoundsContainer/MarginContainer/ScrollArrows"] +unique_name_in_owner = true +visible = false +layout_mode = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -8.0 +offset_bottom = 11.0 +grow_horizontal = 0 +scale = Vector2(1, -1) +pivot_offset = Vector2(0, 5.5) +theme_override_fonts/font = ExtResource("4_wabg6") +text = "v" + +[node name="DownArrow" type="Label" parent="ScreenBoundsContainer/MarginContainer/ScrollArrows"] +unique_name_in_owner = true +visible = false +layout_mode = 1 +anchors_preset = 3 +anchor_left = 1.0 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = -8.0 +offset_top = -14.0 +offset_bottom = -3.0 +grow_horizontal = 0 +grow_vertical = 0 +pivot_offset = Vector2(0, 5.5) +theme_override_fonts/font = ExtResource("4_wabg6") +text = "v" + +[node name="AnimationPlayer" type="AnimationPlayer" parent="ScreenBoundsContainer/MarginContainer/ScrollArrows"] +libraries = { +&"": SubResource("AnimationLibrary_1k8u3") +} +autoplay = "float" + +[node name="ScrollingContainer" type="Control" parent="ScreenBoundsContainer"] unique_name_in_owner = true layout_mode = 1 anchors_preset = 15 @@ -44,13 +163,21 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 + +[node name="TitleList" type="VBoxContainer" parent="ScreenBoundsContainer/ScrollingContainer"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 88.0 +grow_horizontal = 2 theme_override_constants/separation = 0 -[node name="SelectionMask" type="ColorRect" parent="ScreenBoundsContainer"] +[node name="SelectionMask" type="ColorRect" parent="ScreenBoundsContainer/ScrollingContainer"] unique_name_in_owner = true material = SubResource("ShaderMaterial_4rnpc") custom_minimum_size = Vector2(70, 11) layout_mode = 0 -offset_top = 1.00001 +offset_top = 11.9999 offset_right = 70.0 -offset_bottom = 12.0 +offset_bottom = 22.9999 diff --git a/src/world/world.gd b/src/world/world.gd index 9f7ff6f..9a55303 100644 --- a/src/world/world.gd +++ b/src/world/world.gd @@ -31,7 +31,8 @@ var debug_unlock_next_milestone: bool: if value: var milestone := manager.next_milestone() manager.grunk_vault = manager.next_milestone_amount() - manager.milestone_reached.emit(milestone) + if milestone: + manager.milestone_reached.emit(milestone) var current_level_scene: PackedScene var current_level: Level