游戏蛮牛学习群(纯技术交流,不闲聊):539178957
游戏蛮牛 手机端
开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

首页   >   博客   >   绿茶风凉

Unity3D笔记——UDP 广播和异步接受 热度 1

个人分类: Unity3D笔记 | 2017-12-28 09:35
标签:unity3d UDP网络
0 个评论 | 阅读 535 | 收藏 | 举报

1.鼠标点击是单一事件,不可能同一时间点击多个地方。 
2.延迟其实有点大,虽然就零点几秒。但是我们的项目对延迟比较看重。

所以提出了第二个方案:红外检测到数据后Launcher的服务通过坐标转换成屏幕坐标,通过UDP全网广播,游戏和桌面监听(桌面也需要通过触碰打开游戏等等)。所以就需要我专门做一个unity能用的UDP监听功能,并转换成输入。

一.UDP广播

为了测试,我也做了一个简单的UDP的广播代码;

[code]csharpcode:

//服务器端Scoket对象;
    UdpClient client;

    private IPEndPoint endpoint;

void Start()
    {
        //绑定UdpClient 端口,8866
        client = new UdpClient(new IPEndPoint(IPAddress.Any, 8866));

        //全网(255,255,255,255)
        endpoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 0);

        //每秒都发送
        InvokeRepeating("Send",1,1);
    }


    void Send()
    {
        string dataStr = "[{\"x\":732.8001098632813,\"y\":1000.0156860351563},{\"x\":817.5443725585938,\"y\":379.5652160644531},{\"x\":956.8383178710938,\"y\":538.0902099609375}]";

        byte[] SendData = System.Text.Encoding.UTF8.GetBytes(dataStr);

        //发送,不需要异步。因为是广播,并且不关心有没有接受
        client.Send(SendData, SendData.Length, endpoint);
    }

备注:上面的代码就做了个简单功能:向全网每秒广播信息。端口号是:8866

二.游戏这边需要接受数据了。UDP异步接受

有几点需求: 
1.单纯接受8866端口的数据就可以。 
2.将byte数据转换成坐标数据。 
3.接受到数据,才会触发游戏一些输入机制。所以需要异步接收(防止卡死)

unity这边的接受代码:

[code]csharpcode:

//服务器端Scoket对象;
    private Socket ServerSocket;

    private IPEndPoint Clients;

    private IPEndPoint Server;

    private EndPoint epSender;

    //发送数据的字符数组
    private byte[] SendData = new byte[1024];

    //接受数据的字符数组
    private byte[] ReceiveData = new byte[1024];


    // Use this for initialization
    void Start()
    {
        //服务器Socket对象实例化
        ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

        //服务器的IP和端口
        Server = new IPEndPoint(IPAddress.Any, 8866);

        //Socket对象跟服务器端的IP和端口绑定
        ServerSocket.Bind(Server);

        //客户端的IP和端口,端口 0 表示任意端口
        Clients = new IPEndPoint(IPAddress.Any, 0);

        //实例化客户端 终点
        epSender = (EndPoint)Clients;

        ServerSocket.BeginReceiveFrom(ReceiveData, 0, ReceiveData.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromClients), epSender);

    }

    /// <summary>
    /// 异步接受,处理数据
    /// </summary>
    /// <param name="iar"></param>
    private void ReceiveFromClients(IAsyncResult iar)
    {
        int reve = ServerSocket.EndReceiveFrom(iar, ref epSender);

        //数据处理
        string str = System.Text.Encoding.UTF8.GetString(ReceiveData, 0, reve);

       //每次接受到数据就传给ServerInput做处理。
        ServerInput.GetInstance().AnalyzeJsonData(str);

        ServerSocket.BeginReceiveFrom(ReceiveData, 0, ReceiveData.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromClients), epSender);

    }

下面这句是每次启动异步接受的代码。

[code]csharpcode:

ServerSocket.BeginReceiveFrom(ReceiveData, 0, ReceiveData.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveFromClients), epSender);


下面的是:每次接受到数据后就将数据传给serverInput做处理。

[code]csharpcode:

 //数据处理
        string str = System.Text.Encoding.UTF8.GetString(ReceiveData, 0, reve);

       //每次接受到数据就传给ServerInput做处理。
        ServerInput.GetInstance().AnalyzeJsonData(str);

ServerInput代码:我们的协议是json格式的。所以这里做了个json的转换。和一个公开的事件:ServerInputEvent 每次接受到数据都会传给这个事件。游戏里哪里需要 直接注册这个事件就可以用了。 
(注意:安卓的OpenOL的屏幕坐标系和unity的坐标系是上下反的。所以要处理下:Screen.height-(int)jObject[“y”])

[code]csharpcode:

public event Action<List<Vector2>> ServerInputEvent;

    private static ServerInput instance = null;
    public static ServerInput GetInstance() { return instance ?? new ServerInput(); }

    ServerInput() { instance = this; }

    /// <summary>
    /// 处理服务器传来的json信息,传给事件
    /// </summary>
    /// <param name="jsonData"></param>
    public void AnalyzeJsonData(string jsonData) {

        try
        {
            List<Vector2> posList = new List<Vector2>();
            JArray jsonObj = JArray.Parse(jsonData);

            foreach (JObject jObject in jsonObj)
            {
                //Debug.Log(jObject["x"]);
                //Debug.Log(jObject["y"]);

                Vector2 pos = new Vector2((int)jObject["x"],Screen.height-(int)jObject["y"]);
                posList.Add(pos);

            }
            if (ServerInputEvent != null)
                ServerInputEvent(posList);
        }
        catch (Exception)
        {

            throw;
        }
    } 
**最后附上test代码: 简单的打印到屏幕中 
备注下(异步接受是子线程的,所以不能直接给UI赋值 所以转到主线程的Update.涉及到物理系统也一样)**

[code]csharpcode:

[SerializeField]
    private Text text;

    string str = null;

    // Use this for initialization
    void Start () {
        //向ServerInputEvent事件注册
        ServerInput.GetInstance().ServerInputEvent += attack;
    }

    private void Update()
    {
        text.text = str;
    }

    //这边写游戏内容的控制
    void attack(List<Vector2> pos) {

        str = "";

        foreach (var item in pos)
        {
            print(item);
            str = str + "  " + "(" + item.x.ToString() + "," + item.y.ToString()+ ")";
        }
    }

最后附上项目: 
链接:https://pan.baidu.com/s/1cK0UXC 密码:9gw0

1 0

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册帐号
返回顶部