Как вызвать разные методы / сценарии от одного делегата? - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь понять мой вопрос. У меня есть объект сервера в сцене Unity. Сервер должен вызывать разные методы из разных сцен каждый раз, когда приходит сообщение от Клиента.

Я бы предпочел не хранить ссылки на все сценарии взаимодействия в моей сцене в сценарии сервера. Моим решением было создать делегата и подписать скрипт взаимодействия на событие делегата. Однако моя сцена изменилась, и я обнаружил, что два метода из разных сценариев подписываются на одного и того же делегата, и я получаю только хороший результат.

Мое решение состояло в том, чтобы создать другого делегата специально для следующего метода, но мне интересно, сколько делегатов я могу создать, и есть ли способ создать один делегат, но каждый раз он выполняет другую функцию (или это другое действие?)

public class Server : MonoBehaviour
{
    public delegate void CommunicationEvent();
    public static event CommunicationEvent OnCommunication;

    public delegate void PortalEvent();
    public static event PortalEvent OnSceneSync;

    private const int MAX_USER = 1;
    private const int PORT = 26000;
    private const int WEB_PORT = 26001;
    private const int BYTE_SIZE = 1024; 

 /*.... */

    private void LightsOn(int cnnId, int recHostId, Net_OnEnterGate oeg)
    {
        OnCommunication?.Invoke();
        SendClient(recHostId, cnnId, oeg);
    }

    private void SceneSyncing(int cnnId, int recHostId, Net_OnSceneSync oss)
    {
        oss.TransNumber = LoadScene.currentSceneNumber;
        OnSceneSync?.Invoke();
        SendClient(cnnId, recHostId, oss);
    }

    private void LoadNewScene(int cnnID, int recHostId, Net_OnSceneLoad osl)
    {
        OnCommunication?.Invoke();
    }

Я хочу, если возможно иметь один делегат OnCommunication (), и чтобы на него подписывались разные сценарии для выполнения их уникальных методов, а не для выполнения метода из предыдущего сценария в сцене.

Возможно ли и какой рабочий процесс вы бы предложили?

1 Ответ

1 голос
/ 06 июня 2019

Я еще не до конца понял вопрос и не вижу, где вы подписываете обратные вызовы к событиям.

Интересно, сколько делегатов я могу создать

& RightArrow; Столько, сколько вам нравится! Вопрос в том, нужен ли ты и хочешь?


Если вы хотите добавить несколько обратных вызовов к одному событию (так звучит заголовок), вы просто используете += вместо =

public class Example : MonoBehaviour
{
     private void Awake()
     {
         // Note: It is always save to remove callbacks
         //       even if not added yet.
         //       This makes sure they are added only once for this instance
         OnCommunication -= OnServerCommunication;
         OnSceneSync -= OnServerSceneSync;

         OnCommunication += OnServerCommunication;
         OnSceneSync += OnServerSceneSync;
     }

     privtae void OnDestroy()
     {
         // Make sure to always remove callbacks when not needed anymore
         OnCommunication -= OnServerCommunication; 
         OnSceneSync -= OnServerSceneSync;
     }

     private void OnServerCommunication()
     {
         Debug.Log("Communication was invoked", this);
     }

     private void OnServerSceneSync()
     {
         Debug.Log("Scene sync was invoked", this);
     }
}

Если ваш вопрос скорее похож на «Я хочу добавить несколько обратных вызовов, но всегда выполнять только один из них». Я бы посоветовал вообще не использовать event s, а что-то вроде

public interface IServerCommunicationHandler
{
    void OnServerCommunication();
}

public interface IServerSceneSyncHandler
{
    void OnServerSceneSync();
}

А в хранилище сервера слушатели вроде

public class Server : MonoBehaviour
{
    private static readonly List<IServerCommunicationHandler> CommunicationListeners = new List<IServerCommunicationHandler>();
    private static readonly List<IServerSceneSyncHandler> SceneSyncListeners = new List<IServerSceneSyncHandler>();

    public static void AddCommunicationListener(IServerCommunicationHandler listener)
    {
        if (!CommunicationListeners.Contains(listener)) CommunicationListeners.Add(listener);
    }

    public static void RemoveCommunicationListener(IServerCommunicationHandler listener)
    {
        if (CommunicationListeners.Contains(listener)) CommunicationListeners.Remove(listener);
    }

    public static void AddSceneSyncListener(IServerSceneSyncHandler listener)
    {
        if (!SceneSyncListeners.Contains(listener)) SceneSyncListeners.Add(listener);
    }

    public static void RemoveSceneSyncListener(IServerSceneSyncHandler listener)
    {
        if (SceneSyncListeners.Contains(listener)) SceneSyncListeners.Remove(listener);
    }
}

и чем вместо OnCommunication?Invoke() и OnSceneSync?.Invoke() есть, например,

private void InvokeCommunication()
{
    var listener = CommunicationListeners.Count > 0 ? CommunicationListeners[0] : null;
    if (listener == null) return;

    listener.OnServerCommunication();
    CommunicationListeners.RemoveAt(0);
}

private void InvokeSceneSync()
{
    var listener = SceneSyncListeners.Count > 0 ? SceneSyncListeners[0] : null;
    if (listener == null) return;

    listener.OnServerSceneSync();
    SceneSyncListeners.RemoveAt(0);
}

Тогда сценарии могут выглядеть, например,

public class Example : MonoBehaviour, IServerCommunicationHandler, IServerSceneSyncHandler
{
    private void Awake()
    {
        Server.AddCommunicationListener(this);
        Server.AddSceneSyncListener(this);
    }

    private void OnDestroy()
    {
        Server.RemoveCommunicationListener(this);
        Server.RemoveSceneSyncListener(this);
    }

    public void OnSeverCommunication()
    {
        Debug.Log("Communication was invoked", this);
    }

    public void OnServerSceneSync()
    {
        Debug.Log("Scene sync was invoked", this);
    }
}
...