xiandie/scene/dialog/balloon_debug.gd

208 lines
6.6 KiB
GDScript3
Raw Permalink Normal View History

extends CanvasLayer
@export var force_locale :String:
set(val):
force_locale = val
if force_locale:
TranslationServer.set_locale(force_locale)
@export var auto_play := true
## The action to use for advancing the dialogue
@export var next_action: StringName = &"interact"
## The action to use to skip typing the dialogue
@export var skip_action: StringName = &""
## The dialogue resource
var resource: DialogueResource
## Temporary game states
var temporary_game_states: Array = []
## See if we are waiting for the player
var is_waiting_for_input: bool = false
## See if we are running a long mutation and should hide the balloon
var will_hide_balloon: bool = false
## The current line
var dialogue_line: DialogueLine:
set(value):
if value:
dialogue_line = value
apply_dialogue_line()
else:
# The dialogue has finished so close the balloon
queue_free()
get:
return dialogue_line
## A cooldown timer for delaying the balloon hide when encountering a mutation.
var mutation_cooldown: Timer = Timer.new()
## The base balloon anchor
@onready var balloon: Control = %Balloon
## The label showing the name of the currently speaking character
@onready var character_label: RichTextLabel = %CharacterLabel
## The label showing the currently spoken dialogue
@onready var dialogue_label: DialogueLabel = %DialogueLabel
@onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer
func _ready() -> void:
balloon.hide()
Engine.get_singleton("DialogueManager").mutated.connect(_on_mutated)
mutation_cooldown.timeout.connect(_on_mutation_cooldown_timeout)
add_child(mutation_cooldown)
# 自定义获得文本,从 tags 中获取备注参数
func _setup_content_text() -> void:
var translation_key = dialogue_line.translation_key
var text
if translation_key:
text = tr(translation_key, "dialogue")
if text == translation_key:
text = dialogue_line.text
else:
text = dialogue_line.text
if dialogue_line.tags.has("shake"):
# eg. [shake rate=20 level=10][/shake]
text = "[shake rate=20 level=6]" + text + "[/shake]"
character_label.text = "[shake rate=20 level=6]" + character_label.text + "[/shake]"
if dialogue_line.tags.has("wave"):
# eg. [wave amp=25 freq=5][/wave]
text = "[wave amp=15 freq=5]" + text + "[/wave]"
character_label.text = "[wave amp=15 freq=5]" + character_label.text + "[/wave]"
if dialogue_line.tags.has("item"):
# orange color
text = "[color=orange]" + text + "[/color]"
dialogue_line.text = text
# func _unhandled_input(_event: InputEvent) -> void:
# # Only the balloon is allowed to handle input while it's showing
# get_viewport().set_input_as_handled()
# func _notification(what: int) -> void:
# ## Detect a change of locale and update the current dialogue line to show the new language
# if what == NOTIFICATION_TRANSLATION_CHANGED and _locale != TranslationServer.get_locale() and is_instance_valid(dialogue_label):
# _locale = TranslationServer.get_locale()
# var visible_ratio = dialogue_label.visible_ratio
# self.dialogue_line = await resource.get_next_dialogue_line(dialogue_line.id)
# if visible_ratio < 1:
# dialogue_label.skip_typing()
## Start some dialogue
func start(dialogue_resource: DialogueResource, title: String, extra_game_states: Array = []) -> void:
temporary_game_states = [self] + extra_game_states
is_waiting_for_input = false
resource = dialogue_resource
self.dialogue_line = await resource.get_next_dialogue_line(title, temporary_game_states)
const CHARACTER_COLOR_MAP = {
"音效": Color.DARK_VIOLET,
"美术": Color.WHITE_SMOKE,
"default": Color.LIGHT_SALMON,
}
## Apply any changes to the balloon given a new [DialogueLine].
func apply_dialogue_line() -> void:
mutation_cooldown.stop()
is_waiting_for_input = false
balloon.focus_mode = Control.FOCUS_ALL
balloon.grab_focus()
character_label.visible = not dialogue_line.character.is_empty()
character_label.text = tr(dialogue_line.character, "dialogue")
#主要角色颜色
if CHARACTER_COLOR_MAP.has(dialogue_line.character):
character_label.modulate = CHARACTER_COLOR_MAP[dialogue_line.character]
else:
character_label.modulate = CHARACTER_COLOR_MAP["default"]
dialogue_label.hide()
_setup_content_text()
dialogue_label.dialogue_line = dialogue_line
# Show our balloon
balloon.show()
will_hide_balloon = false
dialogue_label.show()
if not dialogue_line.text.is_empty():
dialogue_label.type_out()
# # Wait for input
# if dialogue_line.responses.size() > 0:
# balloon.focus_mode = Control.FOCUS_NONE
# responses_menu.show()
# else:
is_waiting_for_input = true
# balloon.focus_mode = Control.FOCUS_ALL
# balloon.grab_focus()
await get_tree().create_timer(2.0).timeout
# debug line 不需要下一行,直接释放(避免触发 dialogue_ended 信号)
queue_free()
## Go to the next line
func next(next_id: String) -> void:
self.dialogue_line = await resource.get_next_dialogue_line(next_id, temporary_game_states)
#region Signals
func _on_mutation_cooldown_timeout() -> void:
if will_hide_balloon:
will_hide_balloon = false
balloon.hide()
func _on_mutated(_mutation: Dictionary) -> void:
is_waiting_for_input = false
will_hide_balloon = true
mutation_cooldown.start(0.1)
# func _on_balloon_gui_input(event: InputEvent) -> void:
# # 根据全局配置,是否允许忽略输入
# if temporary_game_states.has(GlobalConfig.DIALOG_IGNORE_INPUT):
# return
# # See if we need to skip typing of the dialogue
# if dialogue_label.is_typing:
# if event.is_action_pressed("interact") or event.is_action_pressed("cancel"):
# dialogue_label.skip_typing()
# get_viewport().set_input_as_handled()
# return
# # var mouse_was_clicked: bool = event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed()
# # var skip_button_was_pressed: bool = event.is_action_pressed(skip_action)
# # if mouse_was_clicked or skip_button_was_pressed:
# # get_viewport().set_input_as_handled()
# # dialogue_label.skip_typing()
# # return
# if not is_waiting_for_input: return
# if dialogue_line.responses.size() > 0: return
# When there are no response options the balloon itself is the clickable thing
# get_viewport().set_input_as_handled()
# if event is InputEventMouseButton and event.is_pressed() and event.button_index == MOUSE_BUTTON_LEFT:
# next(dialogue_line.next_id)
# elif event.is_action_pressed(next_action) and get_viewport().gui_get_focus_owner() == balloon:
# if event.is_action_pressed("interact") or event.is_action_pressed("cancel"):
# # if event.is_action_pressed("interact") and get_viewport().gui_get_focus_owner() == balloon:
# get_viewport().set_input_as_handled()
# manually_skipped_line.emit()
# next(dialogue_line.next_id)