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

客户端代码结构
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 initialization
onLoad: 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 initialization
onLoad: 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 callback
update: 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]);
}
//组装完整的URL
var 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 initialization
onLoad: 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);


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


下一篇:达达麻将开房间
本文详细介绍了达达麻将客户端的初始化流程,包括加载场景、Login场景的逻辑,以及游客登录和创建角色的步骤。在加载场景中,初始化全局管理对象,预加载资源,并进入Login场景。Login场景中,监听事件并处理微信登录和游客登录。如果无用户信息,将进入创建角色场景,完成角色创建后重新登录。

3661

被折叠的 条评论
为什么被折叠?



