如何从一个委托调用不同的方法/脚本?

时间:2019-06-06 14:43:40

标签: c# unity3d server delegates invoke

我试图理解我的问题。 我在Unity场景中有一个服务器对象。 每当来自客户端的消息到达时,服务器需要从不同的场景调用不同的方法。

我不想在Server脚本中保留对场景中所有交互脚本的引用。我的解决方案是创建一个委托,并使交互脚本订阅该委托事件。但是,我的情况发生了变化,我发现来自不同脚本的两个方法都订阅了相同的委托,并且我只能获得很好的结果。

我的解决方案是为下一个方法专门创建另一个委托,但是我想知道我可以创建多少个委托,有没有一种方法可以创建一个委托,但是每次都要执行另一个函数(或者是另一个动作?)< / p>

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 个答案:

答案 0 :(得分:1)

我还没有完全理解问题,也看不到您在哪里订阅了事件的回调。

  

我想知道我可以创建多少个代表

→尽可能多!问题是您需要吗?


如果您想向一个事件添加多个回调(即标题的发音),则只需使用+=而不是=

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,而是使用类似的

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);
    }
}