为什么在多嵌套事件函数中调用脚本时我的代码挂起



我正在努力让我的事件系统在统一中工作。我正在使用Nakama服务器制作在线回合制游戏。

Nakama 服务器使用事件来通知客户端。我有一个MatchClient.cs脚本来处理连接到服务器和匹配。当匹配器匹配玩家并且游戏准备好开始时,此脚本将调用MatchReady(UnityEvent)。

MatchEventBroadcastManager.cs脚本处理服务器发送到客户端的匹配事件。游戏特定的事件在此脚本中声明(例如其他脚本订阅的OnRivalMove等)它有一个MatchReady()函数,当调用MatchClient的MatchReady事件时调用该函数。

到目前为止,一切正常。

这是MatchEventBroadcastManager.cs脚本的一部分:

public delegate void MatchStartedEvent();
public static event MatchStartedEvent OnMatchStart;
public void MatchReady()
{        
//Handle notifications from the server
_client.Socket.OnNotification += (_, notification) =>
{
switch (notification.Code)
{
case 1:
OnMatchStart?.Invoke();
break;
}
};
}

我尝试使用另一个 UnityEvent 进行OnMatchStart,但它不会触发检查器中引用的任何函数(我相信这可能与事件的嵌套有关,但不确定)。

这需要在事件中,因为在玩家匹配之前我无法订阅Socket.OnNotification事件(并且Socket不为空)。

在这一点上,我们有:

  • Nakama事件通知MatchClient玩家已匹配。
  • MatchClient 通知 MatchEventBroadcastManager(以及其他脚本)匹配现已准备就绪。
  • MatchEventBroadcastManager 订阅服务器的 OnNotification 事件。
  • 当此事件触发时,将调用 OnMatchStart。

到目前为止,一切似乎都正常工作。

直到

我有一个处理等待屏幕的WaitingScreenMenu.cs脚本(显然)。

它订阅OnMatchStart事件,只想转换到下一个菜单。

private void Start()
{
MatchEventBroadcastManager.OnMatchStart += MatchStarted;
Debug.Log("Menu manager: ");
Debug.Log(_menuManager.name);
}
public void MatchStarted()
{
Debug.Log("Menu manager: ");
Debug.Log(_menuManager.name);
Debug.Log("Test after");
}

我删除了到下一个菜单的过渡,只是尝试访问外部对象进行测试,但这是执行挂起的点。

在游戏启动时的调试输出中_menuManager.name正确打印到控制台。

当调用 MatchStarted 时,"Menu manager: "会打印出来,但不打印其他内容。

如果我注释掉Debug.Log(_menuManager.name);,那么它会打印:

"Menu manager: "
"Test after"

我尝试过其他脚本,结果相同。我从一个订阅到非嵌套事件且运行正常的函数中调用了该函数。

我试图将游戏逻辑分成可管理的部分,但似乎处理事件的唯一方法是让MatchClient.cs处理所有事情,并处理巨大而笨拙的混乱。

在事件方面,Unity 真的以这种方式受到限制还是我错过了什么?

提前感谢您的帮助。

使用 Visual Studio 调试器发现了错误。在事件中中断并检查_menuManager的值显示了 UnityException。UnityException: get_gameObject can only be called from the main thread.

正在从异步方法调用事件。查看它,我发现您无法从单独的线程与 UnityEngine 进行通信。

我没有直接在Socket.OnNotification事件中调用我的事件,而是设置了一个在Update()中签入的标志,该标志随后在主线程上调用我的事件。

MatchEventBroadcastManager.cs脚本的替换部分:

private bool notifMatchStarted;
public UnityEvent MatchStarted;
void Update()
{
//Invoke events here to guarantee they are called from the main thread.
if(notifMatchStarted)
{
MatchStarted.Invoke();
notifMatchStarted = false;
}
}
public void MatchReady()
{
//Handle notifications from the server
_client.Socket.OnNotification += (_, notification) =>
{
switch (notification.Code)
{
case 1:
notifMatchStarted = true;
break;
}
};
}

相关内容

  • 没有找到相关文章

最新更新