Simple turn-based queue not working

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By turbostack

Hello, I am trying to make a simple turn-based movement demo. The structure of my code is as such:

Node2D
- Kinematic Body 1
- Kinematic Body 2
- Kinematic Body 3

The script on Node2D is supposed to manage the turns of each kinematic body. Each kinematic body should only move once, and then the turn must transfer to the next kinematic body.

I have it configured such that the parent script waits for a signal “completed” from the child node, and then makes the next node in the tree the “active character” playing a turn. Below is the parent script.

extends Node2D

class_name TurnQueue

var active_character = get_child(0)

func play_turn():
	yield(active_character, "completed")
	var new_index : int = (active_character.get_index() + 1) % get_child_count()
	active_character = get_child(new_index)

Below is the script being used by the parent node’s children.

extends KinematicBody2D

signal completed

var inputs = {
	'ui_up': Vector2.UP,
	'ui_down': Vector2.DOWN,
	'ui_left': Vector2.LEFT,
	'ui_right': Vector2.RIGHT
}

func _unhandled_input(event):
	for dir in inputs.keys():
		if event.is_action_pressed(dir):
			move(dir)
			emit_signal("completed")

func move(dir):
	position += inputs[dir] * 500

The script for all the children each have a signal connected to the play_turn() function in the parent script. What is currently happening is that all three kinematic bodies will move together once, then I get the two errors that stop the game:

First argument of yield() is null.

and

get_child: Index p_index = 0 is out of bounds (data.children.size() = 0).

I am very new to Godot, please let me know if anything is unclear. Your help is appreciated!

:bust_in_silhouette: Reply From: johnygames

The way you chose to do this strikes me as odd. I have trouble keeping up with your code and I am sure there’s gotta be a better way to do what you want.

Having said that, I think your first issue is that all kinematic bodies trigger at the same time because there is no condition to prevent them from doing it. Since they all emit the signal at the same time, they move at the same time. Or it might be that the kinematic bodies move to the designated place instantly and it appears as if they move at the same time.

Secondly, the index of your active_character variable keeps increasing without a condition to reset it back to zero when its number exceeds the amount of children in your scene (at least I don’t see any such condition). This will result in index errors.

I would opt for simplicity whenever that is possible. I would put the kinematic bodies in a group or list so that I can loop through them at runtime. Then I would execute any commands for each of those nodes separately. At this point I would make sure to implement a method that forces the engine to wait until all animations are finished before moving to the next item in the list/group. That way it is ensured that objects will not appear to be moving simultaneously, but in a turn-based manner instead.