I’m attempting to iterate through a simple array of numbers, but I’m getting strange results depending on if the array is declared within the function, and if it is passed to the function.
func repeat_word():
var word = [3,1,3]
print(word)
for i in word:
print(str(i) + " dings to play")
var dings = i
for x in range(dings):
print("ding!")
$BellSound.play()
await get_tree().create_timer(.2).timeout
await get_tree().create_timer(.3).timeout
This code works, the sound plays a set of 3, then 1 then 3 dings and the console output is displayed as expected.
however…
func repeat_word(inc_word):
print(inc_word)
for i in inc_word:
print(str(i) + " dings to play")
var dings = i
for x in range(dings):
print("ding!")
$BellSound.play()
await get_tree().create_timer(.2).timeout
await get_tree().create_timer(.3).timeout
Will only play the first ‘set’ of dings, however the print(inc_word) statement correctly shows the passed array of values (for instance if the array is " inc_word[3,1,3] ", then [3,1,3] will print to console, but only 3 dings will play.
Can anyone explain why and/or give me some ideas on how to resolve this?
In the time between me posting, and this post appearing on the forum, I’ve done some more digging, and sadly still suffering from the same issue.
Rather than pass the array to the function, the array is referenced directly, which hasn’t changed anything. I’ve also tried to work out what is different between an ‘in function’ array (as it were) and an ‘external’ array with “print(type_string(typeof(new_word)))” but it just reports an ‘Array’
Here is the current code :-
extends Node
var current_word: Array
var current_digit: int
var code_string
func add_digit_to_word():
if current_digit != 0:
var digstr = str(current_digit)
print("last digit was " + digstr)
current_word.append(current_digit)
print("array is now " + str(current_word))
current_digit = 0
func array_to_string(arr: Array) -> String:
var s = ""
for i in arr:
s += str(i) + " - "
return s
func display_word():
repeat_word() #
var s = array_to_string(current_word)
s = s.left(s.length() -2) # Removes the extra " - " at the end of the arry
$Message.text = s
$Message.show()
#var new_word = [3,1,3]
#print(type_string(typeof(new_word)))
current_word.clear()
func repeat_word():
for i in current_word:
print(str(i) + " dings to play")
var dings = i
for x in range(dings):
print("ding!")
$BellSound.play()
await get_tree().create_timer(.2).timeout
await get_tree().create_timer(.3).timeout
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
$Message.hide()
$WordTimerLabel.hide()
$DigitTimerLabel.hide()
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
if $DigitTimer.is_stopped():
$DigitTimerLabel.text = "Stopped"
$DigitTimerLabel.show()
else:
$DigitTimerLabel.text = str($DigitTimer.time_left)
$DigitTimerLabel.show()
if $WordTimer.is_stopped():
$WordTimerLabel.text = "Stopped"
$WordTimerLabel.show()
else:
$WordTimerLabel.text = str($WordTimer.time_left)
$WordTimerLabel.show()
if Input.is_action_just_pressed("tapper"):
$TapDown.play()
current_digit += 1
$DigitTimer.start()
$WordTimer.start()
if Input.is_action_just_released("tapper"):
$TapUp.play()
func _on_digit_timer_timeout() -> void:
add_digit_to_word()
func _on_word_timer_timeout() -> void:
display_word()
running the above, and building the ‘word’ with the input key (i’ve set it as spacebar), as 1 beat then 2 beats, gives the following console output
last digit was 1
array is now [1]
last digit was 2
array is now [1, 2]
1 dings to play
ding!
This shows the array is correct, but for whatever reason, the for loop does not progress to the second value.
The problem is that when using await within repeat_word() the code in display_word() that succeeds the repeat_word() call is executed before repeat_word() has finished all iterations.
Using the await keyword with a signal or a call to a function that is also a coroutine will immediately return the control to the caller.
In the caller (display_word()) the array is cleared using current_word.clear() before repeat_word() had a chance to do all dings.
The solution is to make a copy of the current_word array within repeat_word() so that it has all the data it needs to output the dings:
func repeat_word():
var word = current_word.duplicate()
for dings in word:
print(str(dings) + " dings to play")
for x in range(dings):
print("ding!")
$BellSound.play()
await get_tree().create_timer(.2).timeout
await get_tree().create_timer(.3).timeout
Yes, there is a way: use await repeat_word() in display_word():
func display_word():
var s = array_to_string(current_word)
s = s.left(s.length() -2) # Removes the extra " - " at the end of the arry
$Message.text = s
$Message.show()
await repeat_word()
current_word.clear()
I’ve rearranged the lines in display_word() so that the message is updated first (otherwise the message would be updated only after all those dings)