How to make an animation from an AnimationPlayer node sync up with a line of text in a textbox?

Using a textbox and AnimationPlayer nodes, I’m trying to make it so whenever you continue to the next line of text, if you want an animation to play, it will, on that specific line of text. I’m having trouble doing so. This is for my intro cutscene.

This is the first AnimationPlayer node, which has the first lines of the intro. I’m using the Call Method option from this textbox to get the queue_text() function, which makes the text appear and work in the first place:

enum State {
	READY,
	READING,
	FINISHED
}

var current_state = State.READY
var text_queue = []
var dialog_spr_queue = []

func _ready():
	_hide_textbox()
	
func _process(delta):
	match current_state:
		State.READY:
			if !text_queue.is_empty():
				display_text()
				display_sprite()
			button_2.disabled = false
			touch_button.disabled = false
			textbox_ready.emit()
		State.READING:
			if Input.is_action_just_pressed("skip"):
				label.visible_ratio = 1
				end_symbol.text = ">"
				tween.kill()
				change_state(State.FINISHED)
				typing_dialog_sfx.stop()
			button_2.disabled = true
			touch_button.disabled = true
			textbox_reading.emit()
		State.FINISHED:
			if Input.is_action_just_pressed("interact"):
				change_state(State.READY)
				_hide_textbox()
				_smooth_transit()
				smooth_textbox_transition.emit()
				#if !text_queue.is_empty():
					#show_textbox()
				#else:
					#_hide_textbox()
			textbox_finished.emit()
				
func queue_text(next_text):
	text_queue.push_front(next_text)
	
func display_sprite():
	var next_face = dialog_spr_queue.pop_back()
	boxspr.texture = next_face
	
func queue_face(next_face):
	dialog_spr_queue.push_front(next_face)


func _hide_textbox():
	start_symbol.text = ""
	end_symbol.text = ""
	label.text = ""
	textbox_container.hide()
	
func show_textbox():
	start_symbol.text = "
	
	>"
	textbox_container.show()
	
func display_text():
	tween = get_tree().create_tween()
	var next_text = text_queue.pop_back()
	label.text = next_text
	label.visible_ratio = 0.0
	change_state(State.READING)
	show_textbox()
	tween.tween_property(label, "visible_ratio", 1.0, len(next_text) * CHAR_READ_RATE)
	tween.connect("finished", on_tween_finished)
	typing_dialog_sfx.play()
	
	
func on_tween_finished():
	end_symbol.text = ">"
	change_state(State.FINISHED)
	typing_dialog_sfx.stop()
	
func change_state(next_state):
	current_state = next_state
	match current_state:
		State.READY:
			print("Changing to be ready...")
		State.READING:
			print("Changing to be reading...")
		State.FINISHED:
			print("Changing to be finished...")

func _smooth_transit():
	if !text_queue.is_empty():
		show_textbox()
	else:
		_hide_textbox()

Then, after the last line of this AnimationPlayer node, I want to transition to another AnimationPlayer node, which, besides the text, has another animation altogether.

The text flows as it should. If I press the button that progresses the lines of text, it will proceed normally - Except the extra animation, the Sprite2D’s positioning changing. It will happen as soon as I proceed to the very second line of the intro, not when I transition to the next AnimationPlayer node containing the next string of text and the sprite’s position changing. The animation basically is triggered too early.

If it’s relevant: How I make one AnimationPlayer node go to another is by using a signal from the textbox that emits when a line of text is finished. I then put said signal in the script of the first AnimationPlayer node, where if the textbox is finished and I press a button, it will proceed to the next line of text. After a certain point, it goes to the next AnimationPlayer node.

extends AnimationPlayer
@onready var textbox = $"../CharacterBody2D/Camera2D/Textbox"
var dialogue_pass = false
@onready var begin_text_1 = $"../begin_text_1"

func _on_textbox_textbox_finished():
	if Input.is_action_just_pressed("interact") && dialogue_pass == false:
		begin_text_1.play("new_anim_1")
		dialogue_pass = true
	if Input.is_action_just_pressed("interact") && dialogue_pass == true:
		pass

TLDR: Animation is triggering too early into a cutscene, and I’m not sure how to sync it the line of text the animation is supposed to go trigger with.

Managed to fix it, eventually. It was actually quite simple. For how I built this cutscene system, I used an AnimationPlayer node for each line of text. For the first AnimationPlayer node, I emit a signal from the main Textbox node into it.

func _on_textbox_textbox_finished():
	next_dialog.emit()
	if Input.is_action_just_pressed("interact") && dialouge_pass == false && current_animation == "new_anim_0":
		begin_cutscene_1.play("new_anim_1")
		dialouge_pass = true
	if Input.is_action_just_pressed("interact") && dialouge_pass == true && current_animation == "new_anim_0":
		pass

Then, from that signal, I emit a custom signal called “next_dialog” into each subsequent AnimationPlayer node. And each subsequent node will also have a “next_dialog” signal.

func _on_begin_cutscene_next_dialog():
	next_dialog.emit()
	if Input.is_action_just_pressed("interact") && dialogue_pass == false && current_animation == "new_anim_1":
		begin_cutscene_2.play("new_anim_2")
		dialogue_pass = true
	if Input.is_action_just_pressed("interact") && dialogue_pass == true && current_animation == "new_anim_1":
		pass

The key here to get the animations to play right is to simply check what the current animation is.

I think the whole method of things is a little rough. But this is just what is working for me currently.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.