您的位置:首页 > 移动开发 > Cocos引擎

小蜗牛(摇一摇)诞生记四(cocos creator第一个项目)

2018-03-11 01:07 375 查看
现在已经进入开发第二天了,要解决的问题是与后端的通信。
后端采用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 (){
4000

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)); //nullcc.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){

bdf8
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;

上面中有些 重连,错误提示,超时提示等还没有测试调试完整!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: