From abebc75a8a9564f3c8b059d37b15e91dbe52ee14 Mon Sep 17 00:00:00 2001 From: Caleb Date: Thu, 28 Dec 2023 15:29:40 -0800 Subject: [PATCH] Add music player --- project.godot | 1 + src/common/music/music_player.gd | 46 +++++++++++++ src/common/music/music_player.tscn | 65 +++++++++++++++++++ .../area_transitions/area_transition.gd | 28 ++++++-- .../area_transitions/area_transition.tscn | 5 ++ src/field/field.gd | 3 +- src/field/gamepieces/gamepiece.gd | 19 +++--- .../screen_transitions/screen_transition.gd | 2 + 8 files changed, 152 insertions(+), 17 deletions(-) create mode 100644 src/common/music/music_player.gd create mode 100644 src/common/music/music_player.tscn diff --git a/project.godot b/project.godot index f5b56aa..c2eb985 100644 --- a/project.godot +++ b/project.godot @@ -20,6 +20,7 @@ config/icon="res://icon.svg" Camera="*res://src/field/field_camera.gd" Dialogic="*res://addons/dialogic/Other/DialogicGameHandler.gd" FieldEvents="*res://src/common/globals/global_field_events.gd" +Music="*res://src/common/music/music_player.tscn" [dialogic] diff --git a/src/common/music/music_player.gd b/src/common/music/music_player.gd new file mode 100644 index 0000000..b274ef9 --- /dev/null +++ b/src/common/music/music_player.gd @@ -0,0 +1,46 @@ +class_name MusicPlayer extends Node + +@onready var _anim: = $AnimationPlayer as AnimationPlayer +@onready var _track: = $AudioStreamPlayer as AudioStreamPlayer + + +func play(new_stream: AudioStream, time_in: = 0.0, time_out: = 0.0) -> void: + if new_stream == _track.stream: + return + + if is_playing(): + if is_equal_approx(time_out, 0.0): + time_out = 0.005 + + _anim.speed_scale = 1.0/time_out + _anim.play("fade_out") + await _anim.animation_finished + + _track.stop() + + _track.stream = new_stream + if is_equal_approx(time_in, 0.0): + time_in = 0.005 + + _track.volume_db = -50.0 + _track.play() + _anim.speed_scale = 1.0/time_in + _anim.play("fade_in") + await _anim.animation_finished + + _anim.speed_scale = 1.0 + + +func stop(time_out: = 0.0) -> void: + if is_equal_approx(time_out, 0.0): + time_out = 0.005 + + _anim.speed_scale = 1.0/time_out + _anim.play("fade_out") + await _anim.animation_finished + + _track.stop() + + +func is_playing() -> bool: + return _track.playing diff --git a/src/common/music/music_player.tscn b/src/common/music/music_player.tscn new file mode 100644 index 0000000..ed12591 --- /dev/null +++ b/src/common/music/music_player.tscn @@ -0,0 +1,65 @@ +[gd_scene load_steps=6 format=3 uid="uid://cvgehp0c71fkg"] + +[ext_resource type="Script" path="res://src/common/music/music_player.gd" id="1_m166w"] + +[sub_resource type="Animation" id="Animation_e1vdt"] +resource_name = "fade_out" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("AudioStreamPlayer:volume_db") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.0, -50.0] +} + +[sub_resource type="Animation" id="Animation_meedk"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("AudioStreamPlayer:volume_db") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} + +[sub_resource type="Animation" id="Animation_ln66x"] +resource_name = "fade_in" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("AudioStreamPlayer:volume_db") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [-50.0, 0.0] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_isbl1"] +_data = { +"RESET": SubResource("Animation_meedk"), +"fade_in": SubResource("Animation_ln66x"), +"fade_out": SubResource("Animation_e1vdt") +} + +[node name="MusicPlayer" type="Node"] +script = ExtResource("1_m166w") + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +"": SubResource("AnimationLibrary_isbl1") +} + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] diff --git a/src/field/cutscenes/templates/area_transitions/area_transition.gd b/src/field/cutscenes/templates/area_transitions/area_transition.gd index ebc6a68..48584cf 100644 --- a/src/field/cutscenes/templates/area_transitions/area_transition.gd +++ b/src/field/cutscenes/templates/area_transitions/area_transition.gd @@ -13,6 +13,10 @@ class_name AreaTransition extends Trigger var target = $Destination as Sprite2D target.position = arrival_coordinates - position + target.texture.get_size()/2 +# The blackout timer is used to wait between fade-out and fade-in. No delay looks odd. +@onready var _blackout_timer: = $BlackoutTimer as Timer +@onready var _transition: = $CanvasLayer/ScreenTransition as ScreenTransition + func _ready() -> void: super._ready() @@ -22,21 +26,33 @@ func _ready() -> void: func _on_area_entered(area: Area2D) -> void: + # Pausing the field immediately will deactivate physics objects, which are in the middle of + # processing (hence _on_area_entered). We need to wait a frame before pausing anything. await get_tree().process_frame + + # Pause the field gamestate to prevent the player from wandering off mid-transition. _is_cutscene_in_progress = true - $CanvasLayer/ScreenTransition.cover(0.25) - await $CanvasLayer/ScreenTransition.finished + # Cover the screen to hide the area transition. + _transition.cover(0.25) + await _transition.finished + # Move the gamepiece to it's new position and update the camera immediately. var gamepiece: = area.owner as Gamepiece if gamepiece: gamepiece.cell = gamepiece.gameboard.pixel_to_cell(arrival_coordinates) - gamepiece._on_travel_finished() + gamepiece.reset_travel() Camera.reset_position() - await get_tree().create_timer(0.20).timeout - $CanvasLayer/ScreenTransition.reveal(0.10) - await $CanvasLayer/ScreenTransition.finished + # Let the screen rest in darkness for a little while. Revealing the screen immediately with no + # delay looks 'off'. + _blackout_timer.start() + await _blackout_timer.timeout + + # Reveal the screen and unpause the field gamestate. + _transition.reveal(0.10) + await _transition.finished + # Finally, unpause the field gameplay, allowing the player to move again. _is_cutscene_in_progress = false diff --git a/src/field/cutscenes/templates/area_transitions/area_transition.tscn b/src/field/cutscenes/templates/area_transitions/area_transition.tscn index 47f8b78..795127b 100644 --- a/src/field/cutscenes/templates/area_transitions/area_transition.tscn +++ b/src/field/cutscenes/templates/area_transitions/area_transition.tscn @@ -16,6 +16,7 @@ texture = ExtResource("3_retee") [node name="CanvasLayer" type="CanvasLayer" parent="." index="2"] [node name="ScreenTransition" type="ColorRect" parent="CanvasLayer" index="0"] +visible = false anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 @@ -23,3 +24,7 @@ grow_horizontal = 2 grow_vertical = 2 color = Color(0, 0, 0, 1) script = ExtResource("4_sgvmu") + +[node name="BlackoutTimer" type="Timer" parent="." index="3"] +wait_time = 0.25 +one_shot = true diff --git a/src/field/field.gd b/src/field/field.gd index 66f918f..8bd01e0 100644 --- a/src/field/field.gd +++ b/src/field/field.gd @@ -17,13 +17,12 @@ const PLAYER_CONTROLLER: = preload("res://src/field/gamepieces/controllers/Playe func _ready() -> void: + assert(gameboard) randomize() - assert(gameboard) Camera.scale = scale Camera.gameboard = gameboard Camera.make_current() - Camera.reset_position() diff --git a/src/field/gamepieces/gamepiece.gd b/src/field/gamepieces/gamepiece.gd index b0ae213..440aff9 100644 --- a/src/field/gamepieces/gamepiece.gd +++ b/src/field/gamepieces/gamepiece.gd @@ -165,7 +165,7 @@ func _physics_process(delta: float) -> void: # If we've reached the end of the path, either travel to the next waypoint or wrap up movement. if has_arrived: - _on_travel_finished() + reset_travel() ## Begin travelling towards the specified cell. @@ -204,6 +204,15 @@ func travel_to_cell(destination_cell: Vector2i) -> void: travel_begun.emit() +## Stop the gamepiece from travelling and set it at its cell. +func reset_travel() -> void: + _path.curve = null + _follower.progress = 0 + + set_physics_process(false) + arrived.emit() + + ## Returns [code]true[/code] if the gamepiece is currently traversing a path. func is_moving() -> bool: return is_physics_processing() @@ -225,11 +234,3 @@ func set_cell(value: Vector2i) -> void: func get_faced_cell() -> Vector2i: return (Vector2(cell) + direction).round() - - -func _on_travel_finished() -> void: - _path.curve = null - _follower.progress = 0 - - set_physics_process(false) - arrived.emit() diff --git a/src/field/ui/screen_transitions/screen_transition.gd b/src/field/ui/screen_transitions/screen_transition.gd index 7669d9f..f96993f 100644 --- a/src/field/ui/screen_transitions/screen_transition.gd +++ b/src/field/ui/screen_transitions/screen_transition.gd @@ -10,6 +10,8 @@ var _tween: Tween func _ready() -> void: mouse_filter = Control.MOUSE_FILTER_IGNORE + + show() reveal() -- GitLab