aboutsummaryrefslogtreecommitdiff
path: root/game/src
diff options
context:
space:
mode:
author ClarkeCode <33846391+ClarkeCode@users.noreply.github.com>2023-03-06 22:14:19 +0100
committer GitHub <noreply@github.com>2023-03-06 22:14:19 +0100
commitce325c16c0f5d82ed51abd8bd13928a7bc609ba5 (patch)
tree9684123684de590ecd3be99be034d68f4bc6f8b7 /game/src
parent95173891f7c5eea7717a58ae4f1438fd09e0ee1f (diff)
Add Music Player (#49)
* Adding MusicConductor * Added selectable songs and player visibility toggle * Refinements to the music system * SongInfo compatability with various audio formats * Moved UI reqs to editor description; flipped conditions to exclude music .import files * Made selection of the first music track extension-agnostic * Fixed visual bug with play/pause button when interacting with progress slider
Diffstat (limited to 'game/src')
-rw-r--r--game/src/GameMenu.tscn9
-rw-r--r--game/src/MusicConductor/MusicConductor.gd68
-rw-r--r--game/src/MusicConductor/MusicConductor.tscn13
-rw-r--r--game/src/MusicConductor/MusicUIController.gd66
-rw-r--r--game/src/MusicConductor/MusicUIController.tscn64
-rw-r--r--game/src/MusicConductor/SongInfo.gd11
6 files changed, 231 insertions, 0 deletions
diff --git a/game/src/GameMenu.tscn b/game/src/GameMenu.tscn
index 9442d1a..2c223ec 100644
--- a/game/src/GameMenu.tscn
+++ b/game/src/GameMenu.tscn
@@ -6,6 +6,7 @@
[ext_resource type="PackedScene" uid="uid://b7oncobnacxmt" path="res://src/LocaleButton.tscn" id="4_jno35"]
[ext_resource type="PackedScene" uid="uid://c8knthxkwj1uj" path="res://src/Credits/Credits.tscn" id="4_n0hoo"]
[ext_resource type="PackedScene" uid="uid://crhkgngfnxf4y" path="res://src/LobbyMenu/LobbyMenu.tscn" id="4_nofk1"]
+[ext_resource type="PackedScene" uid="uid://dmnqyvl3qfq2e" path="res://src/MusicConductor/MusicUIController.tscn" id="6_lts1m"]
[node name="GameMenu" type="Control"]
layout_mode = 3
@@ -20,6 +21,14 @@ script = ExtResource("1_cafwe")
layout_mode = 1
metadata/_edit_vertical_guides_ = [251.0, 269.0, 504.0, 523.0, 15.0, 759.0, 777.0]
+[node name="MusicUIController" parent="." instance=ExtResource("6_lts1m")]
+layout_mode = 1
+anchor_left = 0.843
+anchor_right = 0.953
+offset_left = -0.0400391
+offset_right = 0.159912
+metadata/_edit_use_anchors_ = true
+
[node name="OptionsMenu" parent="." instance=ExtResource("3_111lv")]
visible = false
layout_mode = 1
diff --git a/game/src/MusicConductor/MusicConductor.gd b/game/src/MusicConductor/MusicConductor.gd
new file mode 100644
index 0000000..a463d6d
--- /dev/null
+++ b/game/src/MusicConductor/MusicConductor.gd
@@ -0,0 +1,68 @@
+extends Node
+
+# SS-67
+@export_dir var musicDir : String
+@export_file var firstSongName : String
+
+var selectedTrack = 0
+var availableSongs : Array[SongInfo] = []
+var autoPlayNextSong : bool = true
+
+func getAllSongNames() -> Array[String]:
+ var songNames : Array[String] = []
+ for si in availableSongs:
+ songNames.append(si.readableName)
+ return songNames
+
+func getCurrentSongIndex() -> int:
+ return selectedTrack
+
+func getCurrentSongName() -> String:
+ return availableSongs[selectedTrack].readableName
+
+func scrubSongByPercentage(percentage: float) -> void:
+ var percentInSeconds : float = (percentage / 100.0) * $AudioStreamPlayer.stream.get_length()
+ $AudioStreamPlayer.play(percentInSeconds)
+
+func getCurrentSongProgressPercentage() -> float:
+ return 100 * ($AudioStreamPlayer.get_playback_position() / $AudioStreamPlayer.stream.get_length())
+
+func isPaused() -> bool:
+ return $AudioStreamPlayer.stream_paused
+
+func togglePlayPause() -> void:
+ $AudioStreamPlayer.stream_paused = !$AudioStreamPlayer.stream_paused
+
+func startCurrentSong() -> void:
+ $AudioStreamPlayer.stream = availableSongs[selectedTrack].loadedStream
+ $AudioStreamPlayer.play()
+
+# SS-70
+func startSongByIndex(id: int) -> void:
+ selectedTrack = id
+ startCurrentSong()
+
+# SS-69
+func nextSong() -> void:
+ selectedTrack = (selectedTrack + 1) % len(availableSongs)
+ startCurrentSong()
+
+func prevSong() -> void:
+ selectedTrack = (len(availableSongs) - 1) if (selectedTrack == 0) else (selectedTrack - 1)
+ startCurrentSong()
+
+# Called when the node enters the scene tree for the first time.
+func _ready():
+ var dir = DirAccess.open(musicDir)
+ for fname in dir.get_files():
+ if !fname.ends_with(".import"):
+ if fname.get_basename() == firstSongName:
+ selectedTrack = availableSongs.size()
+ availableSongs.append(SongInfo.new(musicDir, fname))
+ startCurrentSong()
+
+
+func _on_audio_stream_player_finished():
+ if autoPlayNextSong:
+ nextSong()
+ startCurrentSong()
diff --git a/game/src/MusicConductor/MusicConductor.tscn b/game/src/MusicConductor/MusicConductor.tscn
new file mode 100644
index 0000000..69529d8
--- /dev/null
+++ b/game/src/MusicConductor/MusicConductor.tscn
@@ -0,0 +1,13 @@
+[gd_scene load_steps=2 format=3 uid="uid://b1h31mnn8n2nu"]
+
+[ext_resource type="Script" path="res://src/MusicConductor/MusicConductor.gd" id="1_56t1b"]
+
+[node name="MusicConductor" type="Node"]
+script = ExtResource("1_56t1b")
+musicDir = "res://audio/music/"
+firstSongName = "The_Crown"
+
+[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
+bus = &"Music"
+
+[connection signal="finished" from="AudioStreamPlayer" to="." method="_on_audio_stream_player_finished"]
diff --git a/game/src/MusicConductor/MusicUIController.gd b/game/src/MusicConductor/MusicUIController.gd
new file mode 100644
index 0000000..f2c9225
--- /dev/null
+++ b/game/src/MusicConductor/MusicUIController.gd
@@ -0,0 +1,66 @@
+extends Control
+
+@export var songSelectorButton : OptionButton
+@export var progressSlider : HSlider
+@export var prevSongButton : Button
+@export var playPauseButton : Button
+@export var nextSongButton : Button
+@export var widgetVisibilityButton : Button
+
+var isMusicPlayerVisible : bool = true
+var isUserDraggingProgressSlider : bool = false
+
+# Called when the node enters the scene tree for the first time.
+func _ready():
+ for songName in MusicConductor.getAllSongNames():
+ songSelectorButton.add_item(songName, songSelectorButton.item_count)
+ updateSongNameVisual()
+
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(_delta):
+ if !isUserDraggingProgressSlider:
+ progressSlider.value = MusicConductor.getCurrentSongProgressPercentage()
+
+func updateSongNameVisual():
+ songSelectorButton.selected = MusicConductor.getCurrentSongIndex()
+
+func updatePlayPauseButtonVisual():
+ playPauseButton.text = "||" if MusicConductor.isPaused() else ">"
+
+func _on_play_pause_button_pressed():
+ MusicConductor.togglePlayPause()
+ updatePlayPauseButtonVisual()
+
+func _on_next_song_button_pressed():
+ MusicConductor.nextSong()
+ updateSongNameVisual()
+ updatePlayPauseButtonVisual()
+
+func _on_previous_song_button_pressed():
+ MusicConductor.prevSong()
+ updateSongNameVisual()
+ updatePlayPauseButtonVisual()
+
+func _on_option_button_item_selected(index):
+ # UIFUN-92
+ MusicConductor.startSongByIndex(index)
+
+
+func _on_progress_slider_drag_started():
+ isUserDraggingProgressSlider = true
+
+
+func _on_progress_slider_drag_ended(_value_changed):
+ MusicConductor.scrubSongByPercentage(progressSlider.value)
+ isUserDraggingProgressSlider = false
+ updatePlayPauseButtonVisual()
+
+func _on_music_ui_visibility_button_pressed():
+ isMusicPlayerVisible = !isMusicPlayerVisible
+ widgetVisibilityButton.text = "Hide Player" if isMusicPlayerVisible else "Show Player"
+ songSelectorButton.visible = isMusicPlayerVisible
+ progressSlider.visible = isMusicPlayerVisible
+ prevSongButton.visible = isMusicPlayerVisible
+ playPauseButton.visible = isMusicPlayerVisible
+ nextSongButton.visible = isMusicPlayerVisible
diff --git a/game/src/MusicConductor/MusicUIController.tscn b/game/src/MusicConductor/MusicUIController.tscn
new file mode 100644
index 0000000..49ea355
--- /dev/null
+++ b/game/src/MusicConductor/MusicUIController.tscn
@@ -0,0 +1,64 @@
+[gd_scene load_steps=2 format=3 uid="uid://dmnqyvl3qfq2e"]
+
+[ext_resource type="Script" path="res://src/MusicConductor/MusicUIController.gd" id="1_u4qbn"]
+
+[node name="MusicUIController" type="Control" node_paths=PackedStringArray("songSelectorButton", "progressSlider", "prevSongButton", "playPauseButton", "nextSongButton", "widgetVisibilityButton")]
+editor_description = "UI-104"
+layout_mode = 3
+anchor_right = 0.11
+anchor_bottom = 0.165
+offset_right = 0.199997
+offset_bottom = 0.199997
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_u4qbn")
+songSelectorButton = NodePath("VBoxContainer/SongSelectorButton")
+progressSlider = NodePath("VBoxContainer/ProgressSlider")
+prevSongButton = NodePath("VBoxContainer/HBoxContainer/PreviousSongButton")
+playPauseButton = NodePath("VBoxContainer/HBoxContainer/PlayPauseButton")
+nextSongButton = NodePath("VBoxContainer/HBoxContainer/NextSongButton")
+widgetVisibilityButton = NodePath("VBoxContainer/MusicUIVisibilityButton")
+
+[node name="VBoxContainer" type="VBoxContainer" parent="."]
+layout_mode = 0
+offset_right = 40.0
+offset_bottom = 40.0
+
+[node name="SongSelectorButton" type="OptionButton" parent="VBoxContainer"]
+editor_description = "UI-107"
+layout_mode = 2
+
+[node name="ProgressSlider" type="HSlider" parent="VBoxContainer"]
+layout_mode = 2
+
+[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 4
+
+[node name="PreviousSongButton" type="Button" parent="VBoxContainer/HBoxContainer"]
+layout_mode = 2
+text = "Prev"
+
+[node name="PlayPauseButton" type="Button" parent="VBoxContainer/HBoxContainer"]
+custom_minimum_size = Vector2(30, 0)
+layout_mode = 2
+text = ">"
+
+[node name="NextSongButton" type="Button" parent="VBoxContainer/HBoxContainer"]
+layout_mode = 2
+text = "Next"
+
+[node name="MusicUIVisibilityButton" type="Button" parent="VBoxContainer"]
+editor_description = "UI-106"
+layout_mode = 2
+size_flags_horizontal = 4
+size_flags_vertical = 3
+text = "Hide Player"
+
+[connection signal="item_selected" from="VBoxContainer/SongSelectorButton" to="." method="_on_option_button_item_selected"]
+[connection signal="drag_ended" from="VBoxContainer/ProgressSlider" to="." method="_on_progress_slider_drag_ended"]
+[connection signal="drag_started" from="VBoxContainer/ProgressSlider" to="." method="_on_progress_slider_drag_started"]
+[connection signal="pressed" from="VBoxContainer/HBoxContainer/PreviousSongButton" to="." method="_on_previous_song_button_pressed"]
+[connection signal="pressed" from="VBoxContainer/HBoxContainer/PlayPauseButton" to="." method="_on_play_pause_button_pressed"]
+[connection signal="pressed" from="VBoxContainer/HBoxContainer/NextSongButton" to="." method="_on_next_song_button_pressed"]
+[connection signal="pressed" from="VBoxContainer/MusicUIVisibilityButton" to="." method="_on_music_ui_visibility_button_pressed"]
diff --git a/game/src/MusicConductor/SongInfo.gd b/game/src/MusicConductor/SongInfo.gd
new file mode 100644
index 0000000..85ef96a
--- /dev/null
+++ b/game/src/MusicConductor/SongInfo.gd
@@ -0,0 +1,11 @@
+extends Node
+class_name SongInfo
+
+var fullyQualifiedPath : String = ""
+var readableName : String = ""
+var loadedStream : Resource
+
+func _init(dirname:String, fname:String):
+ fullyQualifiedPath = dirname + fname
+ readableName = fname.get_basename().replace("_", " ")
+ loadedStream = load(fullyQualifiedPath)