Unity 局域网 物体同步

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:

在这里插入图片描述

暂时先这样吧,如果实在看不明白就留言,看到我会回复的。
路长远兮,与君共勉。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Maddie_Mo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值