diff --git a/global/autoload/audio/audio.gd b/global/autoload/audio/audio.gd index 170d75e..f8e8ebc 100644 --- a/global/autoload/audio/audio.gd +++ b/global/autoload/audio/audio.gd @@ -4,49 +4,55 @@ extends Node set(value): default_sfx_pitch_variance = clampf(value, 0.0, 1.0) +var _track: int = 0 +var _current_audio_player: AudioPlayer + @onready var sfx_queue: AudioQueue = %SfxQueue @onready var sfx_map: Node = %SfxMap -@onready var music_track_2_heart: MusicTrack = %MusicTrack2Heart +@onready var music_tracks: Node = %Music + +@onready var heartbeat_ambience: AudioPlayer = %Heartbeat ############### ## overrides ## ############### -# func _ready() -> void: -# _initalize() -# _connect_signals() + +func _ready() -> void: + _initalize() + _connect_signals() + for audio_player: AudioPlayer in music_tracks.get_children(): + audio_player.finished.connect(_on_music_track_finished) + ############# ## helpers ## ############# -# func _initalize() -> void: -# music_tracks.get_child(_track).fade_in() + +func _initalize() -> void: + _current_audio_player = music_tracks.get_child(_track) + _current_audio_player.fade_in() + ############# ## methods ## ############# -# func swap_crossfade_music_next() -> void: -# var track: int = (_track + 1) % music_tracks.get_child_count() -# swap_crossfade_music_new(track, null) -# func swap_crossfade_music(track: int) -> void: -# swap_crossfade_music_new(track, null) +func swap_crossfade_music_next() -> void: + _track = (_track + 1) % music_tracks.get_child_count() + swap_crossfade_audio(music_tracks.get_child(_track)) -# func swap_crossfade_music_new(track: int, song_stream: AudioStream) -> void: -# if _track == track: -# return -# var music_track_next: MusicTrack = music_tracks.get_child(track) -# var music_track_previous: MusicTrack = music_tracks.get_child(_track) -# _track = track +func swap_crossfade_audio(audio_player: AudioPlayer) -> void: + if _current_audio_player == audio_player: + return -# music_track_previous.fade_out() -# music_track_next.fade_in() -# if song_stream != null: -# music_track_next.swap(song_stream) + _current_audio_player.fade_out() + _current_audio_player = audio_player + _current_audio_player.fade_in() func play_sfx( @@ -84,27 +90,30 @@ func _connect_signals() -> void: func _on_tab_changed(tab_data: TabData) -> void: - if tab_data.id == DarknessScreen.TAB_DATA_ID: - Audio.swap_crossfade_music(1) - elif tab_data.id == StarwayScreen.TAB_DATA_ID: - Audio.swap_crossfade_music(2) + if tab_data.id == StarwayScreen.TAB_DATA_ID: + swap_crossfade_audio(heartbeat_ambience) elif tab_data.id == "unknown": - Audio.swap_crossfade_music(3) + _current_audio_player.fade_out() else: - Audio.swap_crossfade_music(0) + var music_player: AudioPlayer = music_tracks.get_child(_track) + swap_crossfade_audio(music_player) + + +func _on_music_track_finished() -> void: + swap_crossfade_music_next() func _on_heart_click() -> void: - music_track_2_heart.audio_stream_player.pitch_scale = 2.0 + heartbeat_ambience.idle_track.pitch_scale = 2.0 func _on_heart_unclick() -> void: - music_track_2_heart.audio_stream_player.pitch_scale = 1.0 + heartbeat_ambience.idle_track.pitch_scale = 1.0 func _on_prestige_condition_pass(_infinity_count: int) -> void: - Audio.swap_crossfade_music(3) + _current_audio_player.fade_out() func _on_soul() -> void: - Audio.swap_crossfade_music(3) + _current_audio_player.fade_out() diff --git a/global/autoload/audio/audio.tscn b/global/autoload/audio/audio.tscn index dd71b92..03cd268 100644 --- a/global/autoload/audio/audio.tscn +++ b/global/autoload/audio/audio.tscn @@ -1,18 +1,35 @@ -[gd_scene load_steps=5 format=3 uid="uid://bp61l7vkkscuw"] +[gd_scene load_steps=8 format=3 uid="uid://bp61l7vkkscuw"] [ext_resource type="Script" path="res://global/autoload/audio/audio.gd" id="1_7i6rq"] [ext_resource type="PackedScene" uid="uid://f1stqtkpi6rl" path="res://global/autoload/audio/audio_queue/audio_queue.tscn" id="2_bb4fe"] -[ext_resource type="PackedScene" uid="uid://cragwwd3j3bqt" path="res://global/autoload/audio/music/music.tscn" id="2_dmcs5"] [ext_resource type="PackedScene" uid="uid://bu2l4l0jhesyw" path="res://global/autoload/audio/sfx_map/sfx_map.tscn" id="3_4nox4"] +[ext_resource type="PackedScene" uid="uid://cragwwd3j3bqt" path="res://global/autoload/audio/audio_player/audio_player.tscn" id="4_gols3"] +[ext_resource type="Resource" uid="uid://cuwcu7njbtvqn" path="res://resources/songs/forest_song.tres" id="5_ftjyd"] +[ext_resource type="Resource" uid="uid://d1yl7vrmvavit" path="res://resources/songs/axes_to_a_bed.tres" id="5_gma2y"] +[ext_resource type="AudioStream" uid="uid://cjg7wv1kxy1ye" path="res://assets/audio/freesound_org/heartbeat_80bpm/loudernoises_heartbeat_80bpm.wav" id="5_s525l"] [node name="Audio" type="Node"] script = ExtResource("1_7i6rq") -[node name="Music" parent="." instance=ExtResource("2_dmcs5")] - [node name="SfxQueue" parent="." instance=ExtResource("2_bb4fe")] unique_name_in_owner = true stream_player_count = 16 [node name="SfxMap" parent="SfxQueue" instance=ExtResource("3_4nox4")] unique_name_in_owner = true + +[node name="Music" type="Node" parent="."] +unique_name_in_owner = true + +[node name="ForestSong" parent="Music" instance=ExtResource("4_gols3")] +default_audio = ExtResource("5_ftjyd") + +[node name="20AxesToABed" parent="Music" instance=ExtResource("4_gols3")] +default_audio = ExtResource("5_gma2y") + +[node name="Ambience" type="Node" parent="."] + +[node name="Heartbeat" parent="Ambience" instance=ExtResource("4_gols3")] +unique_name_in_owner = true +default_audio = ExtResource("5_s525l") +is_looping = true diff --git a/global/autoload/audio/audio_player/audio_player.gd b/global/autoload/audio/audio_player/audio_player.gd new file mode 100644 index 0000000..0d65bc0 --- /dev/null +++ b/global/autoload/audio/audio_player/audio_player.gd @@ -0,0 +1,132 @@ +class_name AudioPlayer extends Node + +signal finished +signal master_volume_changed(volume: float) + +const TWEEN_FADE_AUDIO_DURATION: float = 2.0 + +@export_enum(&"Master", &"Music", &"SFX") var default_bus: String = &"Music" +@export var default_audio: Resource # AudioStream | Song, can't union type in gdscript :( +@export var autoplay: bool = false +@export var max_volume: float = 1.0 +@export var is_looping: bool = false + +var master_volume: float = max_volume +var _current_audio: Resource +var _fade_tween: Tween +var _idle_playback_position: float = 0.0 +var _combat_playback_position: float = 0.0 + +@onready var states: StateMachine = %States +@onready var tracks: Node = %Tracks +@onready var idle_track: AudioStreamPlayer = %Idle +@onready var combat_track: AudioStreamPlayer = %Combat + +############### +## overrides ## +############### + + +func _ready() -> void: + assert(default_audio is AudioStream || default_audio is Song) + + set_bus(default_bus) + set_audio(default_audio) + _connect_signals() + + +############# +## methods ## +############# + + +func set_bus(bus: StringName) -> void: + idle_track.bus = bus + combat_track.bus = bus + + +func set_audio(audio: Resource) -> void: + _current_audio = audio + if audio is AudioStream: + idle_track.stream = audio + if audio is Song: + idle_track.stream = audio.idle_audio_stream + combat_track.stream = audio.combat_audio_stream + + +func is_playing() -> bool: + return idle_track.playing || combat_track.playing + + +func play(restart: bool = true) -> void: + if restart: + _idle_playback_position = 0.0 + _combat_playback_position = 0.0 + idle_track.play(_idle_playback_position) + combat_track.play(_combat_playback_position) + + +func stop() -> void: + idle_track.stop() + combat_track.stop() + + +func set_master_volume(volume_db: float) -> void: + master_volume = volume_db + master_volume_changed.emit(master_volume) + + +func transition_master_volume(from_volume: float, to_volume: float) -> void: + if _fade_tween != null: + _fade_tween.kill() + _fade_tween = create_tween() + + _fade_tween.tween_method(set_master_volume, from_volume, to_volume, TWEEN_FADE_AUDIO_DURATION) + + +func _fade_out_callback(pause: bool) -> void: + if pause: + _idle_playback_position = idle_track.get_playback_position() + _combat_playback_position = combat_track.get_playback_position() + stop() + + +func fade_out(pause: bool = true) -> void: + var from_volume: float = max_volume + var to_volume: float = 0.0 + transition_master_volume(from_volume, to_volume) + _fade_tween.tween_callback(_fade_out_callback.bind(pause)) + + +func fade_in(restart: bool = false) -> void: + var from_volume: float = 0.0 + var to_volume: float = max_volume + transition_master_volume(from_volume, to_volume) + play(restart) + + +############### +## signals ## +############### + + +func _connect_signals() -> void: + SignalBus.tab_changed.connect(_on_tab_changed) + idle_track.finished.connect(_on_track_finished) + combat_track.finished.connect(_on_track_finished) + + +func _on_track_finished() -> void: + if is_looping: + play(0.0) + else: + stop() + finished.emit() + + +func _on_tab_changed(tab_data: TabData) -> void: + if _current_audio is Song: + if tab_data.id == DarknessScreen.TAB_DATA_ID: + states.transition_to("Combat") + elif states.current.name == "Combat" && !tab_data.id == StarwayScreen.TAB_DATA_ID: + states.transition_to("Idle") diff --git a/global/autoload/audio/audio_player/audio_player.tscn b/global/autoload/audio/audio_player/audio_player.tscn new file mode 100644 index 0000000..a289f79 --- /dev/null +++ b/global/autoload/audio/audio_player/audio_player.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=4 format=3 uid="uid://cragwwd3j3bqt"] + +[ext_resource type="Script" path="res://global/autoload/audio/audio_player/audio_player.gd" id="1_3cuwr"] +[ext_resource type="Script" path="res://scenes/component/state_machine/state_machine.gd" id="2_pwrmv"] +[ext_resource type="Script" path="res://global/autoload/audio/audio_player/track_state.gd" id="3_tvnd0"] + +[node name="AudioPlayer" type="Node"] +script = ExtResource("1_3cuwr") + +[node name="Tracks" type="Node" parent="."] +unique_name_in_owner = true + +[node name="Idle" type="AudioStreamPlayer" parent="Tracks"] +unique_name_in_owner = true +bus = &"Music" + +[node name="Combat" type="AudioStreamPlayer" parent="Tracks"] +unique_name_in_owner = true +bus = &"Music" + +[node name="States" type="Node" parent="." node_paths=PackedStringArray("default_state")] +unique_name_in_owner = true +script = ExtResource("2_pwrmv") +default_state = NodePath("Idle") + +[node name="Idle" type="Node" parent="States"] +script = ExtResource("3_tvnd0") + +[node name="Combat" type="Node" parent="States"] +script = ExtResource("3_tvnd0") diff --git a/global/autoload/audio/audio_player/track_state.gd b/global/autoload/audio/audio_player/track_state.gd new file mode 100644 index 0000000..756fd90 --- /dev/null +++ b/global/autoload/audio/audio_player/track_state.gd @@ -0,0 +1,63 @@ +extends StateMachineState + +@onready var audio_player: AudioPlayer = owner + +const TWEEN_TRANSITION_TIME: float = 1.0 + +var track: AudioStreamPlayer +var _transition_tween: Tween +var _is_active: bool = false + +############### +## overrides ## +############### + + +func _on_ready() -> void: + await audio_player.ready + track = audio_player.tracks.get_node(NodePath(self.name)) + track.volume_db = linear_to_db(0.0) + audio_player.master_volume_changed.connect(_on_master_volume_changed) + + +func _on_state_enter() -> void: + print("entered state: %s" % self.name) + _is_active = true + var from_volume: float = 0.0 + var to_volume: float = audio_player.master_volume + transition_volume(from_volume, to_volume) + + +func _on_state_exit() -> void: + print("exited state: %s" % self.name) + _is_active = false + var from_volume: float = audio_player.master_volume + var to_volume: float = 0.0 + transition_volume(from_volume, to_volume) + + +############# +## methods ## +############# + + +func set_volume(volume: float) -> void: + track.volume_db = linear_to_db(volume) + + +func transition_volume(from_volume: float, to_volume: float) -> void: + if _transition_tween != null: + _transition_tween.kill() + _transition_tween = create_tween() + + _transition_tween.tween_method(set_volume, from_volume, to_volume, TWEEN_TRANSITION_TIME) + + +############### +## signals ## +############### + + +func _on_master_volume_changed(volume: float) -> void: + if linear_to_db(volume) < track.volume_db || _is_active: + set_volume(volume) diff --git a/global/autoload/audio/music/music.gd b/global/autoload/audio/music/music.gd deleted file mode 100644 index 1c32a8f..0000000 --- a/global/autoload/audio/music/music.gd +++ /dev/null @@ -1,44 +0,0 @@ -extends Node - -@export var songs: Array[Song] = [] - -@onready var tracks: Node = %Tracks -@onready var states: StateMachine = %States - -@onready var idle_track: AudioStreamPlayer = %Idle -@onready var combat_track: AudioStreamPlayer = %Combat - -var next_song_index: int = 0 - - -func _ready() -> void: - play_next_song() - SignalBus.tab_changed.connect(_on_tab_changed) - idle_track.finished.connect(_on_song_finished) - combat_track.finished.connect(_on_song_finished) - - -func play_next_song() -> void: - play_song(songs[next_song_index]) - next_song_index += 1 - if next_song_index >= len(songs): - next_song_index = 0 - - -func play_song(song: Song) -> void: - print("playing song %s" % str(song.idle_audio_stream)) - idle_track.stream = song.idle_audio_stream - combat_track.stream = song.combat_audio_stream - idle_track.play() - combat_track.play() - - -func _on_tab_changed(tab_data: TabData) -> void: - if tab_data.id == "enemy": - states.transition_to("Combat") - elif states.current_state.name == "Combat": - states.transition_to("Idle") - - -func _on_song_finished() -> void: - play_next_song() diff --git a/global/autoload/audio/music/music.tscn b/global/autoload/audio/music/music.tscn deleted file mode 100644 index c087071..0000000 --- a/global/autoload/audio/music/music.tscn +++ /dev/null @@ -1,33 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://cragwwd3j3bqt"] - -[ext_resource type="Script" path="res://global/autoload/audio/music/music.gd" id="1_c5si3"] -[ext_resource type="Script" path="res://scenes/component/state_machine/state_machine.gd" id="1_mdmqr"] -[ext_resource type="Script" path="res://resources/songs/song.gd" id="2_4kuok"] -[ext_resource type="Script" path="res://global/autoload/audio/music/track_state.gd" id="2_h773k"] -[ext_resource type="Resource" uid="uid://d1yl7vrmvavit" path="res://resources/songs/axes_to_a_bed.tres" id="3_fjjm6"] - -[node name="Music" type="Node"] -script = ExtResource("1_c5si3") -songs = Array[ExtResource("2_4kuok")]([ExtResource("3_fjjm6")]) - -[node name="Tracks" type="Node" parent="."] -unique_name_in_owner = true - -[node name="Idle" type="AudioStreamPlayer" parent="Tracks"] -unique_name_in_owner = true -bus = &"Music" - -[node name="Combat" type="AudioStreamPlayer" parent="Tracks"] -unique_name_in_owner = true -bus = &"Music" - -[node name="States" type="Node" parent="." node_paths=PackedStringArray("default_state")] -unique_name_in_owner = true -script = ExtResource("1_mdmqr") -default_state = NodePath("Idle") - -[node name="Idle" type="Node" parent="States"] -script = ExtResource("2_h773k") - -[node name="Combat" type="Node" parent="States"] -script = ExtResource("2_h773k") diff --git a/global/autoload/audio/music/track_state.gd b/global/autoload/audio/music/track_state.gd deleted file mode 100644 index c421d8d..0000000 --- a/global/autoload/audio/music/track_state.gd +++ /dev/null @@ -1,19 +0,0 @@ -extends StateMachineState - -@onready var music: Node = owner - -var track: AudioStreamPlayer - - -func _on_ready() -> void: - await music.ready - track = music.tracks.get_node(NodePath(self.name)) - - -func _on_state_enter() -> void: - print("ENTERING %s" % self.name) - track.volume_db = linear_to_db(1.0) - - -func _on_state_exit() -> void: - track.volume_db = linear_to_db(0.0) diff --git a/global/autoload/audio/music_track/music_track.gd b/global/autoload/audio/music_track/music_track.gd deleted file mode 100644 index 7e72de8..0000000 --- a/global/autoload/audio/music_track/music_track.gd +++ /dev/null @@ -1,93 +0,0 @@ -class_name MusicTrack extends Node - -const TWEEN_FADE_AUDIO_DURATION: float = 2.0 - -@export_enum(&"Master", &"Music", &"SFX") var bus: String = &"Music" -@export var audio_stream: AudioStream -@export var autoplay: bool = false -@export var max_volume: float = 1.0 - -var _playback_position: float = 0.0 -var _audio_stream_player_tween: Tween - -@onready var audio_stream_player: AudioStreamPlayer = %AudioStreamPlayer - -############### -## overrides ## -############### - - -func _ready() -> void: - audio_stream_player.bus = bus - audio_stream_player.stream = audio_stream - if autoplay: - audio_stream_player.play() - _connect_signals() - - -############# -## methods ## -############# - - -func swap(song_stream: AudioStream) -> void: - audio_stream_player.stream = song_stream - audio_stream_player.play() - - -func fade_out(pause: bool = true) -> void: - audio_stream_player.volume_db = linear_to_db(max_volume) - - if _audio_stream_player_tween != null: - _audio_stream_player_tween.kill() - _audio_stream_player_tween = create_tween() - - _audio_stream_player_tween.tween_method( - _tween_fade_audio.bind(audio_stream_player), max_volume, 0.0, TWEEN_FADE_AUDIO_DURATION - ) - _audio_stream_player_tween.tween_callback(_fade_out_callback.bind(pause)) - - -func fade_in(restart: bool = false) -> void: - audio_stream_player.volume_db = linear_to_db(0.0) - if restart: - _playback_position = 0.0 - audio_stream_player.stop() - - if _audio_stream_player_tween != null: - _audio_stream_player_tween.kill() - _audio_stream_player_tween = create_tween() - - _audio_stream_player_tween.tween_method( - _tween_fade_audio.bind(audio_stream_player), 0.0, max_volume, TWEEN_FADE_AUDIO_DURATION - ) - - -############ -## tweens ## -############ - - -func _tween_fade_audio(volume: float, song: AudioStreamPlayer) -> void: - song.volume_db = linear_to_db(volume) - if !audio_stream_player.playing: - audio_stream_player.play(_playback_position) - - -func _fade_out_callback(pause: bool) -> void: - if pause: - _playback_position = audio_stream_player.get_playback_position() - audio_stream_player.stop() - - -############# -## signals ## -############# - - -func _connect_signals() -> void: - audio_stream_player.finished.connect(_on_song_finished) - - -func _on_song_finished() -> void: - audio_stream_player.play() diff --git a/global/autoload/audio/music_track/music_track.tscn b/global/autoload/audio/music_track/music_track.tscn deleted file mode 100644 index 9a0d66f..0000000 --- a/global/autoload/audio/music_track/music_track.tscn +++ /dev/null @@ -1,10 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://bg37hs706yk1o"] - -[ext_resource type="Script" path="res://global/autoload/audio/music_track/music_track.gd" id="1_gwb5e"] - -[node name="MusicTrack" type="Node"] -script = ExtResource("1_gwb5e") - -[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] -unique_name_in_owner = true -bus = &"Music" diff --git a/resources/songs/axes_to_a_bed.tres b/resources/songs/axes_to_a_bed.tres index d953d01..ab664cb 100644 --- a/resources/songs/axes_to_a_bed.tres +++ b/resources/songs/axes_to_a_bed.tres @@ -1,10 +1,10 @@ [gd_resource type="Resource" script_class="Song" load_steps=4 format=3 uid="uid://d1yl7vrmvavit"] [ext_resource type="Script" path="res://resources/songs/song.gd" id="1_4i0cq"] -[ext_resource type="AudioStream" uid="uid://esxco7hisjn4" path="res://assets/audio/20 Axes Arr MSTR.mp3" id="1_31y33"] -[ext_resource type="AudioStream" uid="uid://cvo3kjga80knk" path="res://assets/audio/joseph_philip_burke/axes_to_a_bed_compressed.mp3" id="2_q13b1"] +[ext_resource type="AudioStream" uid="uid://boao20b74vwfi" path="res://assets/audio/20 Axes Arr MSTR LOOP.mp3" id="1_s067o"] +[ext_resource type="AudioStream" uid="uid://cvo3kjga80knk" path="res://assets/audio/joseph_philip_burke/axes_to_a_bed_compressed.mp3" id="2_tpojr"] [resource] script = ExtResource("1_4i0cq") -idle_audio_stream = ExtResource("2_q13b1") -combat_audio_stream = ExtResource("1_31y33") +idle_audio_stream = ExtResource("2_tpojr") +combat_audio_stream = ExtResource("1_s067o") diff --git a/resources/songs/forest_song.tres b/resources/songs/forest_song.tres new file mode 100644 index 0000000..33bda78 --- /dev/null +++ b/resources/songs/forest_song.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="Song" load_steps=4 format=3 uid="uid://cuwcu7njbtvqn"] + +[ext_resource type="AudioStream" uid="uid://tksoficve1me" path="res://assets/audio/Forest Arr MSTR LOOP.mp3" id="1_ngt8i"] +[ext_resource type="Script" path="res://resources/songs/song.gd" id="1_rw51e"] +[ext_resource type="AudioStream" uid="uid://b5ad2ujlpx4s8" path="res://assets/audio/joseph_philip_burke/forest_song_compressed.mp3" id="2_6gcgk"] + +[resource] +script = ExtResource("1_rw51e") +idle_audio_stream = ExtResource("2_6gcgk") +combat_audio_stream = ExtResource("1_ngt8i") diff --git a/scenes/component/state_machine/state_machine.gd b/scenes/component/state_machine/state_machine.gd index 4574e45..34914ff 100644 --- a/scenes/component/state_machine/state_machine.gd +++ b/scenes/component/state_machine/state_machine.gd @@ -3,7 +3,11 @@ class_name StateMachine extends Node @export var default_state: StateMachineState var states: Dictionary -var current_state: StateMachineState +var current: StateMachineState + +############### +## overrides ## +############### func _ready() -> void: @@ -16,19 +20,24 @@ func _ready() -> void: func _input(event: InputEvent) -> void: - current_state._on_input(event) + current._on_input(event) func _process(delta: float) -> void: - current_state._on_process(delta) + current._on_process(delta) func _physics_process(delta: float) -> void: - current_state._on_physics_process(delta) + current._on_physics_process(delta) + + +############# +## methods ## +############# func transition_to(state_name: StringName) -> void: - if current_state: - current_state._on_state_exit() - current_state = states[state_name] - current_state._on_state_enter() + if current: + current._on_state_exit() + current = states[state_name] + current._on_state_enter()