leaf 和cocos creator 遊戲實戰(一)使用protobuf完成通訊

來源:互聯網
上載者:User

項目目的:

  • 開發一個互動性的小遊戲,限於服務端經驗較少,故開始學習leaf架構,用戶端用cocos creator。
  • 網路上此類可學習案例較少,故想一邊學習,一邊分享給後學者,謹以此勉勵自己!

環境搭建:

  • golang 環境搭建和cocos creator的環境搭建網上教程很多,不再贅述,golang IDE可使用Goland。

  • leaf架構地址:https://github.com/name5566/leaf.git

  • leaf入門教程:https://github.com/name5566/leaf/blob/master/TUTORIAL_ZH.md

  • example gihub地址:
        server:https://github.com/ddkgo/LeafServerExample.git
        client:https://github.com/ddkgo/LeafServerCocosClient.git

  • LeafServerExample搭建:
    擷取:
    git clone https://github.com/ddkgo/LeafServerExample.git
    設定 LeafServerExample目錄到 GOPATH 環境變數後擷取 Leaf:
    go get github.com/name5566/leaf
    擷取protobuf支援:
    go get github.com/golang/protobuf/proto

本文:

server接收和處理訊息:

1.建立一個msgPro.proto:
syntax = "proto3";package msg;message Hello {    int32 id = 1;    string name = 2;}

編譯 msgPro.proto 檔案(對此不瞭解?請先閱讀《在 Golang 中使用 Protobuf》一文)得到 msgPro.pb.go 檔案,命令如下:
        protoc --go_out=. msgPro.proto
將msgPro.pb.go 放在LeafServerExample src/msg檔案夾下。

2.編輯 msg.go 檔案:
package msgimport (    "github.com/name5566/leaf/network/protobuf")// 使用 Protobuf 訊息處理器var Processor = protobuf.NewProcessor()func init() {    Processor.Register(&Hello{})}
3.接下來處理 Hello 訊息的路由:

將 Hello 訊息路由到 game 模組中。開啟 LeafServerExample gate/router.go,敲入如下代碼:

package gateimport (    "server/msg"    "server/game")func init() {    // 這裡指定訊息 Hello 路由到 game 模組    msg.Processor.SetRouter(&msg.Hello{}, game.ChanRPC)}
4.處理訊息:

在 game 模組中處理 Hello 訊息了。開啟 LeafServerExample game/internal/handler.go,敲入如下代碼:

package internalimport (    "server/msg"    "reflect"    "github.com/name5566/leaf/gate"    "github.com/name5566/leaf/log"    "github.com/golang/protobuf/proto")func init() {    // 向當前模組(game 模組)註冊 Hello 訊息的訊息處理函數 handleHello    handler(&msg.Hello{}, handleHello)}func handler(m interface{}, h interface{}) {    skeleton.RegisterChanRPC(reflect.TypeOf(m), h)}func handleHello(args []interface{}) {    // 收到的 Hello 訊息    m := args[0].(*msg.Hello)    // 訊息的寄件者    a := args[1].(gate.Agent)    // 輸出收到的訊息的內容    log.Debug("hello %v", m.GetName())    retBuf :=&msg.Hello{        Name: *proto.String("client"),    }    // 給寄件者回應一個 Hello 訊息    a.WriteMsg(retBuf)}

client接收和處理訊息:

擷取protobufjs,在LeafServerCocosClient目錄下:
npm install protobufjs

1.proto編譯成靜態檔案:

把msgPro.proto 複製到LeafServerCocosClient node_modules.bin檔案夾下,把proto檔案編譯成靜態檔案使用:

pbjs -t static-module -w commonjs -o protocol.js msgPro.protopbts -o protocol.d.ts protocol.js

把protocol.js 和protocol.d.ts拷貝到LeafServerCocosClient assets\script\protocol檔案夾中.

2.建立websocket並串連:

建立netControl類:

const {ccclass, property} = cc._decorator;//定義全域的變數import  * as onfire from "./libs/onfire/onfire.js"; //處理事件的類庫          import {netConfig} from './NetConfig'@ccclassexport class netControl extends cc.Component {    private _sock:WebSocket = null  //當前的webSocket的對象        connect(){        if(this._sock ==null || this._sock.readyState!==1){            //當前介面沒有開啟            //重新串連            this._sock = new WebSocket(netConfig.host+":"+netConfig.port)            this._sock.onopen = this._onOpen.bind(this);            this._sock.onclose = this._onClose.bind(this);            this._sock.onmessage = this._onMessage.bind(this);        }        return this;    }    _onOpen(){        onfire.fire("onopen")    }    _onClose(err){        onfire.fire("onclose",err)        let self = this        let reVar = setInterval(function(){            // 先對重連過後的Websocket進行判斷,如果重連成功則斷開迴圈            if(self._sock.readyState == 1){                clearInterval(reVar)            }            self._sock = new WebSocket(netConfig.host+":"+netConfig.port)        }, 5000)    //每5秒嘗試一次重連    }    _onMessage(obj){        onfire.fire("onmessage",obj)    }    send(msg){        if(this._sock.readyState == 1){            this._sock.send(msg);        }    }    protoBufAddtag(tag: number,buffer: Uint8Array){        let addtag_buffer=new Uint8Array(buffer.length+2)        let tagBinary = this.binary(tag,2)        addtag_buffer.set(tagBinary,0)        addtag_buffer.set(buffer.subarray(0,buffer.length),2)        return addtag_buffer    }    parseProtoBufId(obj,callback:Function){        let blob:Blob = obj.data        let reader = new FileReader();        reader.readAsArrayBuffer(blob);        reader.onload = function(e) {            let unit16 = new Uint16Array(e.target.result)            let id = unit16[0]            console.log("receive message id = "+id)            let dataUnit8Array = new Uint8Array(e.target.result)            dataUnit8Array = dataUnit8Array.slice(2)                        callback(id,dataUnit8Array)        }            }    binary (num:number, Bits:number) {        let resArry = []        let xresArry = []        let i=0;        for(;num>0;){            resArry.push(num % 2)            num=num/2            i++;        }        for(let j=i-1;j>=0;j--)            xresArry.push(resArry[j])        if (Bits < xresArry.length) {            console.log("位元小於二進位位元")        }              if (Bits) {            for(let r = xresArry.length; r < Bits; r++) {                xresArry.unshift(0)            }        }        //return xresArry.join().replace(/,/g, '');        return xresArry    }}

由於在 Leaf 中,預設的 Protobuf Processor 將一個完整的 Protobuf 訊息定義為如下格式:

-------------------------| id | protobuf message |-------------------------

所以在發送訊息時需要加上頭部id:

sendHello(name : string){     let protocolId = 0     let message = msg.Hello.create({ id:0,name:name })     let buffer  = msg.Hello.encode(message).finish()     //leaf 前兩位為協議序號,故需封裝一下     let addtag_buffer = this.netControl.protoBufAddtag(protocolId,buffer)     this.netControl.send(addtag_buffer);     console.log("sendToWS");}

接收到leaf返回的訊息時:

   onMessage(obj){        //leaf 前兩位為協議序號,需要解一下啊協議序號        this.netControl.parseProtoBufId(obj,this.OnGameMessage.bind(this))      }

同樣的前兩位是leaf自動加上的id,需要處理下:

    parseProtoBufId(obj,callback:Function){        let blob:Blob = obj.data        let reader = new FileReader();        reader.readAsArrayBuffer(blob);        reader.onload = function(e) {            let unit16 = new Uint16Array(e.target.result)            let id = unit16[0]            console.log("receive message id = "+id)            let dataUnit8Array = new Uint8Array(e.target.result)            dataUnit8Array = dataUnit8Array.slice(2)                        callback(id,dataUnit8Array)        }            }

具體Helloworld 類:

import {netControl} from "./NetControl"import  * as onfire from "./libs/onfire/onfire"import { msg } from "./protocol/protocol.js"const {ccclass, property} = cc._decorator@ccclassexport default class Helloworld extends cc.Component {    @property(cc.Label)    label: cc.Label = null;    @property    text: string = 'hello';    private msssageFire    private netControl:netControl = null    private proto    onLoad(){        this.netControl = new netControl()        }    start () {        // init logic        this.label.string = this.text;        this.netControl.connect();        this.msssageFire=onfire.on("onmessage",this.onMessage.bind(this))    }    OnBtnSendHello(){        this.sendHello("ddk")    }    sendHello(name : string){        let protocolId = 0        let message = msg.Hello.create({ id:0,name:name })        let buffer  = msg.Hello.encode(message).finish()        //leaf 前兩位為協議序號,故需封裝一下        let addtag_buffer = this.netControl.protoBufAddtag(protocolId,buffer)        this.netControl.send(addtag_buffer);        console.log("sendToWS");    }    onMessage(obj){        //leaf 前兩位為協議序號,需要解一下啊協議序號        this.netControl.parseProtoBufId(obj,this.OnGameMessage.bind(this))      }    OnGameMessage(id: number,data: Uint8Array){        if(id===0){            console.log("get Hello message!");            let gameMsg = msg.Hello.decode(data)            console.log(gameMsg)        }    }        onDestroy(){        onfire.un(this.msssageFire);        }}

:

server:
client:
goland build setting:

參考:

在 Leaf 中使用 Protobuf

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.