我做了循环,但它停止了主循环。请帮忙
extends Area2D
@onready var sprite = $Sprite
@onready var audio = $Audio
@onready var body = $Body
var rock = false
func disable_stone(player, stone_thread):
stone_thread.start(await disable(player, stone_thread))
func disable(player, stone_thread):
if !rock:
print("super")
rock = true
await get_tree().create_timer(0.5).timeout
body.colbox.disabled = true
sprite.modulate.a8 = 100
audio.play()
await get_tree().create_timer(2).timeout
while !(player in get_overlapping_areas()): pass
body.colbox.disabled = false
sprite.modulate.a8 = 255
rock = false
stone_thread.wait_to_finish()
我生成线程。我不知道如何解决这个问题。我尝试了我所知道的一切。
信号在主线程上调度,并同步执行。
当您
await
作为信号※时,该方法将返回(并因此停止执行)一个对象,该对象表示其在代码中的位置。
然后,当发出等待的信号时,Godot 将获取该对象,尝试找到它来自的代码中的位置,并从那里执行......再次:同步。
因此,当您
await
时,代码的执行最终将在主线程中恢复。
顺便说一句,你知道有些信号
signal
会传递一些参数,那么,当你 await
一个信号时,它会返回传递的第一个参数的值。
※:是的,你
await
发出信号。当您拨打 create_timer
时,您会收到 SceneTreeTimer
,然后您会 await
从中收到 timeout
信号。您可以await
任何其他信号。
我还看到你
await
的disable
方法,这使得该方法成为一个协同例程......而你正在将结果提供给Thread
?我觉得你不是这个意思。
你的问题的症结似乎是这一行:
while !(player in get_overlapping_areas()): pass
# REST OF YOUR CODE HERE
您正在循环等待
player
不再与 Area2D
重叠。除了 get_overlapping_areas
中的列表在物理框架上更新之外。如果主线程在这个循环中,它永远不会执行物理帧。这使得这个循环成为无限循环。
因此我们要解决的是如何等待
player
不再与Area2D
重叠。
为此,不要使用辅助
Thread
,也不要使用协同例程。
解决此问题的正统方法是检查
_physics_frame
是否仍与 player
重叠。 顺便说一下,不要检查
Area2D
,而是检查player in get_overlapping_areas()
。
由于您不立即关心检查,因此我们需要第二个 overlaps_area(player)
标志(除了
bool
之外)。我称之为 rock
,所以你可以这样做:waiting_exit
将方法连接到 func _physics_process(_delta:float) -> void:
if waiting_exit and not overlaps_area(player):
waiting_exit = false
# REST OF YOUR CODE HERE
area_exited
重叠时,您会收到信号:
Area2D
(如果对象是物理体或类似物体),或 body_exited
(如果对象是另一个区域)。既然您正在检查 area_exited
,我假设
get_overlapping_areas
是 player
,因此您需要 Area2D
。因此,您可以将一个方法连接到 area_exited
信号(请参阅
使用信号),并在该方法中放置代码的第二部分:
area_exited
将匿名方法连接到 func _on_area_exited(area:Area2D) -> void:
if waiting_exit and player == area:
waiting_exit = false
# REST OF YOUR CODE HERE
area_exited
信号的解决方案:
area_exited
是的,您可以重用匿名函数。然而,此时使用传统的命名函数(例如在之前的解决方案中)会更好。
等待
# Declare a continuation variable
# Initialize it with an empty callable, so we can reference it
var continuation := Callable()
# Set the continuation to an anonymous method
continuation = func(area:Area2D) -> void:
# Make sure the area leaving is the player
if area != player:
return
# REST OF YOUR CODE HERE
# Safely disconnect
if continuation.is_valid() and area_exited.is_connected(continuation):
area_exited.disconnect(continuation)
# Release the reference to this anonymous method
continuation = Callable()
# Connect the signal to the continuation
area_exited.connect(continuation)
的解决方案
area_exited
await
信号可能很诱人,所以我要在这里提一下。但是,我也不推荐这样做(不是线程安全的)。我相信会是这样的:
area_exited
问题是,使用多线程物理时可能无法正常工作(因为您的代码不会不断等待信号)。
检查每个物理框架的解决方案(但使用
while player == await area_exited:
pass
# REST OF YOUR CODE HERE
await
解决此问题,我建议改为
await
物理框架:await
这种方法应该没有问题,而且这是对你所拥有的最小的改变。