MP3 UI scrolling

This commit is contained in:
Rob Kelly 2025-06-27 17:46:08 -06:00
parent 22163f6f32
commit f840738288
6 changed files with 190 additions and 19 deletions

View File

@ -228,8 +228,6 @@ text = ""
[node name="RetroSelectorList" parent="." instance=ExtResource("3_n8ehr")] [node name="RetroSelectorList" parent="." instance=ExtResource("3_n8ehr")]
unique_name_in_owner = true unique_name_in_owner = true
offset_bottom = 11.0
options = Array[String](["aaa", "bbb", "ccc", "defghijk"])
[node name="TransitionPlayer" type="AnimationPlayer" parent="."] [node name="TransitionPlayer" type="AnimationPlayer" parent="."]
unique_name_in_owner = true unique_name_in_owner = true

View File

@ -1,7 +1,8 @@
extends Tool extends Tool
## Pump up the jamz! ## Pump up the jamz!
const RUMBLE_INTENSITY = 0.006 const BIG_RUMBLE = 0.006
const SMALL_RUMBLE = 0.0009
const RUMBLE_DROPOFF = 0.8 const RUMBLE_DROPOFF = 0.8
@onready var mp3_controller: MP3Controller = %MP3Controller @onready var mp3_controller: MP3Controller = %MP3Controller
@ -20,12 +21,12 @@ func unlocked() -> bool:
func fire() -> void: func fire() -> void:
if not firing: if not firing:
firing = true firing = true
rumbler.intensity = RUMBLE_INTENSITY rumbler.intensity = BIG_RUMBLE
mp3_controller.select() mp3_controller.select()
func switch_mode() -> void: func switch_mode() -> void:
rumbler.intensity = RUMBLE_INTENSITY rumbler.intensity = SMALL_RUMBLE
mp3_controller.cancel() mp3_controller.cancel()

View File

@ -74,7 +74,7 @@ render_target_update_mode = 4
[node name="ScreenTransform" type="Marker2D" parent="HUDTool/Rumbler/Position/HUDElement/DeviceScreenMask/SubViewportContainer/SubViewport"] [node name="ScreenTransform" type="Marker2D" parent="HUDTool/Rumbler/Position/HUDElement/DeviceScreenMask/SubViewportContainer/SubViewport"]
texture_filter = 1 texture_filter = 1
position = Vector2(17.939, -1) position = Vector2(17.939, -2)
rotation = 0.139626 rotation = 0.139626
skew = 0.0331613 skew = 0.0331613

View File

@ -1,16 +1,17 @@
@tool
class_name RetroSelectorList extends Control class_name RetroSelectorList extends Control
const DEFAULT_HEIGHT := 76.0 const DEFAULT_HEIGHT := 79.0
const LINE_HEIGHT_PX := 11 const LINE_HEIGHT_PX := 11
const LINE_HEIGHT_OFFSET := 1 const LINE_HEIGHT_OFFSET := 1
const SELECTION_SMOOTHING := 8.0 const SELECTION_SMOOTHING := 8.0
const MAX_LINES := 7
const BLINK_INTERVAL := 0.2 const BLINK_INTERVAL := 0.2
@export var options: Array[String] = [] @export var options: Array[String] = []
@export var selection_idx := 0: @export var selection_idx := 0:
set(value): set = _set_selection_idx
selection_idx = wrapi(value, 0, options.size())
@export var expanded := true: @export var expanded := true:
set(value): set(value):
if value != expanded: if value != expanded:
@ -22,16 +23,49 @@ const BLINK_INTERVAL := 0.2
@export var tween_scale := 0.24 @export var tween_scale := 0.24
@export var debug_rebuild := false:
set(value):
if value:
rebuild_list()
var _active_tween: Tween var _active_tween: Tween
var _scroll_line := 0
@onready var screen_bounds_container: Control = %ScreenBoundsContainer @onready var screen_bounds_container: Control = %ScreenBoundsContainer
@onready var scrolling_container: Control = %ScrollingContainer
@onready var title_list: VBoxContainer = %TitleList @onready var title_list: VBoxContainer = %TitleList
@onready var selection_mask: ColorRect = %SelectionMask @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: func _ready() -> void:
rebuild_list() 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 ## This is a workaround for an issue with the clipping boundary
func _hide_unselected() -> void: func _hide_unselected() -> void:
for i: int in title_list.get_child_count(): for i: int in title_list.get_child_count():
@ -57,6 +91,7 @@ func rebuild_list() -> void:
title_list.add_child(item_label) title_list.add_child(item_label)
selection_idx = (selection_idx % options.size()) if options else 0 selection_idx = (selection_idx % options.size()) if options else 0
_update_scrolling()
func _new_tween() -> Tween: func _new_tween() -> Tween:
@ -83,6 +118,7 @@ func expand() -> Tween:
) )
_active_tween = tween _active_tween = tween
_show_all() _show_all()
scroll_arrows.show()
selection_mask.show() selection_mask.show()
return tween return tween
@ -103,7 +139,10 @@ func select_and_contract() -> Tween:
func contract() -> Tween: func contract() -> Tween:
var tween := _new_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.set_parallel(true)
( (
tween tween
@ -128,3 +167,8 @@ func _process(delta: float) -> void:
selection_mask.position.y = lerpf( selection_mask.position.y = lerpf(
selection_mask.position.y, target_position, 1 - exp(-SELECTION_SMOOTHING * delta) 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)
)

View File

@ -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="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="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="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"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_4rnpc"]
shader = ExtResource("3_4rnpc") shader = ExtResource("3_4rnpc")
@ -16,16 +78,18 @@ clip_contents = true
layout_mode = 3 layout_mode = 3
anchors_preset = 0 anchors_preset = 0
offset_right = 70.0 offset_right = 70.0
offset_bottom = 76.0 offset_bottom = 79.0
theme = ExtResource("2_4rnpc") theme = ExtResource("2_4rnpc")
script = ExtResource("1_kvinm") 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="."] [node name="ScreenBoundsContainer" type="Control" parent="."]
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(70, 76) custom_minimum_size = Vector2(70, 79)
anchors_preset = 0 anchors_preset = 0
offset_right = 70.0 offset_right = 70.0
offset_bottom = 76.0 offset_bottom = 79.0
[node name="Background" type="ColorRect" parent="ScreenBoundsContainer"] [node name="Background" type="ColorRect" parent="ScreenBoundsContainer"]
layout_mode = 1 layout_mode = 1
@ -36,7 +100,62 @@ grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
color = Color(0.619608, 0.678431, 0.705882, 1) 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 unique_name_in_owner = true
layout_mode = 1 layout_mode = 1
anchors_preset = 15 anchors_preset = 15
@ -44,13 +163,21 @@ anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 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 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 unique_name_in_owner = true
material = SubResource("ShaderMaterial_4rnpc") material = SubResource("ShaderMaterial_4rnpc")
custom_minimum_size = Vector2(70, 11) custom_minimum_size = Vector2(70, 11)
layout_mode = 0 layout_mode = 0
offset_top = 1.00001 offset_top = 11.9999
offset_right = 70.0 offset_right = 70.0
offset_bottom = 12.0 offset_bottom = 22.9999

View File

@ -31,6 +31,7 @@ var debug_unlock_next_milestone: bool:
if value: if value:
var milestone := manager.next_milestone() var milestone := manager.next_milestone()
manager.grunk_vault = manager.next_milestone_amount() manager.grunk_vault = manager.next_milestone_amount()
if milestone:
manager.milestone_reached.emit(milestone) manager.milestone_reached.emit(milestone)
var current_level_scene: PackedScene var current_level_scene: PackedScene