Here's a mock-up of my script:
# player.gd
extends HBoxContainer
class_name Player
var can_play = false
signal thing
func _ready():
connect("thing", #the following script# , "stuff")
func _input(Input):
if !can_play:
return
emit_signal("thing")
# game.gd
extends Node
var players = [Player0, Player1, Player2, Player3] # of class Player
var current_player = 0
func _ready():
yadda()
func yadda():
players[current_player].can_play = true
func stuff():
players[current_player].can_play = false
print(players[current_player])
current_player = (current_player + 1) % 4
yadda()
My goal here is to have each player get their name printed when it's their turn and on input. Only one player should have their can_play set to true. On every input, the current player has their can_play set to false and the next one set to true.
Now this code works every time except when current_player == 3. If there's an input after that, the code prints both "Player3" and "Player0". Player3 and Player0 have their can_play set to true one after the other with only one input. This doesn't happen for the other Players either.
I have tried setting a Timer so that the code doesn't set can_play to true directly and it was successful. The real problem here is that I don't understand why the code wouldn't work only on Player3 and Player0
This is caused by event propagation. Input events bubble up the tree starting from the deepest leaf nodes.
Explanation
The situation is when
Player3can_playand the left click input event begins propagating up the scene tree.Player3receives the left click input event. Itcan_playand signals toMainto dostuff().stuff()setscan_playto false.stuff()setscurrent_playerto the next player,Player0.Player2receives the left click input event. It can't play.Player1receives the left click input event. It can't play.Player0receives the left click input event. Itcan_playand signals toMainto dostuff().Mainreceives the left click input event.Solution
Call
SceneTree.set_input_as_handled()after handling the input event.Tip
The
thingsignal connection here should be connected by the parent. For example:This decouples
Player.gdfromMain.gd.Player.gdno longer needs to know about the methodstuff().Generally, signals go up the scene tree and method calls go down the scene tree.