Problem with Yield function on an active child "turn" (turn RPG)

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

Hey ! I made a turn queue who’s gettint the childs, and making the fastest takes his turn first.

class_name TurnQueue

onready var active_character

func _ready():
	initialize()

func initialize():
	var mobs = get_mobs()
	mobs.sort_custom(self, "sort_mobs")
	for mob in mobs:
		mob.raise()
	active_character = get_child(0)
    active_character.play_turn()

static func sort_mobs(a, b):
	return a.speed > b.speed

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

func get_mobs():
	return get_children()

But now I’m in a pinch. The play_turn() function seems to work well, but whenever I try to call up the play_turn() function on my turn queue, it’ll say “Stack Overflow” since it’s yielding when I try to call it with $"..".play_turn() If I try to call TurnQueue.play_turn(), it’ll say “Non static funtion “play_turn” can only be called from an instance”… But my active-character is an instance. Or I’m misunderstanding something…

I hope someone could help me with this, I’m new on this yielding thing.

That code belogns to the character script? if not, can you share the play_turn function of the active_character?

p7f | 2020-06-27 15:30

This code is in my TurnQueue node :confused:
Tree looks like that :

TurnQueue → Has the script I showed above
-Child 1
-Child 2
-Child 3

Each of the 3 child has their own scripts with a Speed stats in it

Atm, I only did a fast check to verify if this work :

func play_turn():
	if mana >= 20:
		print("spell")

Rensae | 2020-06-27 17:12

I don’t get why you are calling active player’s play_turn both in yield and at the end of turnqueue’s play_turn. Shouldn’t you only call it after you obtained the new indes? Or you want to make sure that the previous active_player finished his turn?
In that case, i would emit a signal in the player’s play_turn, and then change the yield to wait for that signal. Also, you may have to ask first if active player is playing a turn.

p7f | 2020-06-28 16:27

It’s because the battle will continue until one side or the other is completely wiped out

I wanted to make sure the active_player turn was completed before calling the next one yeah

So I kind of misunderstood how to use the yield function… I see, I’ll take my time with it

I’m kinda lost tbh, I can’t seem to put all of the things I need together somehow…

Rensae | 2020-06-28 18:14

I feel lost any time i want to learn something new about programming. Eventually you start figuring out how it works, and you feel less lost hehe. I think feeling lost is part of the learning process. If you can share de project, maybe i can test it and see what can be done to work as you expected.

p7f | 2020-06-29 14:14

Ha ha yeah that’s true. Since there is no doc for Yield, I really had a hard tome figuring out how it worked. Now I think it’s all good, I just have some troubles with a previous setget I made…
I’m sorry, I can’t share the project since he’s near finished rn :confused: I’d have love to tho, but the ressources are not mine I’m only the coder in there.

onready var hp := base_hp setget set_health

Here is my setget and his function :

func set_health(new_health):
	if hp != new_health:
		hp = new_health
		$Hp1.value = int((float(hp) / max_hp) * 100)
		$HpText.text = str(hp,"/", max_hp)
	if hp <= 0:
		$'Char1/C1/1'.texture = dead
		$Hp1.value = int((float(hp) / max_hp) * 0)

$Hp1 is a progress bar texture, I think i didn’t mess up this
$HpText is a label used to write how many hp are left on the total max_hp

But it don’t work. Whenever I change the hp, it’ll not trigger and I don’t know why. I did a lot of tests on previous “projects”, but it’s the first time it seems the setget doesn’t work.

Rensae | 2020-06-29 14:30

Is that setget a different issue then? If so i recommend you openning a new question for it. If the original question is solved now, You may add an answer of how you solved it and select it so others can see its solved, and see the solution if facing the same issue.
The setget seems fine to me. If you can make at least a minimal project where to reproduce the issue, it would be easier to help!

p7f | 2020-06-29 14:42

Thanks, I’ll try to do a miniature version and then I’ll come back on another topic ^^

Rensae | 2020-06-29 15:01

:bust_in_silhouette: Reply From: Rensae

Yes, you’re right. I’m sorry I got carried away…

So, how did I solve it :

Is used the advice of p7r and used signals instead, so, my code looks like that now :

class_name TurnQueue

onready var active_character

func _ready():
	initialize()

func initialize():
	var mobs = get_mobs()
	mobs.sort_custom(self, "sort_mobs")
	for mob in mobs:
		mob.raise()
	active_character = get_child(0)
	active_character.play_turn()

static func sort_mobs(a, b):
	return a.speed > b.speed

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)
	active_character.play_turn()

func get_mobs():
	return get_children()

Now here is the solution : On your active_character, you need to create a signal using

signal completed

After that, in your play_turn() function inside of your actual character, you need to make him take his turn (creating a scene with some buttons that you can load and use for exemple), and THEN use

emit_signal("completed")

When you figure out how to use the yield function, it becomes quite handful, especially for scenarios when you need to wait for your player to take a choice.