分享
  1. 首页
  2. 文章

leaf 和cocos creator 游戏实战(一)使用protobuf完成通讯

simpleDis · · 3335 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

项目目的:

  • 开发一个交互性的小游戏,限于服务端经验较少,故开始学习leaf框架,客户端用cocos creator。
  • 网络上此类可学习案例较少,故想一边学习,一边分享给后学者,谨以此勉励自己!

环境搭建:

正文:

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 msg
import (
 "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 gate
import (
 "server/msg"
 "server/game"
)
func init() {
 // 这里指定消息 Hello 路由到 game 模块
 msg.Processor.SetRouter(&msg.Hello{}, game.ChanRPC)
}
4.处理消息:

在 game 模块中处理 Hello 消息了。打开 LeafServerExample game/internal/handler.go,敲入如下代码:

package internal
import (
 "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.proto
pbts -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'
@ccclass
export 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
@ccclass
export 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


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:simpleDis

查看原文:leaf 和cocos creator 游戏实战(一)使用protobuf完成通讯

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
3335 次点击
被以下专栏收入,发现更多相似内容
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏