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

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

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

达达麻将版图

 

 

 

客户端代码结构

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

 

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

 

下一篇:达达麻将开房间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值