有没有办法使用GDScript词典来防止这种种族条件?
我正在使用GDScript中的以下函数:
func remove_entity(ent: Sprite):
sprite_lst[ent].queue_free()
sprite_lst.erase(ent)
draw_entities()
sprite_lst
是一本词典,它包含HUD上的所有精灵。这些精灵的键是它们代表的实际对象。该功能被称为从HUD中删除其中一种。
然而,这大多有效,似乎有种族条件,阻止了比赛总是按预期工作的。有时,此函数在尝试调用queue_free()
时会引发异常,因为ent
在sprite_lst ent
。 >。
要进行故障排除,我尝试在擦除对象ID之前尝试打印出对象ID。但是,一旦我向此功能添加了打印
语句,它就停止了异常。因此,我将功能更改为:
func remove_entity(ent: Sprite):
var this_sprite = sprite_lst[ent]
this_sprite.queue_free()
sprite_lst.erase(ent)
draw_entities()
当从sprite_lst
中存储实体时,该函数始终有效。在我看来,在queue_free()
之前,在词典上调用erase()
方法,在Sprite上调用。
有什么方法可以防止这种比赛状况,或者迫使这两条线依次运行?
I am working with the following function in GDScript:
func remove_entity(ent: Sprite):
sprite_lst[ent].queue_free()
sprite_lst.erase(ent)
draw_entities()
sprite_lst
is a Dictionary that holds all of the Sprites on the HUD. The keys for these Sprites are the actual object that they're representing. This function is called to remove one of those sprites from the HUD.
This mostly works alright, however, it seems to have a race condition preventing it from always working as intended. Sometimes, this function will throw an exception when trying to call queue_free()
on the intended object, because ent
is not found as a key in sprite_lst
.
To troubleshoot, I tried printing out the object ID before erasing it. However, once I added a print
statement to this function, it stopped throwing the exception. So then I changed the function to this:
func remove_entity(ent: Sprite):
var this_sprite = sprite_lst[ent]
this_sprite.queue_free()
sprite_lst.erase(ent)
draw_entities()
When storing the entity from sprite_lst
, the function always works. It seems to me like sometimes the erase()
method is called on the dictionary, before queue_free()
is called on the Sprite.
Is there any way to prevent this race condition, or force these two lines to run sequentially?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在代码中,您始终首先调用
queue_free()
。但是,这排队免费。它类似于call_deferred(“ free”)
(并不完全相同,但这可以使这个想法跨越)。我们可以在您的代码中应用大量的防御编程。
首先,我们可以检查该条目是否存在:
或者我们可以使用
get
,如果不是这样,则可以返回null:第二,我们可以检查是否有一个有效的实例(不是null,而不是释放):
这样,
queue_free
呼叫上不应有例外。我想您也想删除任何无效的条目,对吗?值得庆幸的是,
擦除
不会抱怨不在那里的钥匙,因此我们不需要支票来保护它。好吧,这会照顾错误。但是,您为什么要关心节点何时获释?我会冒险猜测您关心的原因是因为您依靠它从场景树中删除节点。我们可以直接解决这个问题:
我想您可以做到这一点(这是不一样的,因为这也在场景树之外起作用,但是我认为我们不必担心这种情况):
在这种情况下,请注意请注意,尝试从另一个不是父母的
节点
中删除node
,这不是父母会导致错误。因此,即使您知道应该是父母的,您仍然需要一张检查:或者,如果它对您有用,则可以避免使用
remove_and_skip
的父级shenanigans,例如:请注意,
emove_and_and_skip < /代码>将节点的孩子添加回场景树。
remove_child
不会(节点
将使孩子在场景树外面)。为了完整,我还会提到:
擦除
返回是否删除了某些内容。IS_QUEUD_FOR_DELETION
在Object> Object
上检查queue_free
。还提醒您,释放
node
并不能使其所有引用null
相反,它们变得无效,这就是为什么is_instance_valid
并检查如果不是null
不是同一回事。In your code, you always call
queue_free()
first. However, that queues a free. It is similar tocall_deferred("free")
(not exactly the same, but this gets the idea across).We can apply plenty of defensive programming to your code.
First of all, we can check if the entry is there:
Or we can use
get
which will return null if it isn't:Second we can check if we got a valid instance (not null and not freed):
That way there should be no exception on the
queue_free
call.I suppose you want to remove any invalid entry, too, right? Thankfully
erase
won't complain about a key not being there, so we don't need a check to guard it.Alright, that takes care of the error. However, why do you care about when the node gets freed? I'll venture to guess that the reason you care is because you rely on it to remove the node from the scene tree. We could address that directly:
I suppose you could do this instead (which isn't the same, because this also works outside of the scene tree, but I don't think we need to worry about that case):
On that note, be aware that attempting to remove a
Node
from anotherNode
which isn't the parent will cause an error. So even if you know which should be parent, you still need a check:Or, if it works for you, you could avoid parent shenanigans with
remove_and_skip
, for example:Be aware that
remove_and_skip
will add the children of the node back to the scene tree. Whileremove_child
would not (theNode
will keep children outside the scene tree).For completeness I'll also mention that:
erase
returns whether or not it removed something.is_queued_for_deletion
to check if you calledqueue_free
on anObject
.And also remind you that freeing a
Node
does not make all the reference to itnull
, instead they become invalid, which is whyis_instance_valid
and checking if it isn'tnull
aren't the same thing.