unity3D 对接 workerman 实现联机游戏( 二 )


(2). 坐标的整合发送
服务器端在接收消息回调中,循环所有连接端,并给所有连接端发送从客户端发送过来的坐标 。
$worker->onMessage = function ($connection, $data) use ($worker) {// 循环连接foreach($worker->connections as $connection){// 发送坐标$connection->send($data);}};客户端维护一个名为 players 的字典,它将存放所有玩家的信息 。msgList 是消息列表,接收到服务端的消息后,客户端会将消息保存在 msgList 中,等待 Update 逐一进行处理 。
using UnityEngine;using System;using System.Collections;using System.Collections.Generic;using System.Net;using System.Net.Sockets;using UnityEngine.UI;public class Walk : MonoBehaviour{//socket和缓冲区Socket socket;const int BUFFER_SIZE = 1024;public byte[] readBuff = new byte[BUFFER_SIZE];//玩家列表Dictionary<string, GameObject> players = new Dictionary<string, GameObject>();//消息列表List<string> msgList = new List<string>();//Player预设public GameObject prefab;//自己的IP和端口string id;//添加玩家void AddPlayer(string id, Vector3 pos){GameObject player = (GameObject)Instantiate(prefab, pos, Quaternion.identity);TextMesh textMesh = player.GetComponentInChildren<TextMesh>();textMesh.text = id;players.Add(id, player);}//发送位置协议void SendPos(){GameObject player = players[id];Vector3 pos = player.transform.position;//组装协议string str = "POS ";str += id + " ";str += pos.x.ToString() + " ";str += pos.y.ToString() + " ";str += pos.z.ToString() + " ";byte[] bytes = System.Text.Encoding.Default.GetBytes(str);socket.Send(bytes);Debug.Log("发送 " + str);}//发送离开协议void SendLeave(){//组装协议string str = "LEAVE ";str += id + " ";byte[] bytes = System.Text.Encoding.Default.GetBytes(str);socket.Send(bytes);Debug.Log("发送 " + str);}//移动void Move(){if (id == "")return;GameObject player = players[id];//上if (Input.GetKey(KeyCode.UpArrow)){player.transform.position += new Vector3(0, 0, 1);SendPos();}//下else if (Input.GetKey(KeyCode.DownArrow)){player.transform.position += new Vector3(0, 0, -1); ;SendPos();}//左else if (Input.GetKey(KeyCode.LeftArrow)){player.transform.position += new Vector3(-1, 0, 0);SendPos();}//右else if (Input.GetKey(KeyCode.RightArrow)){player.transform.position += new Vector3(1, 0, 0);SendPos();}}//离开void OnDestory(){SendLeave();}//开始void Start(){Connect();//请求其他玩家列表,略//把自己放在一个随机位置UnityEngine.Random.seed = (int)DateTime.Now.Ticks;float x = 100 + UnityEngine.Random.Range(-30, 30);float y = 0;float z = 100 + UnityEngine.Random.Range(-30, 30);Vector3 pos = new Vector3(x, y, z);AddPlayer(id, pos);//同步SendPos();}//链接void Connect(){//Socketsocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);//Connectsocket.Connect("192.168.1.199", 1234);id = socket.LocalEndPoint.ToString();//Recvsocket.BeginReceive(readBuff, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCb, null);}//接收回调private void ReceiveCb(IAsyncResult ar){try{int count = socket.EndReceive(ar);//数据处理string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);msgList.Add(str);//继续接收socket.BeginReceive(readBuff, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCb, null);}catch (Exception e){socket.Close();}}void Update(){//处理消息列表for (int i = 0; i < msgList.Count; i++)HandleMsg();//移动Move();}//处理消息列表void HandleMsg(){//获取一条消息if (msgList.Count <= 0)return;string str = msgList[0];msgList.RemoveAt(0);//根据协议做不同的消息处理string[] args = str.Split(' ');if (args[0] == "POS"){OnRecvPos(args[1], args[2], args[3], args[4]);}else if (args[0] == "LEAVE"){OnRecvLeave(args[1]);}}//处理更新位置的协议public void OnRecvPos(string id, string xStr, string yStr, string zStr){//不更新自己的位置if (id == this.id)return;//解析协议float x = float.Parse(xStr);float y = float.Parse(yStr);float z = float.Parse(zStr);Vector3 pos = new Vector3(x, y, z);//已经初始化该玩家if (players.ContainsKey(id)){players[id].transform.position = pos;}//尚未初始化该玩家else{AddPlayer(id, pos);}}//处理玩家离开的协议public void OnRecvLeave(string id){if (players.ContainsKey(id)){Destroy(players[id]);players[id] = null;}}}3. 演示效果

unity3D 对接 workerman 实现联机游戏

文章插图
 

unity3D 对接 workerman 实现联机游戏

文章插图
 
总结以前只是从入门的角度简单介绍了一个二者通讯的方法,其实 workerman 可以基于 TCP 自定义协议,这样就可以实现特别的封包解包了 。后面如果有时间的话,可能会分享一下用 workerman 实现一个小成品的 3D 游戏 。


推荐阅读