Update
This commit is contained in:
146
demos/8. handling animations/handling_animations_log.gd
Normal file
146
demos/8. handling animations/handling_animations_log.gd
Normal file
@@ -0,0 +1,146 @@
|
||||
extends VBoxContainer
|
||||
|
||||
@export var dialogue_gdscript : GDScript = null
|
||||
var dialogue_engine : DialogueEngine = null
|
||||
|
||||
@onready var animation_player : AnimationPlayer = find_child("LogAnimationPlayer")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
dialogue_engine = dialogue_gdscript.new()
|
||||
dialogue_engine.dialogue_started.connect(__on_dialogue_started)
|
||||
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
|
||||
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
|
||||
dialogue_engine.dialogue_cancelled.connect(__on_dialogue_cancelled)
|
||||
|
||||
|
||||
func _input(p_input_event : InputEvent) -> void:
|
||||
if p_input_event.is_action_pressed(&"ui_accept"):
|
||||
if not animation_player.is_playing():
|
||||
dialogue_engine.advance()
|
||||
else:
|
||||
# Player is inpatient -- auto-advance the text
|
||||
var animation_name : StringName = animation_player.get_current_animation()
|
||||
var animation : Animation = animation_player.get_animation(animation_name)
|
||||
animation_player.advance(animation.get_length()) # this will fire the animation_finished signal automatically
|
||||
accept_event() # accepting input event here to stop it from traversing into into buttons possibly added through the interaction
|
||||
|
||||
|
||||
func __on_dialogue_started() -> void:
|
||||
print("Dialogue Started!")
|
||||
|
||||
|
||||
func __on_dialogue_continued(p_dialogue_entry : DialogueEntry) -> void:
|
||||
# Add the text to the log:
|
||||
var label : RichTextLabel = RichTextLabel.new()
|
||||
label.set_use_bbcode(true)
|
||||
label.set_fit_content(true)
|
||||
if p_dialogue_entry.has_metadata("author"):
|
||||
var author : String = p_dialogue_entry.get_metadata("author")
|
||||
label.set_text(" > " + author + ": " + p_dialogue_entry.get_formatted_text())
|
||||
else:
|
||||
label.set_text(" > " + p_dialogue_entry.get_formatted_text())
|
||||
add_child(label, true)
|
||||
|
||||
# Setup the animation:
|
||||
animation_player.stop(true) # internally some timers do not reset properly unless we do this
|
||||
if not animation_player.has_animation_library(&"demo"):
|
||||
var new_animation_library : AnimationLibrary = AnimationLibrary.new()
|
||||
animation_player.add_animation_library(&"demo", new_animation_library)
|
||||
var animation_library : AnimationLibrary = animation_player.get_animation_library(&"demo")
|
||||
var animation : Animation = create_visible_characters_animation_per_character(label.get_text(), 0.045, true)
|
||||
animation_player.set_root_node(label.get_path())
|
||||
animation_library.add_animation(&"dialogue", animation)
|
||||
animation_player.play(&"demo/dialogue")
|
||||
|
||||
# Setup the post dialogue callback
|
||||
if p_dialogue_entry.has_metadata(&"get_player_name"):
|
||||
animation_player.animation_finished.connect(__on_animation_finished.bind(__get_player_name), CONNECT_ONE_SHOT)
|
||||
|
||||
|
||||
func __on_dialogue_finished() -> void:
|
||||
print("Dialogue Finished! Exiting...")
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func __on_dialogue_cancelled() -> void:
|
||||
print("Dialogue Cancelled! Exiting...")
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
# Must return player name to update the variable within DialogueEngine
|
||||
func __get_player_name() -> void:
|
||||
# Get player name into the current stack:
|
||||
var line_edit : LineEdit = LineEdit.new()
|
||||
add_child(line_edit)
|
||||
var p_data : Array = []
|
||||
line_edit.text_submitted.connect(func(text : String) -> void:
|
||||
p_data.push_back(text)
|
||||
)
|
||||
line_edit.grab_focus()
|
||||
line_edit.set_placeholder("Enter your name.")
|
||||
|
||||
# Disable input processing by this node to avoid calling DialogueEngine.advance if the user presses space or enter
|
||||
set_process_input(false)
|
||||
|
||||
await line_edit.text_submitted
|
||||
line_edit.set_editable(false)
|
||||
|
||||
# Allow the user to progress the dialogue
|
||||
set_process_input(true)
|
||||
|
||||
# Auto-advance the dialogue so the user does not have to press space or enter again
|
||||
@warning_ignore("unsafe_property_access")
|
||||
dialogue_engine.player_name = p_data[0]
|
||||
dialogue_engine.advance()
|
||||
|
||||
|
||||
func __on_animation_started(p_animation_name : StringName) -> void:
|
||||
print("Animation started:", p_animation_name)
|
||||
|
||||
|
||||
func __on_animation_finished(p_animation_name : StringName, p_post_dialogue_callback : Callable) -> void:
|
||||
if p_animation_name == &"demo/dialogue":
|
||||
p_post_dialogue_callback.call()
|
||||
|
||||
|
||||
# Utility function to animate the text at a constant speed
|
||||
func create_visible_characters_animation_per_character(p_text : String, p_time_per_character : float, p_instant_first_character : bool = false, p_time_whitespace : bool = false) -> Animation:
|
||||
# Do initial calculations
|
||||
var whitespace_regex : RegEx
|
||||
if not p_time_whitespace or p_instant_first_character:
|
||||
whitespace_regex = RegEx.new()
|
||||
whitespace_regex.compile("\\s")
|
||||
|
||||
# Create animation and track
|
||||
var animation : Animation = Animation.new()
|
||||
var track_index : int = animation.add_track(Animation.TYPE_VALUE)
|
||||
animation.track_set_path(track_index, ".:visible_characters")
|
||||
animation.track_set_interpolation_type(track_index, Animation.INTERPOLATION_LINEAR)
|
||||
|
||||
# Configure keys
|
||||
var total_time : float = 0.0
|
||||
var total_visible_characters : int = 0
|
||||
var whitespace_time_offset : float = 0.0
|
||||
animation.track_insert_key(track_index, total_time, 0)
|
||||
var total_animation_length : float = 0.0
|
||||
for character : String in p_text:
|
||||
total_time += p_time_per_character
|
||||
total_visible_characters += 1
|
||||
if not p_time_whitespace and whitespace_regex.sub(character, "", true).is_empty():
|
||||
whitespace_time_offset += p_time_per_character
|
||||
continue
|
||||
total_animation_length = total_time - whitespace_time_offset
|
||||
animation.track_insert_key(track_index, total_animation_length, total_visible_characters)
|
||||
animation.set_length(total_animation_length)
|
||||
|
||||
if p_instant_first_character:
|
||||
if animation.track_get_key_count(track_index) > 0:
|
||||
# Shift all the keys back in time according to the time it took per character
|
||||
for key_index : int in animation.track_get_key_count(track_index):
|
||||
var key_time : float = animation.track_get_key_time(track_index, key_index)
|
||||
animation.track_set_key_time(track_index, key_index, key_time - p_time_per_character)
|
||||
animation.set_length(total_animation_length - p_time_per_character)
|
||||
return animation
|
||||
|
||||
|
||||
Reference in New Issue
Block a user