You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Godot中await循环触发多次导致脚本丢失错误求助

循环内多次使用await触发时的错误问题

我需要遍历所有帝国,依次通知它们进行回合,等待当前回合完成后再触发下一个帝国的回合。玩家的第一个回合可以正常运行,但当AI调用endTurn()时,出现如下错误:

E 0:01:08:0911   Map.gd:419 @ endTurn(): Resumed function 'beginRound()' after await, but script is gone.  
    At script: res://scripts/HostGameMenu.gd:197  
    <C++ Error>    Method/function failed. Returning: Variant()  
    <C++ Source>   modules/gdscript/gdscript_function.cpp:197 @ resume()  
    <Stack Trace>  Map.gd:419 @ endTurn()  
    Tribe.gd:221 @ takeTurn()  
    Map.gd:414 @ beginNewTurn()  
    HostGameMenu.gd:196 @ beginRound()  
    Map.gd:419 @ endTurn()  
    Map.gd:1912 @ endEmpireTurn()  

相关脚本代码

脚本一(HostGameMenu.gd)

func beginRound():
    for i in range(empireTurnOrder.size()):
        empireTurnIndex = i # 仅用于外部调试时查看当前回合所属帝国
        gameMap.beginNewTurn.rpc(empireTurnOrder[empireTurnIndex]) # empireTurnOrder是PackedStringArray类型
        await gameMap.beginNextTurn
    gameMap.endRound.rpc() # gameMap指向脚本二所在节点

脚本二(Map.gd)

signal beginNextTurn

@rpc("any_peer", "call_local", "reliable")
func beginNewTurn(nextEmpire: String) -> void:
    var empire = getEmpire(nextEmpire)
    if empire.playerId != -1 and empire.playerId != userEmpire.playerId: # 仅用于多人模式,测试时未启用。userEmpire是玩家控制的帝国节点(脚本三实例)
        pass
    else:
        if empire.playerId == userEmpire.playerId:
            # UI修改,无关逻辑
        empire.takeTurn() # empire指向脚本三的节点实例

func endTurn():
    if not serverHandler.inServer or multiplayer.get_unique_id() == 1: # serverHandler指向脚本一所在节点,单人测试时inServer始终为true
        print(is_instance_valid(serverHandler))
        emit_signal("beginNextTurn")

func endRound():
    if not serverHandler.inServer or multiplayer.get_unique_id() == 1:
        serverHandler.beginRound()

func endEmpireTurn(): # 绑定到按钮点击事件
    # 少量UI修改
    endTurn()

脚本三(Tribe.gd)

func takeTurn():
    if playerId == -1:
        map.endTurn() # map指向脚本二所在节点
    else:
        # 玩家回合由按钮点击触发endTurn,此处无逻辑

打印输出

True

True

我已查找相关帖子,但大多是_process()中await计时器的问题,解决方案不适用于当前场景。


编辑1

在脚本一中添加如下函数,并将beginNextTurn信号连接到该函数:

func turnEnded() -> void:
    print(empireTurnOrder[empireTurnIndex] + "'s turn is over.")

信号触发时能正确打印内容,但错误依旧存在。


编辑2

尝试修改beginNewTurn和beginRound函数:

脚本二修改后的beginNewTurn

@rpc("any_peer", "call_local", "reliable")
func beginNewTurn(nextEmpire: String) -> bool:
    var empire = getEmpire(nextEmpire)
    if empire.playerId != -1 and empire.playerId != userEmpire.playerId:
        pass
    else:
        if empire.playerId == userEmpire.playerId:
            loadedData.get_node("ImportantMenuHub/EndTurn").set_disabled(false)
            loadedData.get_node("ResourceHUD/RaiseAll").set_disabled(false)
        empire.takeTurn()
    await beginNextTurn
    return true

脚本一修改后的beginRound

func beginRound():
    for i in range(empireTurnOrder.size()):
        empireTurnIndex = i
        await gameMap.beginNewTurn(empireTurnOrder[empireTurnIndex])
    gameMap.endRound.rpc()

此时在emit_signal("beginNextTurn")行出现错误:Parameter "function" is null,测试输出如下:

true

<empire 1>'s turn is over.

true

<empire 2>'s turn is over.


问题分析与解决方法

核心问题拆解

第一个错误Resumed function 'beginRound()' after await, but script is gone本质是await挂起的函数上下文被销毁,信号触发时仍尝试恢复执行;第二个错误Parameter "function" is null是因为await beginNextTurn时,信号没有绑定有效回调。

具体修复步骤

  1. 确保脚本实例生命周期稳定
    检查HostGameMenu节点是否在回合流程中被意外销毁/隐藏(比如UI切换时误删)。可以在beginRound()开头添加print(is_instance_valid(self)),回合过程中持续验证实例有效性。

  2. 修正rpc与await的配对逻辑
    单人测试场景下无需使用rpc,直接调用函数避免远程上下文干扰:

    # 脚本一的beginRound修改
    func beginRound():
        for i in range(empireTurnOrder.size()):
            empireTurnIndex = i
            # 替换rpc为直接调用
            gameMap.beginNewTurn(empireTurnOrder[empireTurnIndex])
            await gameMap.beginNextTurn
        gameMap.endRound()
    
  3. 确保信号绑定始终有效
    在脚本二的_ready()中显式绑定信号,避免动态绑定失效:

    # 脚本二的_ready函数
    func _ready():
        connect("beginNextTurn", serverHandler, "turnEnded")
    
  4. 调整AI回合触发流程
    AI回合直接调用endTurn()会导致信号立即触发,可添加短暂延迟确保逻辑完成:

    # 脚本三的takeTurn修改
    func takeTurn():
        if playerId == -1:
            # 等待AI逻辑执行完成(示例用0.1秒延迟,可根据实际逻辑调整)
            await get_tree().create_timer(0.1).timeout
            map.endTurn()
        else:
            pass
    

内容的提问来源于stack exchange,提问作者Frasher Gray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 14:48:11