Unity 局域网 物体同步
代码很简单没有难度,都有注解,随便 康一康 就会了。
老规矩,直接上代码:
局域网 EXE控制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 局域网控制
/// </summary>
public class LANControl_ZH : MonoBehaviour
{
//开启次数
public int _LANControlInt = 0;
public static LANControl_ZH _LANControl;
private void Awake()
{
_LANControl = this;
switch (PlayerPrefs.GetInt("_LANControlInt"))
{
case 0:
GetComponent<LANServer_ZH>().enabled = true;
GetComponent<LANClient_ZH>().enabled = false;
break;
default:
GetComponent<LANServer_ZH>().enabled = false;
GetComponent<LANClient_ZH>().enabled = true;
break;
}
Debug.Log(PlayerPrefs.GetInt("_LANControlInt"));
_LANControlInt = PlayerPrefs.GetInt("_LANControlInt");
_LANControlInt += 1;
PlayerPrefs.SetInt("_LANControlInt", _LANControlInt);
//限制本地访问exe次数
if (PlayerPrefs.GetInt("_LANControlInt") > 2)
{
_LANControlInt = 0;
PlayerPrefs.SetInt("_LANControlInt", _LANControlInt);
Application.Quit();
}
}
}
局域网 服务器
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class LANServer_ZH : MonoBehaviour
{
[Header("客户端地址")]
public string _UDPClientIP;
[Header("客户端端口")]
public int _ConnectPort;
[Header("发送字符")]
public string _Send = "Maddie";
[Header("接收字符")]
private string _Receive;
private Socket _Socket;
private EndPoint _ClientEnd;
private IPEndPoint _IpEnd;
private string _SendStr;
private byte[] _RecvData = new byte[1024];
private byte[] _SendData = new byte[1024];
private int _RecvLen;
private Thread _ConnectThread;
//可移动物体数组
public List<GameObject> _ListTra;
//可移动物体 坐标信息数据
public List<string> _TraStr = new List<string>();
// 接受客户端字符
public Queue<string> _ClientTraStr = new Queue<string>();
//移动物体名字
private static string _StrTraMoveName = "";
private void Start()
{
//在这里初始化 Server
InitSocket();
_ListTra.AddRange(GameObject.FindGameObjectsWithTag("移动"));
}
private void FixedUpdate()
{
//可选择 条件发送
//SocketSend(_Send);
if (Input.GetKeyDown(KeyCode.Space))
{
//向客户端发送信息
StartCoroutine(SocketSendTra(_ListTra));
}
if (Input.GetKeyDown(KeyCode.Q))
{
//同步客户端 信息
StartCoroutine(TraSynchronization(_ClientTraStr));
}
GameObject.Find("Text").GetComponent<Text>().text = "服务器: " + _Receive;
}
private void Update()
{
//向客户端发送信息
StartCoroutine(SocketSendTra(_ListTra));
}
/// <summary>
/// 初始化
/// </summary>
void InitSocket()
{
if (_UDPClientIP != null && _ConnectPort != 0)
{
_IpEnd = new IPEndPoint(IPAddress.Any, _ConnectPort);
// 地址 端口
//_IpEnd = new IPEndPoint(IPAddress.Parse(_UDPClientIP), _ConnectPort);
//通信通道 设置
_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//绑定地址以及开放端口
_Socket.Bind(_IpEnd);
//定义客户端
//IPEndPoint sender = new IPEndPoint(IPAddress.Any, 9631);
IPEndPoint _Sender = new IPEndPoint(IPAddress.Parse(_UDPClientIP), _ConnectPort);
_ClientEnd = _Sender;
//开启一个线程连接
_ConnectThread = new Thread(new ThreadStart(SocketReceive));
_ConnectThread.Start();
}
}
/// <summary>
/// 服务器向客户端发送信息
/// </summary>
/// <param 可移动物体数组信息="_Tra"></param>
private IEnumerator SocketSendTra(List<GameObject> _Tra)
{
//数组清空
_TraStr.Clear();
//移动物体 坐标添加
for (int i = 0; i < _Tra.Count; i++)
{
//移动物体 位置 名字
_TraStr.Add("(" + _Tra[i].transform.position.x.ToString() + "," + _Tra[i].transform.position.y + "," + _Tra[i].transform.position.z + ")" + "," + _Tra[i].name);
//开辟内存空间
_SendData = new byte[1024];
// 字符转换
_SendData = Encoding.UTF8.GetBytes(_TraStr[i]);
//信息发送 客户端
_Socket.SendTo(_SendData, _SendData.Length, SocketFlags.None, _ClientEnd);
Debug.Log("服务器:" + _TraStr[i]);
}
yield return 0;
}
/// <summary>
/// 接收客户端信息
/// </summary>
void SocketReceive()
{
while (true)
{
//开发内存空间
_RecvData = new byte[1024];
try
{
//服务器消息接收
_RecvLen = _Socket.ReceiveFrom(_RecvData, ref _ClientEnd);
//判断接收到的信息 大于 0
if (_RecvLen > 0)
{
//数据转码
_Receive = Encoding.UTF8.GetString(_RecvData, 0, _RecvLen);
if (_Receive != "")
{
_ClientTraStr.Enqueue(_Receive);
}
}
}
catch (Exception _Exception)
{
}
}
}
/// <summary>
/// 物体同步
/// </summary>
/// <param 传递坐标参数="_ClientTraStr"></param>
private IEnumerator TraSynchronization(Queue<string> _ClientTraStr)
{
//判断传递字符是否为空
if (GetRecvQueueStr() != null)
{
if (Parse(GetRecvQueueStr()) != null)
{
//移动物体 名字
Debug.Log(_StrTraMoveName);
for (int j = 0; j < _ListTra.Count; j++)
{
//检测可移动数组传递名字是否在当前客户端数组里面
if (_StrTraMoveName == _ListTra[j].transform.name)
{
//解析传递字符 并更新位置
_ListTra[j].transform.position = Parse(GetRecvQueueStr());
//减去队列第一元素
//_ClientTraStr.Dequeue();
continue;
}
}
}
}
//清除 传递字符串数组
//_ClientTraStr.Clear();
yield return 0;
}
/// <summary>
/// 返回接收到的字符串
/// </summary>
/// <returns></returns>
public string GetRecvQueueStr()
{
string _ReturnQueueStr;
//加锁防止字符串被改
lock (this)
{
if (_ClientTraStr.Count > 0)
{//队列内有数据时,取出
_ReturnQueueStr = _ClientTraStr.Dequeue();
return _ReturnQueueStr;
}
}
return null;
}
/// <summary>
/// 字符串 转换 Vector3
/// </summary>
/// <param 转接字符串="_Name"></param>
/// <returns></returns>
public static Vector3 Parse(string _Name)
{
_Name = _Name.Replace("(", "").Replace(")", "");
string[] _Str = _Name.Split(',');
_StrTraMoveName = _Str[3];
return new Vector3(float.Parse(_Str[0]), float.Parse(_Str[1]), float.Parse(_Str[2]));
}
/// <summary>
/// 连接关闭
/// </summary>
void SocketQuit()
{
//关闭线程
if (_ConnectThread != null)
{
_ConnectThread.Interrupt();
_ConnectThread.Abort();
}
//最后关闭socket
if (_Socket != null)
{
_Socket.Close();
}
Debug.LogWarning("断开连接");
}
/// <summary>
/// 在应用程序退出之前发送给所有游戏对象
/// </summary>
void OnApplicationQuit()
{
SocketQuit();
}
}
局域网 客户端
using UnityEngine;
using System.Collections;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine.UI;
using System.Collections.Generic;
/// <summary>
/// 局域网 客户端
/// </summary>
public class LANClient_ZH : MonoBehaviour
{
[Header("服务器地址")]
public string _UDPServerIP;
[Header("服务器端口")]
public int _ConnectPort;
[Header("发送字符")]
private string _Send;
[Header("接受字符")]
public string _Receive;
private string _Str = "";
private Socket _Socket;
private EndPoint _ServerEnd;
private IPEndPoint _IpEnd;
private byte[] _RecvData = new byte[1024];
private byte[] _SendData = new byte[1024];
private int _RecvLen = 0;
private Thread _ConnectThread;
//需同步物体数组
public List<GameObject> _ListTra;
//服务器 接受字符
public List<string> _ServerTraStr = new List<string>();
//同步物体 坐标信息数据
public List<string> _TraStr = new List<string>();
//同步物体名字
private static string _StrTraMoveName = "";
void Start()
{
//_UDPClientIP = "192.168.1.106";//服务端的IP
//删除字符串头部及尾部出现的空格
_UDPServerIP = _UDPServerIP.Trim();
_ListTra.AddRange(GameObject.FindGameObjectsWithTag("移动"));
InitSocket();
}
private void FixedUpdate()
{
//if (Input.GetKeyDown(KeyCode.Space))
{
//接收服务器 信息
StartCoroutine(TraSynchronization(_ServerTraStr));
}
if (Input.GetKeyDown(KeyCode.Q))
{
//向服务器发送信息
StartCoroutine(ClientSendTra(_ListTra));
}
GameObject.Find("Text").GetComponent<Text>().text = "客户端: " + _Receive;
}
/// <summary>
/// 初始化
/// </summary>
void InitSocket()
{
if (_UDPServerIP != null && _ConnectPort != 0)
{
//IP、端口赋予
_IpEnd = new IPEndPoint(IPAddress.Parse(_UDPServerIP), _ConnectPort);
//_IpEnd = new IPEndPoint(IPAddress.Any, _ConnectPort);
//通信通道赋予
_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//客户端赋予
//IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
IPEndPoint _Sender = new IPEndPoint(IPAddress.Parse(_UDPServerIP), _ConnectPort);
_ServerEnd = _Sender;
print("等待连接");
//字符串发送
SocketSend(_Str);
print("连接");
//开启一个线程连接
_ConnectThread = new Thread(new ThreadStart(SocketReceive));
_ConnectThread.Start();
}
}
/// <summary>
/// 字符串发送到服务器 (握手)
/// </summary>
/// <param 需要发送的信息="_SendStr"></param>
void SocketSend(string _SendStr)
{
//清空
_SendData = new byte[1024];
//数据转换
_SendData = Encoding.UTF8.GetBytes(_SendStr);
//发送给指定服务端
_Socket.SendTo(_SendData, _SendData.Length, SocketFlags.None, _IpEnd);
}
/// <summary>
/// 接收服务器信息
/// </summary>
void SocketReceive()
{
while (true)
{
_RecvData = new byte[1024];
try
{
//服务器消息接收
_RecvLen = _Socket.ReceiveFrom(_RecvData, ref _ServerEnd);
//判断接收到的信息 大于 0
if (_RecvLen > 0)
{
//数据转码
_Receive = Encoding.UTF8.GetString(_RecvData, 0, _RecvLen);
if (_Receive != "")
{
_ServerTraStr.Add(_Receive);
}
}
}
catch (Exception)
{
}
}
}
/// <summary>
/// 字符串发送到服务器
/// </summary>
/// <param 需要发送的信息="_Tra"></param>
private IEnumerator ClientSendTra(List<GameObject> _Tra)
{
//数组清空
_TraStr.Clear();
//移动物体 坐标添加
for (int i = 0; i < _Tra.Count; i++)
{
//移动物体 位置 名字
_TraStr.Add("(" + _Tra[i].transform.position.x.ToString() + "," + _Tra[i].transform.position.y + "," + _Tra[i].transform.position.z + ")" + "," + _Tra[i].name);
//开辟内存空间
_SendData = new byte[1024];
// 字符转换
_SendData = Encoding.UTF8.GetBytes(_TraStr[i]);
//信息发送 客户端
_Socket.SendTo(_SendData, _SendData.Length, SocketFlags.None, _IpEnd);
}
yield return 0;
}
/// <summary>
/// 物体同步
/// </summary>
/// <param 传递坐标参数="_ClientTraStr"></param>
private IEnumerator TraSynchronization(List<string> _ClientTraStr)
{
//循环检测 当前可移动数组
for (int i = 0; i < _ClientTraStr.Count; i++)
{
//判断传递字符是否为空
if (Parse(_ClientTraStr[i]) != null)
{
//移动物体 名字
Debug.Log(_StrTraMoveName);
for (int j = 0; j < _ListTra.Count; j++)
{
//检测可移动数组传递名字是否在当前客户端数组里面
if (_StrTraMoveName == _ListTra[j].transform.name)
{
//解析传递字符 并更新位置
_ListTra[j].transform.position = Parse(_ClientTraStr[i]);
continue;
}
}
}
}
//清除 传递字符串数组
_ClientTraStr.Clear();
yield return 0;
}
/// <summary>
/// 字符串 转换 Vector3
/// </summary>
/// <param 转接字符串="_Name"></param>
/// <returns></returns>
public static Vector3 Parse(string _Name)
{
_Name = _Name.Replace("(", "").Replace(")", "");
string[] _Str = _Name.Split(',');
_StrTraMoveName = _Str[3];
return new Vector3(float.Parse(_Str[0]), float.Parse(_Str[1]), float.Parse(_Str[2]));
}
/// <summary>
/// 连接关闭
/// </summary>
void SocketQuit()
{
//关闭线程
if (_ConnectThread != null)
{
_ConnectThread.Interrupt();
_ConnectThread.Abort();
}
//最后关闭socket
if (_Socket != null)
{
_Socket.Close();
}
}
/// <summary>
/// 在应用程序退出之前发送给所有游戏对象
/// </summary>
void OnApplicationQuit()
{
SocketQuit();
}
}
最终效果:
组件搭载:
基础界面:
同步物体 Tag:
暂时先这样吧,如果实在看不明白就留言,看到我会回复的。
路长远兮,与君共勉。