最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

unity3d?對(duì)接?workerman?實(shí)現(xiàn)聯(lián)機(jī)游戲功能

 更新時(shí)間:2022年10月14日 09:59:58   作者:北橋蘇  
workerman?是一款開(kāi)源高性能?PHP?應(yīng)用容器,他除了用于互聯(lián)網(wǎng)、即時(shí)通訊、APP?開(kāi)發(fā)、硬件通訊、智能家居、物聯(lián)網(wǎng)等領(lǐng)域的開(kāi)發(fā)外,這篇文章主要介紹了unity3d?對(duì)接?workerman?實(shí)現(xiàn)聯(lián)機(jī)游戲,需要的朋友可以參考下

前言:

Unity3D,相信很多人都知道是用來(lái)做游戲的。網(wǎng)上也有很多這類(lèi)視頻的教程,我也試著學(xué)習(xí)過(guò)。但是當(dāng)要實(shí)現(xiàn)多人實(shí)時(shí)對(duì)戰(zhàn)的教例比較少,而用 PHP 來(lái)做 Unity3d 的服務(wù)器端的就更少了。

我在網(wǎng)上看了一個(gè)作者用 C# 做聯(lián)機(jī)服務(wù)器端的文章后,就根據(jù)他的思路改了一個(gè) PHP 版的。例子只是多個(gè)方塊在一個(gè)場(chǎng)景下移動(dòng),所有玩家可以實(shí)時(shí)看到。以下就以幾個(gè)小事例簡(jiǎn)單介紹一下 PHP 與 Unity3D 通信的實(shí)現(xiàn)吧。(以下的環(huán)境只做參考,其他的版本也可以)

環(huán)境:

1. Unity Hub 3.3.0-c1

2. Unity3D 2019

3. PHP 7.3

4. Workman 4.1

Workman 介紹

workerman 是一款開(kāi)源高性能 PHP 應(yīng)用容器,他除了用于互聯(lián)網(wǎng)、即時(shí)通訊、APP 開(kāi)發(fā)、硬件通訊、智能家居、物聯(lián)網(wǎng)等領(lǐng)域的開(kāi)發(fā)外,也可以用于游戲服務(wù)器端的開(kāi)發(fā),之前實(shí)現(xiàn)的一個(gè)五子棋多人聯(lián)機(jī)大戰(zhàn)雖然用的是 Swoole。但是實(shí)現(xiàn)思路類(lèi)似,五子棋是給同一個(gè)房間內(nèi)的玩家更新棋子的坐標(biāo),而這里也是用于實(shí)時(shí)傳遞玩家的位置。

實(shí)現(xiàn)

客戶(hù)端是 C#,就簡(jiǎn)單先以和服務(wù)器端連接,發(fā)送,接收做例子,進(jìn)一步就是方塊移動(dòng),坐標(biāo)傳遞。

1. 簡(jiǎn)單通訊

客戶(hù)端只是用面板畫(huà)出一個(gè)輸入框 (地址) 和顯示區(qū)域 (接收服務(wù)端發(fā)送的內(nèi)容),而服務(wù)器端是創(chuàng)建 TCP 服務(wù),接收與發(fā)送。

(1). 客戶(hù)端連接

//連接
    public void Connetion()
    {
        //清理text
        recvText.text = "";
        //Socket
        socket = new Socket(AddressFamily.InterNetwork,
                         SocketType.Stream, ProtocolType.Tcp);
        //Connect
        string host = hostInput.text;
        int port = int.Parse(portInput.text);
        socket.Connect(host, port);
        clientText.text = "客戶(hù)端地址1 " + socket.LocalEndPoint.ToString();
        //Recv
        socket.BeginReceive(readBuff, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCb, null);
    }

(2). 客戶(hù)端接收

//接收回調(diào)
    private void ReceiveCb(IAsyncResult ar)
    {
        try
        {
            //count是接收數(shù)據(jù)的大小
            int count = socket.EndReceive(ar);
            //數(shù)據(jù)處理
            string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
            if (recvStr.Length > 300) recvStr = "";
            recvStr += str + "\n";

            recvText.text = "接收的消息 " + recvStr;

            Debug.LogError("接收的消息 "+ recvStr);

            //繼續(xù)接收	
            socket.BeginReceive(readBuff, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCb, null);
        }
        catch (Exception e)
        {
            recvText.text += "鏈接已斷開(kāi)";
            socket.Close();
        }
    }

(3). 客戶(hù)端發(fā)送

//發(fā)送數(shù)據(jù)
    public void Send()
    {
        string str = textInput.text;
        byte[] bytes = System.Text.Encoding.Default.GetBytes("test:" + str);
        try
        {
            socket.Send(bytes);
        }
        catch { }
    }

2. workerman 安裝

(1). 新啟一個(gè)項(xiàng)目,進(jìn)入該目錄,composer require workerman/workerman

(2). 創(chuàng)建一個(gè) start.php

<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// #### 開(kāi)啟TCP服務(wù) ####
$worker = new Worker('tcp://0.0.0.0:1234');
// 4 processes
//$worker->count = 4;
// 客戶(hù)端連接回調(diào)
$worker->onConnect = function ($connection) {
    echo "New Connection\n";
};
// 接收客戶(hù)端消息
$worker->onMessage = function ($connection, $data) use ($worker) {
    // Send data to client
    echo json_encode($data) . "\n";
     //$ip = $connection->getRemoteIp();
    foreach($worker->connections as $connection)
    {
        $connection->send($data);
    }
    //$connection->send("Hello $data \n");
};
// 客戶(hù)端關(guān)閉回調(diào)
$worker->onClose = function ($connection) {
    echo "Connection closed\n";
};
Worker::runAll();
?>

(3). 啟動(dòng),輸入 php start.php start,成功如下

(4). 打開(kāi)客戶(hù)端的 6asyn 場(chǎng)景并運(yùn)行,輸入 TCP 服務(wù)的地址和端口

(5). 點(diǎn)擊發(fā)送,就可以查看 workerman 接收到的信息。

3. 方塊移動(dòng)案例

方塊移動(dòng)服務(wù)器端幾乎不用修改,在連接成功后,將多個(gè)客戶(hù)端的坐標(biāo)傳遞到服務(wù)器端,服務(wù)器處理后再給所有連接發(fā)送坐標(biāo),客戶(hù)端再將數(shù)據(jù)繪制到場(chǎng)景中。

(1). 前后端數(shù)據(jù)約定

POS 用于標(biāo)識(shí)行為,比如 POS 為坐標(biāo)移動(dòng),同理聊天可以用 IM,登陸用 LOGIN 做標(biāo)識(shí)等 (攻擊)。第二個(gè)為客戶(hù)端連接標(biāo)識(shí),標(biāo)識(shí)往后為坐標(biāo) X, Y, Z。

(2). 坐標(biāo)的整合發(fā)送

服務(wù)器端在接收消息回調(diào)中,循環(huán)所有連接端,并給所有連接端發(fā)送從客戶(hù)端發(fā)送過(guò)來(lái)的坐標(biāo)。

$worker->onMessage = function ($connection, $data) use ($worker) {

    // 循環(huán)連接
    foreach($worker->connections as $connection)
    {
        // 發(fā)送坐標(biāo)
        $connection->send($data);
    }
};

客戶(hù)端維護(hù)一個(gè)名為 players 的字典,它將存放所有玩家的信息。msgList 是消息列表,接收到服務(wù)端的消息后,客戶(hù)端會(huì)將消息保存在 msgList 中,等待 Update 逐一進(jìn)行處理。

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和緩沖區(qū)
    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預(yù)設(shè)
    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);
    }

    //發(fā)送位置協(xié)議
    void SendPos()
    {
        GameObject player = players[id];
        Vector3 pos = player.transform.position;
        //組裝協(xié)議
        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("發(fā)送 " + str);
    }

    //發(fā)送離開(kāi)協(xié)議
    void SendLeave()
    {
        //組裝協(xié)議
        string str = "LEAVE ";
        str += id + " ";
        byte[] bytes = System.Text.Encoding.Default.GetBytes(str);
        socket.Send(bytes);
        Debug.Log("發(fā)送 " + str);
    }

    //移動(dòng)
    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();
        }
    }

    //離開(kāi)
    void OnDestory()
    {
        SendLeave();
    }

    //開(kāi)始
    void Start()
    {
        Connect();
        
        //請(qǐng)求其他玩家列表,略
        //把自己放在一個(gè)隨機(jī)位置
        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()
    {
        //Socket
        socket = new Socket(AddressFamily.InterNetwork,
                                 SocketType.Stream, ProtocolType.Tcp);
        //Connect
        socket.Connect("192.168.1.199", 1234);
        id = socket.LocalEndPoint.ToString();
        //Recv
        socket.BeginReceive(readBuff, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCb, null);
    }

    //接收回調(diào)
    private void ReceiveCb(IAsyncResult ar)
    {
        try
        {
            int count = socket.EndReceive(ar);
            //數(shù)據(jù)處理
            string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
            msgList.Add(str);
            //繼續(xù)接收	
            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();
        //移動(dòng)
        Move();
    }

    //處理消息列表
    void HandleMsg()
    {
        //獲取一條消息
        if (msgList.Count <= 0)
            return;
        string str = msgList[0];
        msgList.RemoveAt(0);
        //根據(jù)協(xié)議做不同的消息處理
        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]);
        }
    }

    //處理更新位置的協(xié)議
    public void OnRecvPos(string id, string xStr, string yStr, string zStr)
    {
        //不更新自己的位置
        if (id == this.id)
            return;
        //解析協(xié)議
        float x = float.Parse(xStr);
        float y = float.Parse(yStr);
        float z = float.Parse(zStr);
        Vector3 pos = new Vector3(x, y, z);
        //已經(jīng)初始化該玩家
        if (players.ContainsKey(id))
        {
            players[id].transform.position = pos;
        }
        //尚未初始化該玩家
        else
        {
            AddPlayer(id, pos);
        }
    }

    //處理玩家離開(kāi)的協(xié)議
    public void OnRecvLeave(string id)
    {
        if (players.ContainsKey(id))
        {
            Destroy(players[id]);
            players[id] = null;
        }
    }
}

4. 演示效果

總結(jié)

以前只是從入門(mén)的角度簡(jiǎn)單介紹了一個(gè)二者通訊的方法,其實(shí) workerman 可以基于 TCP 自定義協(xié)議,這樣就可以實(shí)現(xiàn)特別的封包解包了。

到此這篇關(guān)于unity3d 對(duì)接 workerman 實(shí)現(xiàn)聯(lián)機(jī)游戲的文章就介紹到這了,更多相關(guān)unity3d聯(lián)機(jī)游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#程序中使用LINQ to XML來(lái)查詢(xún)XML格式數(shù)據(jù)的實(shí)例

    C#程序中使用LINQ to XML來(lái)查詢(xún)XML格式數(shù)據(jù)的實(shí)例

    這篇文章主要介紹了C#程序中使用LINQ to XML來(lái)查詢(xún)XML格式數(shù)據(jù)的實(shí)例,LINQ to XML是.NET框架中集成的接口,可以將XML數(shù)據(jù)放到內(nèi)存中進(jìn)行處理,需要的朋友可以參考下
    2016-03-03
  • C#程序調(diào)用C++動(dòng)態(tài)庫(kù)(dll文件)遇到的坑及解決

    C#程序調(diào)用C++動(dòng)態(tài)庫(kù)(dll文件)遇到的坑及解決

    這篇文章主要介紹了C#程序調(diào)用C++動(dòng)態(tài)庫(kù)(dll文件)遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C#給圖片加水印的簡(jiǎn)單實(shí)現(xiàn)方法

    C#給圖片加水印的簡(jiǎn)單實(shí)現(xiàn)方法

    這篇文章主要介紹了C#給圖片加水印的簡(jiǎn)單實(shí)現(xiàn)方法,涉及C#操作圖片的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-05-05
  • C#如何動(dòng)態(tài)創(chuàng)建lambda表達(dá)式

    C#如何動(dòng)態(tài)創(chuàng)建lambda表達(dá)式

    這篇文章主要介紹了C#如何動(dòng)態(tài)創(chuàng)建lambda表達(dá)式問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C#中File類(lèi)的文件操作方法詳解

    C#中File類(lèi)的文件操作方法詳解

    這篇文章主要介紹了C#中File類(lèi)的文件操作方法,以實(shí)例的形式詳細(xì)分析了File類(lèi)對(duì)文件的創(chuàng)建、打開(kāi)、復(fù)制、刪除等各種常用的操作,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-11-11
  • 簡(jiǎn)單聊聊c# 事件

    簡(jiǎn)單聊聊c# 事件

    這篇文章主要介紹了c# 事件的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • C#?執(zhí)行Javascript腳本的方法步驟

    C#?執(zhí)行Javascript腳本的方法步驟

    本文主要介紹了C#?執(zhí)行Javascript腳本的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C#反射使用方法過(guò)程及步驟

    C#反射使用方法過(guò)程及步驟

    這篇文章主要為大家詳細(xì)介紹了C#反射使用方法過(guò)程及步驟,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C#爬取動(dòng)態(tài)網(wǎng)頁(yè)上信息得流程步驟

    C#爬取動(dòng)態(tài)網(wǎng)頁(yè)上信息得流程步驟

    動(dòng)態(tài)內(nèi)容網(wǎng)站使用 JavaScript 腳本動(dòng)態(tài)檢索和渲染數(shù)據(jù),爬取信息時(shí)需要模擬瀏覽器行為,否則獲取到的源碼基本是空的,這篇文章主要給大家詳細(xì)介紹了C#爬取動(dòng)態(tài)網(wǎng)頁(yè)上信息得流程步驟,需要的朋友可以參考下
    2024-10-10
  • Unity3D基于UGUI實(shí)現(xiàn)虛擬搖桿

    Unity3D基于UGUI實(shí)現(xiàn)虛擬搖桿

    這篇文章主要為大家詳細(xì)介紹了Unity3D基于UGUI實(shí)現(xiàn)虛擬搖桿,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04

最新評(píng)論

垣曲县| 始兴县| 松潘县| 柘城县| 贡嘎县| 阳城县| 平山县| 祁连县| 屏边| 克拉玛依市| 湟源县| 襄垣县| 阿尔山市| 义乌市| 扶余县| 屏边| 涪陵区| 吴桥县| 万安县| 太和县| 大同市| 四川省| 福安市| 农安县| 社会| 张家川| 拉孜县| 峨边| 华蓥市| 哈尔滨市| 紫金县| 滦平县| 西昌市| 金寨县| 东乡族自治县| 仁布县| 黄山市| 甘泉县| 年辖:市辖区| 小金县| 平顺县|