zoukankan      html  css  js  c++  java
  • 【微信小游戏】微信对战小游戏知识储备

    一、前提

    在微信小游戏异常火爆的前提下,开发个小游戏才是正事,而不是玩个小游戏才是正事!

    废话不多说,步入今天的正题,在慢慢成熟起来的小游戏生态中我们的小游戏如果只是单机+排行的组合,难免显得小游戏单调,乏味今天我们就来尝试下联网操作。

    二、准备

    工具: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

  • 相关阅读:
    [置顶] java 通过classloader加载类再通过classforname实例化
    Linux内核源代码解析——用户发送数据包的起源之sendto
    POJ 2774 Long Long Message&&HDU 1403 Longest Common Substring&&COJ 1203
    add-two-numbers-ii
    【转载】React初学者入门须知
    【Todo】【转载】ES6的学习记录
    【转载】Java中如何写一段内存泄露的程序 & ThreadLocal 介绍和使用
    【Todo】深入理解Javascript系列
    【转载】什么是优秀技术团队
    【转载】React入门-Todolist制作学习
  • 原文地址:https://www.cnblogs.com/zhangdw/p/9183245.html
Copyright © 2011-2022 走看看