达达麻将客户端初始化流程

达达麻将版图

客户端代码结构

1: scripts文件夹下:

(1) 3rdparty: 第三方代码 socket-io;

(2) Comonents: 游戏中挂到节点上的组件;

(3)全局对象:在代码的根目录下;

loading场景

1: Loading Scene 挂载了脚本: LoadingLogic.js

2: 加载场景初始化过程:

(1): 初始化全局的管理对象,全部记录到 cc.vv这个表里面, 特点: cc.vv.userMgr = new UserMgr() 对象实例是小写开头,代码是大写开头,全局唯一只有一个;      initMgr: UserMgr, ReplayMgr, HTTP, Global, Net, GameNetMgr, AnysdkMgr, VoiceMgr, AudioMgr, Utils,  解析url的参数,来决定不同的用户账号

(2)显示几秒的开机画面;

showSplash:function(callback){

(3)检查更新;

this.getServerInfo();

(4)startPreloading: 预加载资源 resources/textures;

(5)加载完成后,进入”login”场景;

注意:官方开源的最新版本,和泄露版本达达麻将(早期版本)相比是有做升级更新的。如下图:1是最新开源,2是早期版本。

在1中:打开游戏,第一个UI界面是start:绑定的脚本是AppStart.js

在2中:打开游戏,第一个UI界面是loading;绑定的JS脚本是LoadingLogic.js

//------------AppStart.js------------function urlParse(){var params = {};if(window.location == null){return params;}var name,value; var str=window.location.href; //取得整个地址栏var num=str.indexOf("?") str=str.substr(num+1); //取得所有参数   stringvar.substr(start [, length ]var arr=str.split("&"); //各个参数放到数组里for(var i=0;i < arr.length;i++){ num=arr[i].indexOf("="); if(num>0){ name=arr[i].substring(0,num);value=arr[i].substr(num+1);params[name]=value;} }return params;
}function initMgr(){cc.vv = {};var UserMgr = require("UserMgr");cc.vv.userMgr = new UserMgr();var ReplayMgr = require("ReplayMgr");cc.vv.replayMgr = new ReplayMgr();cc.vv.http = require("HTTP");cc.vv.global = require("Global");cc.vv.net = require("Net");var GameNetMgr = require("GameNetMgr");cc.vv.gameNetMgr = new GameNetMgr();cc.vv.gameNetMgr.initHandlers();var AnysdkMgr = require("AnysdkMgr");cc.vv.anysdkMgr = new AnysdkMgr();cc.vv.anysdkMgr.init();var VoiceMgr = require("VoiceMgr");cc.vv.voiceMgr = new VoiceMgr();cc.vv.voiceMgr.init();var AudioMgr = require("AudioMgr");cc.vv.audioMgr = new AudioMgr();cc.vv.audioMgr.init();var Utils = require("Utils");cc.vv.utils = new Utils();//var MJUtil = require("MJUtil");//cc.vv.mjutil = new MJUtil();cc.args = urlParse();
}cc.Class({extends: cc.Component,properties: {// foo: {//    default: null,      // The default value will be used only when the component attaching//                           to a node for the first time//    url: cc.Texture2D,  // optional, default is typeof default//    serializable: true, // optional, default is true//    visible: true,      // optional, default is true//    displayName: 'Foo', // optional//    readonly: false,    // optional, default is false// },// ...label: {default: null,type:cc.Label},loadingProgess:cc.Label,},// use this for initializationonLoad: function () {initMgr();cc.vv.utils.setFitSreenMode();console.log('haha'); this._mainScene = 'loading';this.showSplash(function(){this.getServerInfo();}.bind(this));},onBtnDownloadClicked:function(){cc.sys.openURL(cc.vv.SI.appweb);},showSplash:function(callback){var self = this;var SHOW_TIME = 3000;var FADE_TIME = 500;this._splash = cc.find("Canvas/splash");if(true || cc.sys.os != cc.sys.OS_IOS || !cc.sys.isNative){this._splash.active = true;if(this._splash.getComponent(cc.Sprite).spriteFrame == null){callback();return;}var t = Date.now();var fn = function(){var dt = Date.now() - t;if(dt < SHOW_TIME){setTimeout(fn,33);}else {var op = (1 - ((dt - SHOW_TIME) / FADE_TIME)) * 255;if(op < 0){self._splash.opacity = 0;callback();   }else{self._splash.opacity = op;setTimeout(fn,33);   }}};setTimeout(fn,33);}else{this._splash.active = false;callback();}},getServerInfo:function(){var self = this;var onGetVersion = function(ret){cc.vv.SI = ret;if(cc.sys.isNative){var url = cc.url.raw('resources/ver/cv.txt');cc.loader.load(url,function(err,data){cc.VERSION = data;if(ret.version == null){console.log("error.");}else{if(cc.vv.SI.version != cc.VERSION){cc.find("Canvas/alert").active = true;}else{cc.director.loadScene(self._mainScene);}}}.bind(this));}else{cc.director.loadScene(self._mainScene);}};var xhr = null;var complete = false;var fnRequest = function(){self.loadingProgess.string = "正在连接服务器";xhr = cc.vv.http.sendRequest("/get_serverinfo",null,function(ret){xhr = null;complete = true;onGetVersion(ret);});setTimeout(fn,5000);            }var fn = function(){if(!complete){if(xhr){xhr.abort();self.loadingProgess.string = "连接失败,即将重试";setTimeout(function(){fnRequest();},5000);}else{fnRequest();}}};fn();},log:function(content){this.label.string += content + '\n';},
});//--------------------------LoadingLogic------------------------
cc.Class({extends: cc.Component,properties: {tipLabel:cc.Label,_stateStr:'',_progress:0.0,_splash:null,_isLoading:false,},// use this for initializationonLoad: function () {cc.vv.utils.setFitSreenMode();this.tipLabel.string = this._stateStr;this.startPreloading();},startPreloading:function(){this._stateStr = "正在加载资源,请稍候"this._isLoading = true;var self = this;var onProgress = function ( completedCount, totalCount,  item ){//console.log("completedCount:" + completedCount + ",totalCount:" + totalCount );if(self._isLoading){self._progress = completedCount/totalCount;}};//cc.loader.loadResDir("textures",cc.Texture2D, onProgress,function (err, assets) {//    self.onLoadComplete();//});self.onLoadComplete();      },onLoadComplete:function(){this._isLoading = false;this._stateStr = "准备登陆";cc.director.loadScene("login");},// called every frame, uncomment this function to activate update callbackupdate: function (dt) {if(this._stateStr.length == 0){return;}this.tipLabel.string = this._stateStr + ' ';if(this._isLoading){this.tipLabel.string += Math.floor(this._progress * 100) + "%";   }else{var t = Math.floor(Date.now() / 1000) % 4;for(var i = 0; i < t; ++ i){this.tipLabel.string += '.';}            }}
});

Login场景

1: login场景挂载了login.js脚本;

(1)扩展了String对象.format()函数;

String.prototype.format = function(args) { if (arguments.length>0) { var result = this; if (arguments.length == 1 && typeof (args) == "object") { for (var key in args) { var reg=new RegExp ("({"+key+"})","g"); result = result.replace(reg, args[key]); } } else { for (var i = 0; i < arguments.length; i++) { if(arguments[i]==undefined) { return ""; } else { var reg=new RegExp ("({["+i+"]})","g"); result = result.replace(reg, arguments[i]); } } } return result; } else { return this; }
};

(2)监听:push_need_create_role, 进入创建角色创景;

(3)如果不是网页,那么隐藏游客登陆按钮;

(4)如果保存了微信账号在本地直接自动登陆;

(5)微信账号登陆响应;

(6)游客账号登陆;

无account则从本地获取account;本地没有获取到则通过时间来随机一个;

然后通过http将account发给服务器,消息回调处理函数是onAuth。

cc.vv.http.sendRequest("/guest",{account:account},this.onAuth);


var URL = "http://127.0.0.1:9000";exports.master_url = null;
exports.url = null;
exports.token = null;init();function init() {exports.master_url = URL;exports.url = URL;
}function setURL(url) {URL = url;init();
};function sendRequest(path, data, handler, extraUrl) {var xhr = cc.loader.getXMLHttpRequest();xhr.timeout = 5000;if (data == null) {data = {};}if (exports.token) {data.token = exports.token;}if (extraUrl == null) {extraUrl = exports.url;}//解析请求路由以及格式化请求参数var sendpath = path;var sendtext = '?';for (var k in data) {if (sendtext != "?") {sendtext += "&";}sendtext += (k + "=" + data[k]);}//组装完整的URLvar requestURL = extraUrl + sendpath + encodeURI(sendtext);//发送请求console.log("RequestURL:" + requestURL);xhr.open("GET", requestURL, true);if (cc.sys.isNative) {xhr.setRequestHeader("Accept-Encoding", "gzip,deflate", "text/html;charset=UTF-8");}var timer = setTimeout(function() {xhr.hasRetried = true;xhr.abort();console.log('http timeout');retryFunc();}, 5000);var retryFunc = function() {sendRequest(path, data, handler, extraUrl);};xhr.onreadystatechange = function () {console.log("onreadystatechange");clearTimeout(timer);if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)) {// console.log("http res(" + xhr.responseText.length + "):" + xhr.responseText);cc.log("request from [" + xhr.responseURL + "] data [", ret, "]");var respText = xhr.responseText;var ret = null;try {ret = JSON.parse(respText);} catch (e) {console.log("err:" + e);ret = {errcode: -10001,errmsg: e};}if (handler) {handler(ret);}handler = null;}else if (xhr.readyState === 4) {if(xhr.hasRetried){return;}console.log('other readystate == 4' + ', status:' + xhr.status);setTimeout(function() {retryFunc();}, 5000);}else {console.log('other readystate:' + xhr.readyState + ', status:' + xhr.status);}};try {xhr.send();}catch (e) {//setTimeout(retryFunc, 200);retryFunc();}return xhr;
}exports.sendRequest = sendRequest;
exports.setURL = setURL;

服务器中9000是账号服务器:

游客的登陆逻辑

1:获取url里用户的参数,如果有,就用用户传的参数;

    //游客登录onBtnQuickStartClicked:function(){cc.vv.userMgr.guestAuth();},

2: 获取本地的存储的用户,如果没有,就根据时间随机生成一个;

    //游客验证登录guestAuth:function(){var account = cc.args["account"];if(account == null){account = cc.sys.localStorage.getItem("account");}if(account == null){account = Date.now();cc.sys.localStorage.setItem("account",account);}cc.vv.http.sendRequest("/guest",{account:account},this.onAuth);},

3: 发送游客登陆请求到服务器;

cc.vv.http.sendRequest("/guest",{account:account},this.onAuth);

userMgr发到账号服务器上的响应地址:  /guest

4: 账号服务器响应:返回OK和登陆的用户,大厅的ip地址;

    //游客登录服务器返回消息处理onAuth:function(ret){var self = cc.vv.userMgr;if(ret.errcode !== 0){console.log(ret.errmsg);}else{self.account = ret.account;self.sign = ret.sign;cc.vv.http.url = "http://" + cc.vv.SI.hall;//大厅服务器的地址self.login();}   },

5: userMgr: login函数,

    login:function(){var self = this;var onLogin = function(ret){if(ret.errcode !== 0){console.log(ret.errmsg);}else{if(!ret.userid){//jump to register user info.cc.director.loadScene("createrole");}else{console.log(ret);self.account = ret.account;self.userId = ret.userid;self.userName = ret.name;self.lv = ret.lv;self.exp = ret.exp;self.coins = ret.coins;self.gems = ret.gems;self.roomData = ret.roomid;self.sex = ret.sex;self.ip = ret.ip;cc.director.loadScene("hall");}}};cc.vv.wc.show("正在登录游戏");cc.vv.http.sendRequest("/login",{account:this.account,sign:this.sign},onLogin);},

发送请求给大厅服务器 client_server.js提供: /login

服务器返回登陆信息


//配置好响应请求:登录到大厅服务器;
app.get('/login',function(req,res){if(!check_account(req,res)){return;}var ip = req.ip;if(ip.indexOf("::ffff:") != -1){ip = ip.substr(7);}var account = req.query.account;db.get_user_data(account,function(data){if(data == null){http.send(res,0,"ok");return;}var ret = {account:data.account,userid:data.userid,name:data.name,lv:data.lv,exp:data.exp,coins:data.coins,gems:data.gems,ip:ip,sex:data.sex,};//判断是否在游戏,还是在房间;则直接进当前房间//一个账户,不能同时在两个房间里面游戏;db.get_room_id_of_user(data.userid,function(roomId){//如果用户处于房间中,则需要对其房间进行检查。 如果房间还在,则通知用户进入if(roomId != null){//检查房间是否存在于数据库中db.is_room_exist(roomId,function (retval){if(retval){ret.roomid = roomId;}else{//如果房间不在了,表示信息不同步,清除掉用户记录db.set_room_id_of_user(data.userid,null);}http.send(res,0,"ok",ret);});}else {http.send(res,0,"ok",ret);}});});
});

保存用户信息到userMgr;

进入到大厅场景;

如果没有用户,进入到创建角色场景,创建完角色以后,又再重新登陆一次;

创建角色场景

//-------------CreateRole.js--------------------
cc.Class({extends: cc.Component,properties: {inputName:cc.EditBox,// foo: {//    default: null,//    url: cc.Texture2D,  // optional, default is typeof default//    serializable: true, // optional, default is true//    visible: true,      // optional, default is true//    displayName: 'Foo', // optional//    readonly: false,    // optional, default is false// },// ...},onRandomBtnClicked:function(){var names = ["上官","欧阳","东方","端木","独孤","司马","南宫","夏侯","诸葛","皇甫","长孙","宇文","轩辕","东郭","子车","东阳","子言",];var names2 = ["雀圣","赌侠","赌圣","稳赢","不输","好运","自摸","有钱","土豪",];var idx = Math.floor(Math.random() * (names.length - 1));var idx2 = Math.floor(Math.random() * (names2.length - 1));this.inputName.string = names[idx] + names2[idx2];},// use this for initializationonLoad: function () {cc.vv.utils.setFitSreenMode();this.onRandomBtnClicked();},onBtnConfirmClicked:function(){var name = this.inputName.string;if(name == ""){console.log("invalid name.");return;}console.log(name);cc.vv.userMgr.create(name);}// called every frame, uncomment this function to activate update callback// update: function (dt) {// },
});

1:场景挂载了脚本代码代码 CreateRole;

(1)随机的生成一个名字;

(2)随机函数绑定到随机按钮;

(3)确定按钮:userMgr创建用户create函数

2:创建角色:

发送请求给 hallserver --> client_service.js --> “/create_user”;

cc.vv.userMgr.create(name);

返回信息继续走原来登陆的流程;

下一篇:达达麻将开房间

cocos creator麻将教程系列(四)—— 达达麻将客户端初始化流程相关推荐

  1. 从零开始实现自己的Kalimba——Cocos Creator新手教程系列(一)使用瓦片图Tiledmap设计游戏地图

    瓦片图Tiledmap可能是很多2d游戏开发者的偏爱,本节就Cocos Creator如何使用瓦片图进行详细的讲解. Tiled地图编辑器的下载安装不再赘述.下面介绍如何使用地图编辑器. 创建新地图. ...

  2. cocos creator麻将教程系列(三)—— 达达麻将开房间流程

    达达麻将"开房" 目录 达达麻将"开房" 要点 (1)达达麻将版图回顾 (2)达达麻将游戏服务器注册到大厅,来配置负载 (3)创建房间客户端请求; (4)创建房 ...

  3. WPF入门教程系列四——Dispatcher介绍

    WPF入门教程系列四--Dispatcher介绍 一.Dispatcher介绍 微软在WPF引入了Dispatcher,那么这个Dispatcher的主要作用是什么呢? 不管是WinForm应用程序还 ...

  4. 摄像头 保存到外网服务器_【小喵科技】物联网教程系列四:喵家外网IOT服务器...

    HOT新品热卖中■■■■■ 双向海量教学课程 无论是家长还是老师,都可以给孩子一个更好的未来 分享给更多的人 加入我们吧! 夏至の时光 ▼往期精彩课程在文章末尾 ▼喵家外网IOT服务器--快速上手 在 ...

  5. cocos creator麻将教程系列(二)—— 达达麻将的底层通讯express框架与socketio

    达达麻将网络通讯 目录 达达麻将网络通讯 要点: (1)express框架的基本写法 (2)socket.io的基本原理和使用; (3)creator阅读源码的必杀技巧; (4)一起来看达达麻将的游客 ...

  6. cocos creator麻将教程系列(七)—— 达达麻将打包与发布

    达达麻将打包与发布 达达麻将版图 打包注意事项 1:打包之前仔细学习creator的android 与h5的打包; 2: 达达麻将打包两个注意点: (1) 录音的代码; (2)微信的登陆代码; 3: ...

  7. cocos creator麻将教程系列(八)—— 达达麻将语音聊天源码分析

    达达麻将语音聊天源码分析 达达麻将版图 语音聊天 1:语音聊天只支持Native平台,iOS与android; 2: 语音聊天的音频格式为amr; 3: native平台实现了语音的录制和播放,可以移 ...

  8. cocos creator麻将教程系列(六)—— 达达麻将的游戏流程

    达达麻将游戏流程 达达麻将版图 登陆到游戏服务器 1:客户端GameNetMgr.js, connectGameServer连接到游戏服务器,并发送"login"命令; var s ...

  9. cocos creator麻将教程系列(五)—— 达达麻将开房间

    达达麻将开房间 达达麻将版图 达达麻将大厅 1: 大厅挂载了Hall.js 2:  onLoad 代码: // use this for initializationonLoad: function ...

最新文章

  1. C#Redis列表List
  2. 在Windows上同步SVN代码库到备份SVN机器上
  3. 一行代码值 200 万?雷军公开小米新 Logo 引吐槽
  4. Linux 内核 up down,信号量机制中的DOWN操作与UP操作详解
  5. ubuntu安装扩展在phpinfo显示不出来的解决办法
  6. thinkphp用来做什么项目_thinkphp第1课:使用thinkphp创建一个项目
  7. android仿空间photoview,PickPhotoView:一个Android照片选择器
  8. 游戏中基于物理的渲染(一)
  9. 怎样提高学生计算机应用能力,能力学生论文,关于如何提高技校生计算机的应用能力相关参考文献资料-免费论文范文...
  10. YV12数据与AVFrame的相互转换
  11. c语言case小于,大于和小于switch语句C
  12. 【YOLOv5-6.x】设置可学习权重结合BiFPN(Add操作)
  13. python-----异常处理
  14. 分发自动化_使用bitrise自动化应用分发
  15. [原创] Python3.6+request+beautiful 半次元Top100 爬虫实战,将小姐姐的cos美图获得
  16. sim7600ce 拨号上网测试_SIM7600CE TCP/IP连接与PPP拨号上网 4G上网
  17. 【Vegas原创】华为一键强制关闭后台应用的终极解决方法
  18. 使用模板匹配方法检测苹果缺陷
  19. Django数据库学习——定义用户模型(实例)
  20. Spring切入点表达式

热门文章

  1. 计算机知识与技能竞赛配图,第七届”高教杯“全国大学生先进成图技术与产品信息建模创新大赛机械类计算机绘图试卷.doc...
  2. 基于Selenium实现网易云音乐的登录
  3. 前端过程性考核,肝了一宿终于肝出来了!!!
  4. Python函数注释格式
  5. 解决ubuntu 18.04安装搜狗输入法 在fcitx的add input method不显示
  6. 三阶魔方CFOP还原方法图解
  7. hdu 6441 (费马大定理+勾股数 数学)
  8. (个体户)注册公众平台步骤
  9. 支付设计白皮书:支付系统的总架构
  10. 基于恩智浦MK60DN512Z系列单片机的智能模型车主程序与子程序集