Turn queue prototyping, what am I missing?

Godot Version

4.4

Question

Hello, learning developer. It looks like the TurnQueue class will cycle through array of base class Characters I have in the array, but that’s about all I can figure out.

would you mind pointing me in the right direction for: Connecting them together correctly, and having so that truly only on Character can move at a time

extends Node2D
class_name TurnQueue

signal start_turn(character)

var active_character: Character
var turn_queue : Array[Character]
var turn_index : int = 0

func initialiaze() -> void:
    add_initial_characters()

    var character = get_child(0)
    character.connect("turn_ended", Callable(self, "next_turn"))

    if turn_queue.size() > 0:
        active_character = turn_queue[0]

func _ready() -> void:
    initialiaze()

func add_character(character: Character) -> void:
    turn_queue.append(character)
    print(character.name, " has joined, total:", turn_queue.size())

func get_all_characters() -> Array:
    return turn_queue.duplicate()

func add_initial_characters() -> void:
    for child in get_children():
        if child is Character:
            add_character(child)

func next_turn() -> void:
    if turn_queue.size() == 0:
        return
    
    turn_index = (turn_index + 1) % turn_queue.size()
    active_character = turn_queue[turn_index]
    
    print(active_character.name, "'s turn")
    emit_signal("start_turn")
extends Node2D
class_name Character

signal turn_ended

@onready var turn_queue = TurnQueue

var action_points: float

func initialize() -> void:
    turn_queue = turn_queue.new()
    turn_queue.connect("start_turn", Callable(self, "start_turn"))

func _ready() -> void:
    initialize()

func start_turn() -> void:
    print(Character.name, " played turn")
    end_turn()

func end_turn() -> void:
    emit_signal("turn_ended")

Hi,

The first thing that seems weird to me is that TurnQueue gets all of the characters in child nodes (which seems correct), while every character also has an internal TurnQueue (created in Character.initialize()), which means that you have one queue per character + a global one?

What you could do to make it clearer is that, once the global queue has initialized its array of characters, loop through them to initialize the characters with that one queue.
Basically, the queue says to each character: “Hey, from now on I’ll be the queue managing you!”

Something like this:

# TurnQueue

[...]

func add_initial_characters() -> void:
    for child in get_children():
        if child is Character:
            add_character(child)
            child.set_queue(self)  # The queue passes itself as a parameter.

[...]
# Character

[...]

var turn_queue: TurnQueue

# This replaces your initialize() function.
func set_queue(queue: TurnQueue) -> void:
    turn_queue = queue
    turn_queue.connect("start_turn", Callable(self, "start_turn"))

[...]

With such a code, you would have one queue managing all of the characters.


Another issue is that you’re calling start_turn using a signal. But, since all the characters are connected to that signal, how would each character know that it is not the currently active character? They have no way of doing that, so they all play once the signal is emitted.
Here, I believe you don’t want to use a signal. Instead, since you have a direct reference to the active character:

turn_index = (turn_index + 1) % turn_queue.size()
active_character = turn_queue[turn_index]

just use it to call its start_turn function:

turn_index = (turn_index + 1) % turn_queue.size()
active_character = turn_queue[turn_index]
active_character.start_turn()

One last thing: your start_turn function is calling end_turn. I understand that’s a placeholder code while your movement logic is not implemented, but: since end_turn is connected to the queue, it will then get the next character, call its start_turn, that will itself call its end_turn, etc., all of this on one frame.
So, it may seem like your queue logic is not working, but be careful with what. As long as you have no waiting of some sort (either with the actual movement or a placeholder timer), all of your characters will probably all play at the same time again.

Let me know if that helps :slight_smile:

Yes, that helped a bunch! Thank you!

The func set_queue in the character class. Should the signal be removed? Since it isn’t going to be used anymore?

and would you mind explaining the reason we are able to call functions from another script or how to do that? I have been trying to figure out how it works and can’t figure anything out in YouTube or google.

when I run the script, it will make it to the second character and stop the script. is that what you were talking about in the last paragraph? Is it actually going through all characters in the array?

I imagined it would just continue for ever.

What do you mean by calling functions in another script? You don’t really just call functions in a script. You attach a script to a node and you access the properties of the node. But I mean, your code is already “calling functions in another script” plenty of times, so not sure what the problem is here.

Your queue doesn’t go through the characters, because only the first character’s turn_ended signal is connected anywhere.

why and how does this work? They are separate scripts

and how would you connect all the other signals? **** i think ill actually try to figure this part out myself **** actually already figure it out.