脚本忽略设置为 false

Script ignores set to false

这是我的脚本模型:

# 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()

我的目标是让每个玩家在轮到他们输入时打印他们的名字。只有一名玩家应该将他们的 can_play 设置为 true。在每次输入时,当前玩家的 can_play 设置为 false,下一个玩家设置为 true。

现在,除了 current_player == 3 时,此代码每次都有效。如果之后有输入,代码会同时打印“Player3”和“Player0”。 Player3 和 Player0 将他们的 can_play 一个接一个地设置为 true,只有一个输入。其他玩家也不会发生这种情况。

我试过设置一个计时器,这样代码就不会直接将 can_play 设置为 true,并且成功了。这里真正的问题是我不明白为什么代码不能只在 Player3 和 Player0

上运行

这是由事件传播引起的。输入事件从最深的叶节点开始向上冒泡。

说明

Main        ^
  - Player0 |
  - Player1 | _input(event)
  - Player2 |
  - Player3 |

情况是 Player3 can_play 并且左键单击输入事件开始向上传播场景树。

  1. Player3接收到左键点击输入事件。它 can_play 并向 Main 发出信号以执行 stuff()
    • stuff()can_play 设置为 false。
    • stuff()current_player 设置为下一个玩家,Player0
  2. Player2接收到左键点击输入事件。无法播放。
  3. Player1接收到左键点击输入事件。无法播放。
  4. Player0接收到左键点击输入事件。它 can_play 并向 Main 发出信号以执行 stuff()
    • 就是这个问题。
  5. Main接收到左键点击输入事件

解决方案

处理输入事件后调用SceneTree.set_input_as_handled()

if input.is_action_pressed("left_click") and can_play:
    emit_signal("thing")
    get_tree().set_input_as_handled()

提示

# Player.gd
func _ready():
    connect("thing", get_parent(), "stuff")

这里的thing信号连接应该是父级连接的。例如:

# Main.gd
func _ready():
    for player in players:
        player.connect("thing", self, "stuff")

这将 Player.gdMain.gd 分离。 Player.gd 不再需要了解方法 stuff().

通常,信号沿着场景树向上移动,而方法调用沿着场景树向下移动。