Почему мой код зависает при вызове скрипта в функции с несколькими вложенными событиями - PullRequest
0 голосов
/ 29 апреля 2019

Я изо всех сил пытаюсь заставить мою систему событий работать в единстве.Я делаю онлайновую пошаговую игру с сервером Nakama.

Сервер Nakama использует события для уведомления клиентов.У меня есть сценарий MatchClient.cs, который обрабатывает подключение к серверу и поиск совпадений.Этот сценарий вызывает MatchReady (UnityEvent), когда игроки нашли совпадения и игра готова к запуску.

Сценарий MatchEventBroadcastManager.cs обрабатывает события сопоставления, отправленные клиенту сервером.События, специфичные для игры, объявляются в этом сценарии (например, OnOpponentMove и т. Д., На которые подписываются другие сценарии). Имеется функция MatchReady(), которая вызывается при вызове события MatchReady MatchClient.

Пока чтовсе работает правильно.

Это часть сценария 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 действительно ограничена таким образом в отношении событий, или я что-то упустил?

Заранее спасибо за помощь.

Дан

1 Ответ

1 голос
/ 30 апреля 2019

При использовании отладчика 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;
        }
    };
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...