上两篇讲解了客户端注册和登录功能,这篇来说说客户端之间的同步。
客户端创建场景
新建一个场景,命名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玩家移动和位置同步的功能了,其实网上也有很多。