【微信小游戏】微信对战小游戏知识储备
一、前提
在微信小游戏异常火爆的前提下,开发个小游戏才是正事,而不是玩个小游戏才是正事!
废话不多说,步入今天的正题,在慢慢成熟起来的小游戏生态中我们的小游戏如果只是单机+排行的组合,难免显得小游戏单调,乏味。今天我们就来尝试下联网操作。
二、准备
工具:cocos creator
版本:v1.9.1
语言:JavaScript,开源库onfire.js
介绍:我们主要通过WebSocket来实现客户端跟服务器的交互,服务器用Node.js,技术自己选,按照自己擅长的语言。
三、实战
客户端
1、新建场景Login,场景中包含三个按钮,两个文本。按钮分别是建立连接、发送数据,关闭连接。文本分别是显示发送数据和接收数据。绑定事件,绑定脚本就不再多说了。
Login.js代码如下:
cc.Class({ extends: cc.Component, properties: { lbl_sendMsg: { default: null, type: cc.Label, tooltip: "发送的数据" }, lbl_responseMsg: { default: null, type: cc.Label, tooltip: "接收的数据" }, }, start () { this.netControl = require('NetControl'); }, // 打开连接 onOpenSocket(){ console.log("连接完成"); }, // 接收服务器返回的数据 onMessage(obj){ console.log("It's HelloWorld onMessage----->"+ obj.data ); this.lbl_responseMsg.string = obj.data; var responseData = JSON.parse(obj.data); console.log("消息协议号:"+responseData.MsgId); }, // 关闭 WebSocket 连接 onCloseSocket(){ console.log("关闭连接" + new Date().getTime()); }, // 销毁事件注册 onDestroy(){ onfire.un(this.openSocket); onfire.un(this.msssageFire); onfire.un(this.closeSocket); }, btnSocketOpen(){ console.log("开始连接"); this.netControl.connect(); this.openSocket = onfire.on("onopen",this.onOpenSocket.bind(this)); }, btnSocketSend(){ // console.log("socket send!!! "); this.msssageFire = onfire.on("onmessage",this.onMessage.bind(this)); var jsonTmp = "{ \"MsgId\": 1001, \"Name\": \" + \"知心购物\" + \", \"QQGroup\": \"" + 418177552 + "\" }"; this.netControl.send(jsonTmp); //发送的数据 this.lbl_sendMsg.string = jsonTmp; }, btnSocketClose(){ this.closeSocket = onfire.on("onclose",this.onCloseSocket.bind(this)); //关闭:包含主动关闭连接和服务器关闭连接 this.netControl.close(); }, // update (dt) {}, });
2、NetConfig.js代码如下
/** * 当前的网络配置 */ module.exports={ host:"ws://localhost", port:3000 };
3、NetControl.js代码如下
//定义全局的变量 window.onfire = require("onfire"); //处理事件的类库 var netConfig = require('NetConfig'); var NetControl = { _sock:{}, //当前的webSocket的对象 connect: function () { if(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; }, // 关闭连接 close: function(){ if (this._sock.readyState ===1) { this._sock.close(); } }, _onOpen:function(){ onfire.fire("onopen"); }, _onClose:function(err){ onfire.fire("onclose",err); }, _onMessage:function(obj){ onfire.fire("onmessage",obj); }, send:function(msg){ this._sock.send(msg); console.log("send msg"+msg); }, }; module.exports=NetControl;
4、onfire.js代码如下
/** * Created by Administrator on 2018/4/17 0017. */ /** Copyright (c) 2016 hustcc http://www.atool.org/ License: MIT https://github.com/hustcc/onfire.js **/ /* jshint expr: true */ !function (root, factory) { if (typeof module === 'object' && module.exports) module.exports = factory(); else root.onfire = factory(); }(typeof window !== 'undefined' ? window : this, function () { var __onfireEvents = {}, __cnt = 0, // evnet counter string_str = 'string', function_str = 'function', hasOwnKey = Function.call.bind(Object.hasOwnProperty), slice = Function.call.bind(Array.prototype.slice); function _bind(eventName, callback, is_one, context) { if (typeof eventName !== string_str || typeof callback !== function_str) { throw new Error('args: '+string_str+', '+function_str+''); } if (! hasOwnKey(__onfireEvents, eventName)) { __onfireEvents[eventName] = {}; } __onfireEvents[eventName][++__cnt] = [callback, is_one, context]; return [eventName, __cnt]; } function _each(obj, callback) { for (var key in obj) { if (hasOwnKey(obj, key)) callback(key, obj[key]); } } /** * onfire.on( event, func, context ) -> Object * - event (String): The event name to subscribe / bind to * - func (Function): The function to call when a new event is published / triggered * Bind / subscribe the event name, and the callback function when event is triggered, will return an event Object **/ function on(eventName, callback, context) { return _bind(eventName, callback, 0, context); } /** * onfire.one( event, func, context ) -> Object * - event (String): The event name to subscribe / bind to * - func (Function): The function to call when a new event is published / triggered * Bind / subscribe the event name, and the callback function when event is triggered only once(can be triggered for one time), will return an event Object **/ function one(eventName, callback, context) { return _bind(eventName, callback, 1, context); } function _fire_func(eventName, args) { if (hasOwnKey(__onfireEvents, eventName)) { _each(__onfireEvents[eventName], function(key, item) { item[0].apply(item[2], args); // do the function if (item[1]) delete __onfireEvents[eventName][key]; // when is one, delete it after triggle }); } } /** * onfire.fire( event[, data1 [,data2] ... ] ) * - event (String): The event name to publish * - data...: The data to pass to subscribers / callbacks * Async Publishes / fires the the event, passing the data to it's subscribers / callbacks **/ function fire(eventName) { // fire events var args = slice(arguments, 1); setTimeout(function () { _fire_func(eventName, args); }); } /** * onfire.fireSync( event[, data1 [,data2] ... ] ) * - event (String): The event name to publish * - data...: The data to pass to subscribers / callbacks * Sync Publishes / fires the the event, passing the data to it's subscribers / callbacks **/ function fireSync(eventName) { _fire_func(eventName, slice(arguments, 1)); } /** * onfire.un( event ) -> Boolean * - event (String / Object): The message to publish * When passed a event Object, removes a specific subscription. * When passed event name String, removes all subscriptions for that event name(hierarchy) * * Unsubscribe / unbind an event or event object. * * Examples * * // Example 1 - unsubscribing with a event object * var event_object = onfire.on('my_event', myFunc); * onfire.un(event_object); * * // Example 2 - unsubscribing with a event name string * onfire.un('my_event'); **/ function un(event) { var eventName, key, r = false, type = typeof event; if (type === string_str) { // cancel the event name if exist if (hasOwnKey(__onfireEvents, event)) { delete __onfireEvents[event]; return true; } return false; } else if (type === 'object') { eventName = event[0]; key = event[1]; if (hasOwnKey(__onfireEvents, eventName) && hasOwnKey(__onfireEvents[eventName], key)) { delete __onfireEvents[eventName][key]; return true; } // can not find this event, return false return false; } else if (type === function_str) { _each(__onfireEvents, function(key_1, item_1) { _each(item_1, function(key_2, item_2) { if (item_2[0] === event) { delete __onfireEvents[key_1][key_2]; r = true; } }); }); return r; } return true; } /** * onfire.clear() * Clears all subscriptions **/ function clear() { __onfireEvents = {}; } return { on: on, one: one, un: un, fire: fire, fireSync: fireSync, clear: clear }; });
服务器
1、app.js代码如下
var WebSocketServer = require('ws').Server, wss = new WebSocketServer({ port: 3000 }); wss.on('connection', function (ws) { console.log('client connected'); ws.on('message', function (message) { console.log("接受消息"); console.log(`[SERVER] Received: ${message}`); // ws.send(`ECHO: ${message}`, (err) => { ws.send(`{"MsgId":1001, "Name":"微信搜索知心购物小程序"}`, (err) => { if (err) { console.log(`[SERVER] error: ${err}`); } }); }); });
2、package.json
"dependencies": { "websocket": "^1.0.26", "ws": "1.1.1" }
3、通过npm install 安装依赖,通过 node app.js 开启服务器
四、效果
1、建立连接:
服务器:服务器执行打印,输出client connected!
客户端:客户端连接成功后,执行回调this.openSocket注册的函数,进打印操作。
2、发送数据:
服务器:服务器打印收到的数据。
客户端:客户端显示服务器返回的数据。
3、关闭连接:
客户端:点击关闭连接后,执行我们的回调,打印关闭连接; 此时如果再次点击发送数据,则会报 not open 错误
至此,整个的网络流程已完成。
五、思考
1、WebSocket最基本的网络连接,网络请求,网络关闭。
2、应用到游戏中远不止这些可以满足,至少有心跳机制,断线重连机制;
3、玩家之间如何随机匹配对战,好友之间如何1V1匹配对战。
4、WebSocket中不使用Json数据,而使用Protobuf数据。
5、更多问题,欢迎加群讨论学习,QQ群:418177552