Added dialogs with subtitles
This commit is contained in:
parent
26e707f0e1
commit
478c859d33
Binary file not shown.
@ -0,0 +1,19 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="mp3"
|
||||||
|
type="AudioStreamMP3"
|
||||||
|
uid="uid://bu3mcagsgxth"
|
||||||
|
path="res://.godot/imported/Deadbird_Alright_listen_here.mp3-3cc73b7ad94c9ac3c61368e7a863ddc9.mp3str"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://_development/ayuroo/voicelines/conductor/Deadbird_Alright_listen_here.mp3"
|
||||||
|
dest_files=["res://.godot/imported/Deadbird_Alright_listen_here.mp3-3cc73b7ad94c9ac3c61368e7a863ddc9.mp3str"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0.0
|
||||||
|
bpm=0.0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
[gd_resource type="Resource" script_class="DialogEntry" format=3 uid="uid://ju7es8xi1gpc"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://crem3vn3eyf38" path="res://src/core/dialog/dialog_entry.gd" id="1_41r8w"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_41r8w")
|
||||||
|
voiceline_path = "uid://bu3mcagsgxth"
|
||||||
|
subtitle_strings = PackedStringArray("Alright listen here, lass.", "Yer in big trouble.", "If yer helpin\' crooked", "[wave]D[/wave]", "[wave]DJ[/wave]", "[wave]DJ Gro[/wave]", "[wave]DJ Grooves[/wave]", "rig the awards-,", "And I can\'t take ya to jail,", "then yer got to help me even the score.")
|
||||||
|
subtitle_timings = PackedFloat32Array(0, 2.6, 4.2, 6, 6.5, 7, 7.35, 8, 9.6, 11)
|
||||||
|
metadata/_custom_type_script = "uid://crem3vn3eyf38"
|
||||||
41
game/src/core/dialog/dialog_entry.gd
Normal file
41
game/src/core/dialog/dialog_entry.gd
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
@tool
|
||||||
|
class_name DialogEntry
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export_file("*.tres", "*.res", "*.ogg", "*.wav", "*.mp3")
|
||||||
|
var voiceline_path: String
|
||||||
|
@export var precache_vo_stream: bool = false
|
||||||
|
|
||||||
|
@export var subtitle_strings: PackedStringArray = []
|
||||||
|
@export var subtitle_timings: PackedFloat32Array = []
|
||||||
|
|
||||||
|
var _precached_stream: AudioStream
|
||||||
|
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
if precache_vo_stream and not Engine.is_editor_hint():
|
||||||
|
_precached_stream = load(voiceline_path)
|
||||||
|
|
||||||
|
|
||||||
|
func get_voiceline_stream() -> AudioStream:
|
||||||
|
return _precached_stream if precache_vo_stream else load(voiceline_path)
|
||||||
|
|
||||||
|
|
||||||
|
func get_subtitle_string_from_elapsed_time(elapsed_time: float) -> String:
|
||||||
|
var subtitle_string: String = ""
|
||||||
|
|
||||||
|
for time_index: int in range(subtitle_timings.size()):
|
||||||
|
if subtitle_timings.get(time_index) >= elapsed_time:
|
||||||
|
break
|
||||||
|
|
||||||
|
subtitle_string = subtitle_strings.get(time_index)
|
||||||
|
|
||||||
|
return subtitle_string
|
||||||
|
# old (search from reverse)
|
||||||
|
#var timings: PackedFloat32Array = subtitle_timings.duplicate()
|
||||||
|
#timings.reverse()
|
||||||
|
|
||||||
|
#for time_index: int in range(timings.size()):
|
||||||
|
#var time: float = timings.get(time_index)
|
||||||
|
#if time <= elapsed_time:
|
||||||
|
#return subtitle_strings.get((timings.size() - time_index) - 1)
|
||||||
1
game/src/core/dialog/dialog_entry.gd.uid
Normal file
1
game/src/core/dialog/dialog_entry.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://crem3vn3eyf38
|
||||||
13
game/src/core/dialog/dialog_entry_playback.gd
Normal file
13
game/src/core/dialog/dialog_entry_playback.gd
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
class_name DialogEntryPlayback
|
||||||
|
|
||||||
|
|
||||||
|
var dialog_entry: DialogEntry
|
||||||
|
var playback_position: float = 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _init(entry: DialogEntry) -> void:
|
||||||
|
dialog_entry = entry
|
||||||
|
|
||||||
|
|
||||||
|
func get_dialog_subtitle() -> String:
|
||||||
|
return dialog_entry.get_subtitle_string_from_elapsed_time(playback_position)
|
||||||
1
game/src/core/dialog/dialog_entry_playback.gd.uid
Normal file
1
game/src/core/dialog/dialog_entry_playback.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://byt7cdieik05m
|
||||||
91
game/src/core/dialog/dialog_player.gd
Normal file
91
game/src/core/dialog/dialog_player.gd
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
class_name DialogPlayer
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
signal dialog_finished(dialog_key: StringName)
|
||||||
|
|
||||||
|
static var active_dialog_playbacks: Array[DialogEntryPlayback] = []
|
||||||
|
|
||||||
|
@export_node_path("AudioStreamPlayer", "AudioStreamPlayer2D", "AudioStreamPlayer3D")
|
||||||
|
var audio_player: NodePath: set = set_audio_player
|
||||||
|
|
||||||
|
@export var dialogs: Dictionary[StringName, DialogEntry] = {}
|
||||||
|
|
||||||
|
var _audio_player: Node
|
||||||
|
var _current_dialog_key: StringName
|
||||||
|
var _current_dialog_playback: DialogEntryPlayback
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
set_process(false)
|
||||||
|
set_audio_player(audio_player)
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if is_instance_valid(_audio_player) and is_instance_valid(_current_dialog_playback):
|
||||||
|
_current_dialog_playback.playback_position = _audio_player.get_playback_position()
|
||||||
|
|
||||||
|
|
||||||
|
func set_audio_player(audio_player_path: NodePath) -> void:
|
||||||
|
if is_instance_valid(_audio_player):
|
||||||
|
_audio_player.finished.disconnect(_on_dialog_finished)
|
||||||
|
|
||||||
|
audio_player = audio_player_path
|
||||||
|
_audio_player = get_node_or_null(audio_player)
|
||||||
|
|
||||||
|
if not is_instance_valid(_audio_player):
|
||||||
|
set_process(false)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (
|
||||||
|
not _audio_player.has_method(&"play")
|
||||||
|
or not _audio_player.has_method(&"get_playback_position")
|
||||||
|
or not &"playing" in _audio_player
|
||||||
|
or not _audio_player.has_signal(&"finished")
|
||||||
|
):
|
||||||
|
_audio_player = null
|
||||||
|
push_error("audio_player is not a valid player.")
|
||||||
|
return
|
||||||
|
|
||||||
|
set_process(_audio_player.playing)
|
||||||
|
|
||||||
|
if not _audio_player.finished.is_connected(_on_dialog_finished):
|
||||||
|
_audio_player.finished.connect(_on_dialog_finished)
|
||||||
|
|
||||||
|
|
||||||
|
func play(entry_key: StringName, from_position: float = 0.0) -> void:
|
||||||
|
var dialog_entry: DialogEntry = dialogs.get(entry_key)
|
||||||
|
|
||||||
|
if is_instance_valid(dialog_entry):
|
||||||
|
stop_dialog()
|
||||||
|
|
||||||
|
_audio_player.stream = dialog_entry.get_voiceline_stream()
|
||||||
|
_current_dialog_key = entry_key
|
||||||
|
_current_dialog_playback = DialogEntryPlayback.new(dialog_entry)
|
||||||
|
active_dialog_playbacks.append(_current_dialog_playback)
|
||||||
|
|
||||||
|
_audio_player.play(from_position)
|
||||||
|
set_process(true)
|
||||||
|
|
||||||
|
|
||||||
|
func get_current_dialog_entry() -> DialogEntry:
|
||||||
|
return dialogs.get(_current_dialog_key)
|
||||||
|
|
||||||
|
|
||||||
|
func get_playback_position() -> float:
|
||||||
|
return _audio_player.get_playback_position() if is_instance_valid(_audio_player) else 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func stop_dialog() -> void:
|
||||||
|
active_dialog_playbacks.erase(_current_dialog_playback)
|
||||||
|
_current_dialog_key = &""
|
||||||
|
_current_dialog_playback = null
|
||||||
|
_audio_player.stream = null
|
||||||
|
|
||||||
|
|
||||||
|
func _on_dialog_finished() -> void:
|
||||||
|
var entry: DialogEntry = dialogs.get(_current_dialog_key)
|
||||||
|
|
||||||
|
stop_dialog()
|
||||||
|
set_process(false)
|
||||||
|
|
||||||
|
dialog_finished.emit(entry)
|
||||||
1
game/src/core/dialog/dialog_player.gd.uid
Normal file
1
game/src/core/dialog/dialog_player.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://blxophwhpim0l
|
||||||
@ -14,6 +14,7 @@
|
|||||||
[ext_resource type="Script" uid="uid://dyoa3tnirv7wh" path="res://src/core/camera/camera_effect_target.gd" id="7_ghuot"]
|
[ext_resource type="Script" uid="uid://dyoa3tnirv7wh" path="res://src/core/camera/camera_effect_target.gd" id="7_ghuot"]
|
||||||
[ext_resource type="Script" uid="uid://gvuvxikepb2r" path="res://src/gameplay/characters/player/hud.gd" id="11_y2ktv"]
|
[ext_resource type="Script" uid="uid://gvuvxikepb2r" path="res://src/gameplay/characters/player/hud.gd" id="11_y2ktv"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cwvfdx2v41k0h" path="res://src/ui/hud/crosshair.png" id="13_qx1cj"]
|
[ext_resource type="Texture2D" uid="uid://cwvfdx2v41k0h" path="res://src/ui/hud/crosshair.png" id="13_qx1cj"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ct2u3f03lwsnr" path="res://src/ui/hud/hud_subtitle.tscn" id="15_hqe5n"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_vq0uu"]
|
[sub_resource type="Resource" id="Resource_vq0uu"]
|
||||||
script = ExtResource("2_1ixuj")
|
script = ExtResource("2_1ixuj")
|
||||||
@ -289,4 +290,5 @@ scale = Vector2(0.25, 0.25)
|
|||||||
sprite_frames = SubResource("SpriteFrames_p81y6")
|
sprite_frames = SubResource("SpriteFrames_p81y6")
|
||||||
animation = &"to_hollow"
|
animation = &"to_hollow"
|
||||||
frame = 5
|
frame = 5
|
||||||
frame_progress = 1.0
|
|
||||||
|
[node name="HudSubtitle" parent="Hud" unique_id=123148710 instance=ExtResource("15_hqe5n")]
|
||||||
|
|||||||
12
game/src/ui/hud/hud_subtitle.gd
Normal file
12
game/src/ui/hud/hud_subtitle.gd
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class_name HudSubtitle
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
@onready var rich_text_label: RichTextLabel = %RichTextLabel
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
var parts: PackedStringArray = []
|
||||||
|
for playback: DialogEntryPlayback in DialogPlayer.active_dialog_playbacks:
|
||||||
|
parts.append(playback.get_dialog_subtitle())
|
||||||
|
|
||||||
|
rich_text_label.text = "\n".join(parts)
|
||||||
1
game/src/ui/hud/hud_subtitle.gd.uid
Normal file
1
game/src/ui/hud/hud_subtitle.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://ssyyrfvcmird
|
||||||
37
game/src/ui/hud/hud_subtitle.tscn
Normal file
37
game/src/ui/hud/hud_subtitle.tscn
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
[gd_scene format=3 uid="uid://ct2u3f03lwsnr"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ssyyrfvcmird" path="res://src/ui/hud/hud_subtitle.gd" id="1_07tug"]
|
||||||
|
|
||||||
|
[node name="HudSubtitle" type="Control" unique_id=123148710]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
script = ExtResource("1_07tug")
|
||||||
|
metadata/_custom_type_script = "uid://ssyyrfvcmird"
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="." unique_id=441028605]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 12
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
|
[node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer" unique_id=1994554868]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
theme_override_constants/outline_size = 4
|
||||||
|
bbcode_enabled = true
|
||||||
|
text = "Example subtitle"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 2
|
||||||
68
game/tools/dialog_test_scene.tscn
Normal file
68
game/tools/dialog_test_scene.tscn
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
[gd_scene format=3 uid="uid://bqx6t4agunl7h"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ct2u3f03lwsnr" path="res://src/ui/hud/hud_subtitle.tscn" id="1_koq4j"]
|
||||||
|
[ext_resource type="Script" uid="uid://blxophwhpim0l" path="res://src/core/dialog/dialog_player.gd" id="2_4qqmy"]
|
||||||
|
[ext_resource type="Script" uid="uid://crem3vn3eyf38" path="res://src/core/dialog/dialog_entry.gd" id="3_j86jr"]
|
||||||
|
[ext_resource type="Resource" uid="uid://ju7es8xi1gpc" path="res://_development/ayuroo/voicelines/conductor/test_dialog.tres" id="4_pnxnv"]
|
||||||
|
|
||||||
|
[sub_resource type="GDScript" id="GDScript_j86jr"]
|
||||||
|
script/source = "extends Control
|
||||||
|
|
||||||
|
@export var dialog_key: StringName
|
||||||
|
@export_range(0.0, 1.0, 0.001, \"or_greater\", \"suffix:s\") var from_position: float = 0.0
|
||||||
|
@export_range(0.0, 1.0, 0.001, \"or_greater\", \"suffix:s\") var inital_delay: float = 0.5
|
||||||
|
|
||||||
|
@onready var dialog_player: DialogPlayer = $DialogPlayer
|
||||||
|
@onready var replay_button: Button = %ReplayButton
|
||||||
|
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
replay_button.pressed.connect(_on_replay_button_pressed)
|
||||||
|
|
||||||
|
await get_tree().create_timer(inital_delay).timeout
|
||||||
|
_on_replay_button_pressed()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_replay_button_pressed() -> void:
|
||||||
|
dialog_player.play(dialog_key, from_position)
|
||||||
|
"
|
||||||
|
|
||||||
|
[node name="DialogTestScene" type="Control" unique_id=1728136061]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = SubResource("GDScript_j86jr")
|
||||||
|
dialog_key = &"listen_here"
|
||||||
|
|
||||||
|
[node name="HudSubtitle" parent="." unique_id=123148710 instance=ExtResource("1_koq4j")]
|
||||||
|
layout_mode = 1
|
||||||
|
|
||||||
|
[node name="ReplayButton" type="Button" parent="." unique_id=283603298]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -30.0
|
||||||
|
offset_top = -15.5
|
||||||
|
offset_right = 30.0
|
||||||
|
offset_bottom = 15.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "Replay"
|
||||||
|
|
||||||
|
[node name="DialogPlayer" type="Node" parent="." unique_id=928993916]
|
||||||
|
script = ExtResource("2_4qqmy")
|
||||||
|
audio_player = NodePath("AudioStreamPlayer")
|
||||||
|
dialogs = Dictionary[StringName, ExtResource("3_j86jr")]({
|
||||||
|
&"listen_here": ExtResource("4_pnxnv")
|
||||||
|
})
|
||||||
|
metadata/_custom_type_script = "uid://blxophwhpim0l"
|
||||||
|
|
||||||
|
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="DialogPlayer" unique_id=1284459]
|
||||||
Loading…
Reference in New Issue
Block a user