摇一摇诞生记四(websocket通信构建)(cocos creator第一个项目)

现在已经进入开发第二天了,要解决的问题是与后端的通信。

后端采用php websocket 服务,websocket 是自己实现还是用第三方开源程序实现呢?与领导沟通后得知我们是使用的第三方的workerman 来作为websocket 服务。

手机端的三个场景,每一个都需要与后端socket服务通信。所以这就要求,封装的cocos客户端代码能方便的让三个场景共用。

刚开始 ,测试客户端socket功能,直接连接我们已有的sokcet服务显然不合适,因为我们的socket服务有很多逻辑,给他发送消息不确定他的响应方式,所以我从网上找到了一个免费的socket服务地址。他的功能很简单,就是客户单给他发送消息,他就返回什么信息,这对我们测试cocos的websocket封装 很方便,网络地址如下:

 

var ws = new WebSocket("ws://123.207.167.163:9010/ajaxchattest");

websocket的封装,参考是我们之前cocos2d-js封装的。来进行的改造。

WEB_SOCKET_SWF_LOCATION = "/swf/WebSocketMain.swf";
WEB_SOCKET_DEBUG = true;

var WebSocket = WebSocket || window.WebSocket || window.MozWebSocket;

var WebSocketManager = cc.Class.extend({
    _wsObj: null ,
    _wsReConnectTimes: 0 ,
    _reConnectMax: 3 ,
    _connectTimeout: 5 ,
    _reConnectFlag: false ,
    _msg: null ,
    _msgKey: null ,
    _msgSendStatus: 'nothing' ,
    _msgTimeout: 5 ,
    _msgTimeoutTimes: 0 ,
    _msgGet: '' ,
    _target: null ,
    _callback: null ,
    
    ctor: function () {

    },

    // 打开连接
    openConnect: function () {
        if ( this ._wsObj){
            this ._wsObj.close();
            return ;
        }

        this ._wsObj = null ;
        var self = this ;
        
        this.host = ws_server;
        this ._wsObj = new WebSocket(this.host);

        //连接服务器
        this ._wsObj.onopen = function (evt) {
            self.openGet(evt);
        };
        //接收到消息
        this ._wsObj.onmessage = function (evt) {
            self.messageGet(evt);
        };
        //错误信息
        this ._wsObj.onerror = function (evt) {
            self.errorGet(evt);
        };

        this ._wsObj.onclose = function (evt) {
            self.closeGet(evt);
        };

    },

    // 连接超时判断

    connectTimeoutCheck: function (){
        if ( this ._wsObj && this ._wsObj.readyState == WebSocket.CONNECTING){
            // 重连次数
            if ( this ._wsReConnectTimes > this ._reConnectMax){
                // 重试过多后,应该提示玩家目前网络不稳定
                GY_ti_shi_popup.getInstance().show(L( 'gy:ws_wang_luo_bu_wen' ));
            } else {
                this ._wsReConnectTimes++;
                GY_ti_shi_popup.getInstance().show(L( 'gy:ws_timeout' ), 'ws_connect_timeout' );
            }
        } else {
            this .connectTimeoutHandle();
        }

    },

    // 超时后 重新连接
    connectTimeoutHandle: function (){
        // 重新打开连接
        this .closeConnect();
    },

    // 关闭连接
    closeConnect: function () {
        cc.log( "WS CLOSING." );
        if ( this ._wsObj){
            this ._wsObj.close();
        }

    },

    // 连接后处理

    openGet: function (evt) {
       //连接后发送用户信息
        //var login_data = '{"game_name":"car","type":"login"}';

        var login_data = '{"game_name":"car","type":"login","client_name":"'
            +wxNickname+'","open_ID":"'+wxOpneid+'","client_image":"'+wxHeadimgurl+'","game_id":"'+gameId+'","room_id":"'+roomId+'"}';
        //var login_data = '{"game_name":"car","type":"login","client_name":"'
        //    +12124123+'","open_ID":"'+234234+'","client_image":"'+23+'","room_id":"10"}';
        this._wsObj.send(login_data);



    },

    // 获得消息

    messageGet: function (evt) {

        var m_data = eval("("+evt.data+")");
        //console.log(m_data);

        cc.director.getRunningScene().MessageGet(evt);
        switch(m_data['type']){
            // 服务端ping客户端
            case 'ping':

                //cc.director.getRunningScene().MessageGet(evt);
                //this.sendGet('{"game_name":"car","type":"pong"}');
                break;
            //
            case 'login':

                break;
            //
            case 'say':

                break;
            //
            case 'logout':
               break;
        }

    },

    // 获取错误
    errorGet: function (evt) {
        cc.log( "WS Error" );
        this .closeConnect();
    },

    // 连接关闭处理
    closeGet: function (evt) {
        cc.log( "websocket instance closed." );
        this ._wsObj = null ;
        // 连接关闭马上进行重试
        this .openConnect();
    },

    /**
     * 给服务器发送消息
     * @param act
     * @param params
     * @param callback
     * @param target
     */
    //发送数据
    sendGet: function (str) {

        // 判断当前连接
        if ( this .isOpen()) {
            this .sendRequest(str);
        }
        else {
            this .openConnect();
        }


    },

    // 发送消息
    sendRequest: function (str) {

        this ._wsObj.send(str);
       // this ._msgSendStatus = 'msgSend' ;
        // 设置超时时间
        //director.getScheduler().scheduleCallbackForTarget( this , this .sendTimeoutCheck, 0 , 0 , this ._msgTimeout);

    },

    // 消息被响应了

    requestResponse: function (resObj) {
        // 获得响应的消息后,去掉 loading 遮罩
        director.getScheduler().unscheduleCallbackForTarget( this , this .sendTimeoutCheck);
        this ._msg = null ;
        this ._msgSendStatus = 'nothing' ;
        GY_loading_popup.getInstance().hide();
        this ._callback.call( this ._target, resObj._body);
    },

    // 发送消息超时判断

    sendTimeoutCheck: function (){
        if ( this ._msgSendStatus == 'msgSend' ){
            // 消息没有被响应,去掉 loading 遮罩
            GY_loading_popup.getInstance().hide();
            GY_ti_shi_popup.getInstance().show(L( 'gy:ws_timeout' ), 'ws_timeout' );
        }
    },

    // 超时后

    sendTimeoutHandle: function (){
        var act = 'gc/jiao_se/deng_lu' ;
        var param = {};
        param.gc_token = LS.getItem( 'gc_token' );
        param.id_yong_hu = LS.getItem( 'id_yong_hu' );
        param.zhouqi = LS.getItem( 'uc_zhouqi' );
        HttpManager.create().sendGetRequest(act, param, this .callbackTimeoutHandle, this );

    },

    // 超时消息处理
    callbackTimeoutHandle: function (resObj){
        if (resObj.st_code == 1 ) {
            if (G.js_jiao_se.zt_jiao_se == 1 ) {
                SM.goto_page( 'DL_chuang_ming_page' );
            } else if (G.js_jiao_se.zt_jiao_se == 2 ) {
                SM.goto_page( 'YD_yin_dao_' + G.js_jiao_se.xin_shou_jin_du + '_page' );
            } else if (G.js_jiao_se.zt_jiao_se == 3 ) {
                //SM.goto_page('SY_shou_ye_page');
                // 试试看直接刷新页面的效果吧
                SM.flush_page();
            }
        }
    },

    // 判断 ws 是否已经连接
    isOpen: function (){
      return ( this ._wsObj && this ._wsObj.readyState == WebSocket.OPEN);
    },

    purge: function () {
        NC.removeObserver( this , 'ws_timeout' );
        NC.removeObserver( this , 'ws_connect_timeout' );
        this .closeConnect();
        this ._instance = null ;
    }
});

WebSocketManager._instance = null ;

WebSocketManager.getInstance = function () {
    if (! this ._instance) {
        this ._instance = new WebSocketManager();
    }
    return this ._instance;

};

直接放在 cocos creator 中发现报错 大概意思就是 没有cc.Class.extend 。所以 我改为cc.class({.....})

在 场景中需要 require('webSocketManager) 就可以了。现在也能发送消息和接受消息了。

但是新的问题来了。收到的消息 怎么和场景联系起来呢?

原来的cocos2d-js 中关键代码是 cc.director.getRunningScene().MessageGet(evt);

但是发现报错MessageGet 为定义。怎么办?

 

// cc.log(cc.director.getScene().getName()); //waiting
// cc.log(cc.director.getScene().x); //0
// cc.log(cc.director.getScene().color); //object
// cc.log(cc.director.getScene().opacity); //255
// cc.log(cc.director.getScene().getChildByName('Canvas')); //waiting
// cc.log(cc.director.getScene().getChildByName('Canvas').getComponent(cc.Sprite)); //null

 

cc.log(cc.director.getScene().getName());
var scriptName = cc.director.getScene().getName();  //一会构建报错一会不报错??!
console.log('scriptName:'+scriptName);
var curScript = require(scriptName);
cc.log(curScript);
curScript.messageGet(evt);

require 这种方式还是受到领导的提示。 这种方式还要求 场景脚本里边 也要module.exports,  总感觉怪怪的。

还有一个缺点: 就是要求场景的名称 和 脚步名称 相同 或者能方便一一对应起来。

百度查询也发现 可以用事件来 做,百度出来的代码不尽如意,还是看看官网手册,有没有能帮助到的。

手册 脚本开发指南--> 发射和监听事件

 

cc.director.getScene().getChildByName('Canvas').emit('messageScene', {  //构建一会报错一会不报错??!!
    msg: evt.data
});

场景脚本中相应的代码如下:

 

onEnable: function () {
    this.node.on('messageScene', this.messageGet);
},

onDisable: function () {
    this.node.off('messageScene', this.messageGet);
},
 
//收到消息后的处理
messageGet: function (evt) {
    //var m_data = JSON.parse(evt.data);
    var m_data = JSON.parse(evt.detail.msg);

    if( m_data.type == 'gameTime') {  //'playSeconds'  //如果是是游戏剩余时间<= 0 gameSec <= 0 (单位秒)
        //切换到ranking场景
        if(m_data.time <= 0){

            cc.log('in game loadScene.');
            //  清除定时器
            clearInterval(inteval);
            cc.director.getScene().getChildByName('Canvas').getComponent("game").unscheduleAllCallbacks();
            cc.director.loadScene("ranking");
        }
    } else if(m_data.type == 'scoreAdd') {  //以前叫 sendTimingRanking

        var rankNode = cc.director.getScene().getChildByName('Canvas').getComponent('game');
        rankNode.unscheduleAllCallbacks();
        //渲染分数和排名
        rankNode.rankingDisplay.string = m_data.score;  //不要惊讶,他就是排名
    }
},

到这里似乎,通信问题解决了。

当前和require方式 有个相似的弊端,就是场景脚本要挂载到Canvas 节点上,才能方便做事件分发。

当前晚上我就想打包下,看看效果,结果 总是报错 messageGet未定义之类的,一开始我认为可能是用cc.Class 原因,于是 把封装改成普通javaScript类的封装。结果发现还是会报错,有时能打包成功有时不能。又过了一两天我才发现真正的规律是,再打包的时候把socket服务停止,就能一遍过,原因是啥,真的说不上来。

还有一种尝试封装就是我把websocket 封装成cc.class类,让每个场景脚本来继承,但是有最大的问题,每个场景socket就要重新建立连接,显然不可取。

最后 我把socket所在的文件 作为插件(手册有说明,插件加载比场景脚本要早),插件的里边都是默认全局的webSocketManager 对象也是全局的,所以场景脚本不需要require. 不作为插件,作为模块组件module.exports 出来也是可以的。

最后如下:

//下面这些变量 构建后 移到 index.html中;
window.roomId = '991';  //"<?php echo $room_id;?>";
window.gameId = '375';  //"<?php echo $game_id;?>";
window.codeSign = '';   //"<?php echo $codeSign;?>";  $this->encrypt($game_id . "_" . $room_id . "_" . $business_id . "_web"."_".$way);
window.ws_server = 'ws://192.168.3.29:7272';  //"<?php echo YG_SOCKET_URL;?>";
//ws://123.56.234.46:7272  游记测试socket
window.code_url = 'http://res.funchang.com/aHkJHdXrXNssCRYzNJ.png';


//一下是websocket 功能


// var WEB_SOCKET_SWF_LOCATION = "/swf/WebSocketMain.swf";
// var WEB_SOCKET_DEBUG = true;

//var ws_server = 'ws://123.207.167.163:9010/ajaxchattest';
//var ws_server = 'ws://192.168.29.147:7272';

window.WebSocket = WebSocket || window.WebSocket || window.MozWebSocket;


function WebSocketCtor() {

    this._wsObj = null;
    this._wsReConnectTimes = 0;
    this._reConnectMax = 3;
    this._connectTimeout = 5;
    this._reConnectFlag =  false;
    this._msg =  null;
    this._msgKey = null;
    this._msgSendStatus =  'nothing';
    this._msgTimeout = 5;
    this._msgTimeoutTimes = 0;
    this._msgGet = '';
    this._target = null;
    this._callback = null;


    // 打开连接
    //openConnect: function () {
    this.ctor = function () {
        console.log('jjjjjjj');
        this.openConnect();
        console.log('kkkk');



    };

    this.openConnect = function () {
        if ( this ._wsObj){
            this ._wsObj.close();
            return ;
        }

        this ._wsObj = null ;
        var self = this ;

        this.host = ws_server;
        this ._wsObj = new WebSocket(this.host);

        //连接服务器
        this ._wsObj.onopen = function (evt) {
            self.openGet(evt);
        };
        //接收到消息
        this ._wsObj.onmessage = function (evt) {
            self.messageGet(evt);
        };
        //错误信息
        this ._wsObj.onerror = function (evt) {
            self.errorGet(evt);
        };

        this ._wsObj.onclose = function (evt) {
            self.closeGet(evt);
        };
    },

        // 连接超时判断

        this.connectTimeoutCheck = function (){
            if ( this ._wsObj && this ._wsObj.readyState == WebSocket.CONNECTING){
                // 重连次数
                if ( this ._wsReConnectTimes > this ._reConnectMax){
                    // 重试过多后,应该提示玩家目前网络不稳定
                    GY_ti_shi_popup.getInstance().show(L( 'gy:ws_wang_luo_bu_wen' ));
                } else {
                    this ._wsReConnectTimes++;
                    GY_ti_shi_popup.getInstance().show(L( 'gy:ws_timeout' ), 'ws_connect_timeout' );
                }
            } else {
                this .connectTimeoutHandle();
            }

        };

    // 超时后 重新连接
    this.connectTimeoutHandle = function (){
        // 重新打开连接
        this .closeConnect();
    };

    // 关闭连接
    this.closeConnect = function () {
        cc.log( "WS CLOSING." );
        if ( this ._wsObj){
            this ._wsObj.close();
        }

    };

    // 连接后处理

    this.openGet = function (evt) {

        //连接后发送用户信息
        //注意房间ID,游戏ID是变量
        var login_data = {game_name:'shake',type : 'screen_login', game_id:gameId, room_id : roomId}
        this._wsObj.send(JSON.stringify(login_data));

        //如果是第一次连接 会返回: {"type":"screen_login","data":"success","time":"2018-02-28 17:45:30"}


    };

    // 获得消息

    this.messageGet = function (evt) {


        var m_data = eval("("+evt.data+")");
        cc.log('big scene get message:');
        if(m_data.type == 'ping'){

        }else{
            //cc.log(evt.data);
        }


        // if(m_data.type == 'ping'){
        //     var data = {game_name:'shake',type:'pong'};
        //     this._wsObj.send(JSON.stringify(data));
        //     return true;
        // }

        cc.director.getScene().getChildByName('Canvas').emit('messageScene', {  //构建一会报错一会不报错??!!
            msg: evt.data
        });
        


    };

    // 获取错误
    this.errorGet = function (evt) {
        cc.log( "WS Error" );
        this .closeConnect();
    };

    // 连接关闭处理
    this.closeGet = function (evt) {
        cc.log( "websocket instance closed." );
        this ._wsObj = null ;
        // 连接关闭马上进行重试
        this .openConnect();
    };

    /**
     * 给服务器发送消息
     * @param act
     * @param params
     * @param callback
     * @param target
     */
    //发送数据
    this.sendGet = function (str) {

        // 判断当前连接
        if ( this .isOpen()) {
            this .sendRequest(str);
        }
        else {
            this .openConnect();
        }


    };

    // 发送消息
    this.sendRequest = function (str) {

        this ._wsObj.send(str);
        // this ._msgSendStatus = 'msgSend' ;
        // 设置超时时间
        //director.getScheduler().scheduleCallbackForTarget( this , this .sendTimeoutCheck, 0 , 0 , this ._msgTimeout);

    };

    // 消息被响应了

    this.requestResponse = function (resObj) {
        // 获得响应的消息后,去掉 loading 遮罩
        director.getScheduler().unscheduleCallbackForTarget( this , this .sendTimeoutCheck);
        this ._msg = null ;
        this ._msgSendStatus = 'nothing' ;
        GY_loading_popup.getInstance().hide();
        this ._callback.call( this ._target, resObj._body);
    };

    // 发送消息超时判断

    this.sendTimeoutCheck = function (){
        if ( this ._msgSendStatus == 'msgSend' ){
            // 消息没有被响应,去掉 loading 遮罩
            GY_loading_popup.getInstance().hide();
            GY_ti_shi_popup.getInstance().show(L( 'gy:ws_timeout' ), 'ws_timeout' );
        }
    };

    // 超时后

    this.sendTimeoutHandle = function (){
        var act = 'gc/jiao_se/deng_lu' ;
        var param = {};
        param.gc_token = LS.getItem( 'gc_token' );
        param.id_yong_hu = LS.getItem( 'id_yong_hu' );
        param.zhouqi = LS.getItem( 'uc_zhouqi' );
        HttpManager.create().sendGetRequest(act, param, this .callbackTimeoutHandle, this );

    };

    // 超时消息处理
    this.callbackTimeoutHandle = function (resObj){
        if (resObj.st_code == 1 ) {
            if (G.js_jiao_se.zt_jiao_se == 1 ) {
                SM.goto_page( 'DL_chuang_ming_page' );
            } else if (G.js_jiao_se.zt_jiao_se == 2 ) {
                SM.goto_page( 'YD_yin_dao_' + G.js_jiao_se.xin_shou_jin_du + '_page' );
            } else if (G.js_jiao_se.zt_jiao_se == 3 ) {
                //SM.goto_page('SY_shou_ye_page');
                // 试试看直接刷新页面的效果吧
                SM.flush_page();
            }
        }
    };

    // 判断 ws 是否已经连接
    this.isOpen = function (){
        return ( this ._wsObj && this ._wsObj.readyState == WebSocket.OPEN);
    };

    this.purge =  function () {
        NC.removeObserver( this , 'ws_timeout' );
        NC.removeObserver( this , 'ws_connect_timeout' );
        this .closeConnect();
        this ._instance = null ;
    }
};

// WebSocketManager._instance = null ;
//
// WebSocketManager.getInstance = function () {
//     if (! this ._instance) {
//         this ._instance = new WebSocketManager();
//     }
//     return this ._instance;
//
// };

//module.exports = WebSocketManager;

window.WebSocketManager = new WebSocketCtor();
WebSocketManager.openConnect();  //初始化原始ws

//module.exports = obj;

 

上面中有些 重连,错误提示,超时提示等还没有测试调试完整!

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论

打赏作者

学海无涯书山有路

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值