天天看点

PhotonServer(五)——实现客户端用户同步

上两篇讲解了客户端注册和登录功能,这篇来说说客户端之间的同步。

客户端创建场景

新建一个场景,命名GameScene,添加在上一篇中登录成功后跳转至该场景

下面操作内容都是在GameScene场景开发

1、新建一个Player预设体,把Player预设体拖入场景

2、在Player物体上新建Player.cs脚本,Player.cs脚本实现了告诉服务器准备好了,后面既可以

public class Player : MonoBehaviour
{
    //表示是否是自己
    public bool isLocalPlayer = true;
    //表示是否在通话中
    public bool IsOnCalling = false;
    public Text username_text;
    [HideInInspector]
    public string username = "";

    private SyncPlayerHandler syncPlayer;
    private PlayerPannel playerPannel;
    private CallOutPlayer callOutPlayer;
    public Dictionary<string, GameObject> newPlayerDic = new Dictionary<string, GameObject>();

    // Start is called before the first frame update
    void Start()
    {
        if (isLocalPlayer){
             playerPannel = this.GetComponent<PlayerPannel>();
             //发送一个消息告诉服务器客户端准备好了
              syncPlayer = this.GetComponent<SyncPlayerHandler>();
               syncPlayer.DefaultRequest()
        }
        else{
            callOutPlayer = this.GetComponent<CallOutPlayer>();
        } 
    }
    
    public void OnLoginPlayerInfo(string username)
    {
        this.username = username;
        username_text.text = username;
    }

    public void OnLoginPlayerResponse(List<string> usernameList)
    {
        for (int i = 0; i < usernameList.Count; i++)
        {
            playerPannel.OnPlayerCreate(usernameList[i]);//创建连接进服务器准备好的好友列表
        }
    }

    public void OnLoginNewPlayerEvent(string username)
    {
        playerPannel.OnPlayerCreate(username);
    }

    public void OnLeaveLinePlayerEvent(string username)
    {
        if (newPlayerDic.ContainsKey(username)){
            Destroy(newPlayerDic[username]);
            newPlayerDic.Remove(username);
        }
    }
}      

SyncPlayerHandler.cs实现接收服务器返回的用户列表

public class SyncPlayerHandler : BaseHandler
{
    private Player player;
    private PlayerPannel playerPannel;
    private Dictionary<byte, object> data = new Dictionary<byte, object>();
    private void Awake()
    {
        opCodeType = Common.CodeType.SyncPlayer;
        player = this.GetComponent<Player>();
        playerPannel = this.GetComponent<PlayerPannel>();
    }

    public override void Start()
    {
        base.Start();
    }

    public override void DefaultRequest()
    {
            data.Add((byte)ParameterCode.Username, username);
             PhotonEngine.Peer.SendOperation((byte)CodeType.SyncPlayer, data, SendOptions.SendReliable);
    }
    
    //发送准备好的消息后,返回了连接到服务器准备好的用户列表
    public override void OnOperationResponse(OperationResponse response)
    {
        ParameterDictionary data = response.Parameters;
        string usernameJson = data[(byte)ParameterCode.Allusername].ToString();
        string usernamedata = data[(byte)ParameterCode.Username].ToString();
        player.OnLoginPlayerInfo(usernamedata);
        playerPannel.OnSetNodeDssSignaler(usernamedata);
        List<string> usernamelist = JsonMapper.ToObject<List<string>>(usernameJson);

        player.OnLoginPlayerResponse(usernamelist);
    }
}      

NewPlayerEvent.cs实现接收到刚登录的用户信息

using Common;
using ExitGames.Client.Photon;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewPlayerEvent : BaseEvent
{

    private Player player;

    private void Awake()
    {
        eventCode = EventCode.NewPlayer;
        player = this.GetComponent<Player>();
    }
    // Start is called before the first frame update
    protected override void Start()
    {
        base.Start();
    }

   //接收到登录的用户
    public override void OnEvent(EventData eventData)
    {
        ParameterDictionary data = eventData.Parameters;
        string nusername = data[(byte)ParameterCode.Username].ToString();
        player.OnLoginNewPlayerEvent(nusername);
    }

}
      

上面三个脚本就是实现客户端同步的脚本,实现的各客户端之间告诉其他客户端自己已登录,同时获取在线的用户列表,这样就后面就可以实现某一个用户或者某几个用户通信,具体通信,我在这里就不撰述了,跟发送消息同样的道理。

服务器端接收新用户

RemoteServer.Instance.peerList  就是存储上线的用户,SyncPlayerHandler.cs分别把用户列表告诉当前上线客户端,以及当前客户端上线告诉其他客户端。

/// <summary>
    /// 表示有新用户上线
    /// </summary>
    class SyncPlayerHandler : BaseHandler
    {
        private Dictionary<byte, object> data = new Dictionary<byte, object>();

        public SyncPlayerHandler() {
            opCodeType = CodeType.SyncPlayer;
        }

        public override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters, ClientPeer peer)
        {
            List<string> usernameList = new List<string>();
            foreach (ClientPeer tempPeer in RemoteServer.Instance.peerList)
            {
                if (string.IsNullOrEmpty(tempPeer.username) == false && tempPeer != peer)
                {
                    usernameList.Add(tempPeer.username);
                }
            }

            string usernamejson = JsonConvert.SerializeObject(usernameList);

            OperationResponse opResponse = new OperationResponse(operationRequest.OperationCode);//给其指定一个opCode,区分不同的请求的响应
            data.Clear();
            data.Add((byte)ParameterCode.Allusername, usernamejson);
            data.Add((byte)ParameterCode.Username, peer.username);
            opResponse.SetParameters(data);
            RemoteServer.log.Info(usernamejson);
            peer.SendOperationResponse(opResponse, sendParameters);//通过这个方法给客户端一个响应

            //告诉其他客户端有客户端登录
            foreach (ClientPeer tempPeer in RemoteServer.Instance.peerList)
            {
                //string.IsNullOrEmpty(tempPeer.username) == false就是登录后的客户端
                if (string.IsNullOrEmpty(tempPeer.username) == false && tempPeer != peer)
                {
                    RemoteServer.log.Info("event : " + tempPeer.username);
                    EventData eventData = new EventData((byte)EventCode.NewPlayer);
                    data.Clear();
                    data.Add((byte)ParameterCode.Username, peer.username);
                    eventData.SetParameters(data);
                    tempPeer.SendEvent(eventData, sendParameters);
                }
            }
        }
    }      

后续,因为我工作行业不是游戏,所以这里就不讲述Player玩家移动和位置同步的功能了,其实网上也有很多。