Cocos Creator情怀棋牌源代码搭建,开房间流程(三)

情怀麻将“开房”

目录
  • 情怀麻将“开房”
要点
  1. 情怀麻将版图概览
  2. 情怀麻将游戏服务器注册到大厅进行负载配置
  3. 创建房间的客户端请求
  4. 创建房间的服务器响应
  5. 客户端登录到游戏服务器

寻找客户端发送逻辑

  1. 定位创建按钮,并查找关联的函数 → hall.js: onCreateRoomClicked

btn_create_room组件按钮——响应的JS函数为onCreateRoomClicked

onCreateRoomClicked:function(){
        if(cc.vv.gameNetMgr.roomId != null){
            cc.vv.alert.show("提示","房间已经创建!\n必须解散当前房间才能创建新的房间");
            return;
        }
        console.log("onCreateRoomClicked");
        this.createRoomWin.active = true;   
    },

查找this.createRoomWin.active = true;的作用,它在UI界面中处理,代码中未做进一步处理:

原来是用于激活创建房间的UI组件。

2.显示创建房间界面,并找到其挂载的脚本:createRoom.js



CreateRoom.js中的onBtnOK()函数:

3.创建参数列表,配置创建房间的参数,createRoom函数通过HTTP请求将命令发送到大厅服务器。

 createRoom:function(){
        var self = this;
        var onCreate = function(ret){
            if(ret.errcode !== 0){
                cc.vv.wc.hide();
                //console.log(ret.errmsg);
                if(ret.errcode == 2222){
                    cc.vv.alert.show("提示","房卡不足,创建房间失败!");  
                }
                else{
                    cc.vv.alert.show("提示","创建房间失败,错误码:" + ret.errcode);
                }
            }
            else{
                cc.vv.gameNetMgr.connectGameServer(ret);
            }
        };
        
        var difen = 0;
        for(var i = 0; i < self._difenxuanze.length; ++i){
            if(self._difenxuanze[i].checked){
                difen = i;
                break;
            }
        }
        
        var zimo = 0;
        for(var i = 0; i < self._zimo.length; ++i){
            if(self._zimo[i].checked){
                zimo = i;
                break;
            }     
        }

        var huansanzhang = self._wanfaxuanze[0].checked;        
        var jiangdui = self._wanfaxuanze[1].checked;
        var menqing = self._wanfaxuanze[2].checked;
        var tiandihu = self._wanfaxuanze[3].checked;
        
        var type = 0;
        for(var i = 0; i < self._leixingxuanze.length; ++i){
            if(self._leixingxuanze[i].checked){
                type = i;
                break;
            }     
        }
        
        if(type == 0){
            type = "xzdd";
        }
        else{
            type = "xlch";
        }
        
        var zuidafanshu = 0;
        for(var i = 0; i < self._zuidafanshu.length; ++i){
            if(self._zuidafanshu[i].checked){
                zuidafanshu = i;
                break;
            }     
        }
        
        
        var jushuxuanze = 0;
        for(var i = 0; i < self._jushuxuanze.length; ++i){
            if(self._jushuxuanze[i].checked){
                jushuxuanze = i;
                break;
            }     
        }
        
        var dianganghua = 0;
        for(var i = 0; i < self._dianganghua.length; ++i){
            if(self._dianganghua[i].checked){
                dianganghua = i;
                break;
            }     
        }
        
        var conf = {
            type:type,
            difen:difen,
            zimo:zimo,
            jiangdui:jiangdui,
            huansanzhang:huansanzhang,
            zuidafanshu:zuidafanshu,
            jushuxuanze:jushuxuanze,
            dianganghua:dianganghua,
            menqing:menqing,
            tiandihu:tiandihu,   
        }; 
        
        var data = {
            account:cc.vv.userMgr.account,
            sign:cc.vv.userMgr.sign,
            conf:JSON.stringify(conf)
        };
        console.log(data);
        cc.vv.wc.show("正在创建房间");
        cc.vv.http.sendRequest("/create_private_room",data,onCreate);   
    }

将参数组合成一个conf对象,并通过cc.vv.http.sendRequest("/create_private_room", data, onCreate);发送给服务器,请求创建房间。

conf对象转换为JSON字符串:conf: JSON.stringify(conf)

请求被提交至大厅服务器的http client service服务,即客户端发送请求到服务器。

4.响应地址为create_private_room,数据为创建参数,返回结果回调至onCreate函数。

服务器接收到客户端发送的data后,进行相应的逻辑处理。

寻找服务器响应

  1. 大厅服务器:配置了/create_private_room路径,用于处理客户端请求,通过数据库查询玩家数据。

  2. 处理步骤
    (1) 从数据库查询账号信息,使用db.js中的get_user_data函数。

(2) 检查玩家是否已在某个房间内进行游戏:调用get_room_id_of_user函数,只有不在游戏中才能创建新房间。

//验证玩家状态
		db.get_room_id_of_user(userId,function(roomId){
			if(roomId != null){
				http.send(res,-1,"user is playing in room now.");
				return;
			}
			//创建房间

(3) 调用room_service.js中的createRoom函数:

1>找到最小的负载的server; 

2> 获取用户的gems房卡的数目;      

db.get_gems(account,function(data){

优化点:房卡查询过程进行了两次,可通过系统优化减少冗余查询。

随后,执行room_service.js中的createRoom函数,完成房间创建流程。

接着消息被发送到HTTP服务器:

通过调用http.get(serverinfo.ip, serverinfo.httpPort, "/create_room", reqdata, function(ret, data)将请求转发。

流程:由最小负载的游戏服务器创建房间,通过大厅服务器的room_service找到相应的游戏服务器,并交由http_service进行处理。

3.麻将服务器的http_server响应create_room URL请求;

4.roomMgr负责创建房间,通过createRoom方法:

房间创建参数包括userIdconfgemsserverIpconfig.CLIENT_PORT,并执行回调函数处理结果。

//游戏服开房逻辑
exports.createRoom = function(creator,roomConf,gems,ip,port,callback){
	if(
		roomConf.type == null
		|| roomConf.difen == null
		|| roomConf.zimo == null
		|| roomConf.jiangdui == null
		|| roomConf.huansanzhang == null
		|| roomConf.zuidafanshu == null
		|| roomConf.jushuxuanze == null
		|| roomConf.dianganghua == null
		|| roomConf.menqing == null
		|| roomConf.tiandihu == null){
		callback(1,null);
		return;
	}

	if(roomConf.difen < 0 || roomConf.difen > DI_FEN.length){
		callback(1,null);
		return;
	}

	if(roomConf.zimo < 0 || roomConf.zimo > 2){
		callback(1,null);
		return;
	}

	if(roomConf.zuidafanshu < 0 || roomConf.zuidafanshu > MAX_FAN.length){
		callback(1,null);
		return;
	}

	if(roomConf.jushuxuanze < 0 || roomConf.jushuxuanze > JU_SHU.length){
		callback(1,null);
		return;
	}
	
	//需要消耗多少房卡
	var cost = JU_SHU_COST[roomConf.jushuxuanze];
	if(cost > gems){
		callback(2222,null);
		return;
	}

	var fnCreate = function(){
		var roomId = generateRoomId();
		if(rooms[roomId] != null || creatingRooms[roomId] != null){
			fnCreate();
		}
		else{
			creatingRooms[roomId] = true;
			db.is_room_exist(roomId, function(ret) {

				if(ret){
					delete creatingRooms[roomId];
					fnCreate();
				}
				else{
					var createTime = Math.ceil(Date.now()/1000);
					var roomInfo = {
						uuid:"",
						id:roomId,
						numOfGames:0,
						createTime:createTime,
						nextButton:0,
						seats:[],
						conf:{
							type:roomConf.type,
							baseScore:DI_FEN[roomConf.difen],
						    zimo:roomConf.zimo,
						    jiangdui:roomConf.jiangdui,
						    hsz:roomConf.huansanzhang,
						    dianganghua:parseInt(roomConf.dianganghua),
						    menqing:roomConf.menqing,
						    tiandihu:roomConf.tiandihu,
						    maxFan:MAX_FAN[roomConf.zuidafanshu],
						    maxGames:JU_SHU[roomConf.jushuxuanze],
						    creator:creator,
						}
					};
					
					if(roomConf.type == "xlch"){
						roomInfo.gameMgr = require("./gamemgr_xlch");
					}
					else{
						roomInfo.gameMgr = require("./gamemgr_xzdd");
					}
					console.log(roomInfo.conf);
					
					for(var i = 0; i < 4; ++i){
						roomInfo.seats.push({
							userId:0,
							score:0,
							name:"",
							ready:false,
							seatIndex:i,
							numZiMo:0,
							numJiePao:0,
							numDianPao:0,
							numAnGang:0,
							numMingGang:0,
							numChaJiao:0,
						});
					}
					

					//写入数据库
					var conf = roomInfo.conf;
					db.create_room(roomInfo.id,roomInfo.conf,ip,port,createTime,function(uuid){
						delete creatingRooms[roomId];
						if(uuid != null){
							roomInfo.uuid = uuid;
							console.log(uuid);
							rooms[roomId] = roomInfo;
							totalRooms++;
							callback(0,roomId);
						}
						else{
							callback(3,null);
						}
					});
				}
			});
		}
	}

	fnCreate();
};

a. 检查创建房间的参数;

支持两种麻将玩法:血战到底和血流成河;

b. 检查房卡余额:

var cost = JU_SHU_COST[roomConf.jushuxuanze];

c. 创建房间:

通过db.create_room(roomInfo.id, roomInfo.conf, ip, port, createTime, function(uuid)完成房间创建。

5.URL响应返回后调用enterRoom

roommgr.js中的exports.createRoom会回调callback(0, roomId),将roomId返回给http_service,然后发送房间ID。

http.send(res,0,"ok",{roomid:roomId});

hall_service.js接收到回调数据roomId后,准备执行进入房间的逻辑:

调用room_service.enterRoom(userId, name, roomId, function(errcode, enterInfo)来处理用户进入房间的操作。
 

优化点:在游戏中尽量减少使用console.log来打印日志数据,以避免占用服务器资源,从而导致服务器卡顿。建议使用异步日志系统,专门处理日志记录,减少服务器的等待时间。

(4) 调用room_service.js中的enterRoom函数:

exports.enterRoom = function(userId,name,roomId,fnCallback){
	var reqdata = {
		userid:userId,
		name:name,
		roomid:roomId
	};
	reqdata.sign = crypto.md5(userId + name + roomId + config.ROOM_PRI_KEY);

	var checkRoomIsRuning = function(serverinfo,roomId,callback){
		var sign = crypto.md5(roomId + config.ROOM_PRI_KEY);
		http.get(serverinfo.ip,serverinfo.httpPort,"/is_room_runing",{roomid:roomId,sign:sign},function(ret,data){
			if(ret){
				if(data.errcode == 0 && data.runing == true){
					callback(true);
				}
				else{
					callback(false);
				}
			}
			else{
				callback(false);
			}
		});
	}

	var enterRoomReq = function(serverinfo){
		http.get(serverinfo.ip,serverinfo.httpPort,"/enter_room",reqdata,function(ret,data){
			console.log(data);
			if(ret){
				if(data.errcode == 0){
					db.set_room_id_of_user(userId,roomId,function(ret){
						fnCallback(0,{
							ip:serverinfo.clientip,
							port:serverinfo.clientport,
							token:data.token
						});
					});
				}
				else{
					console.log(data.errmsg);
					fnCallback(data.errcode,null);
				}
			}
			else{
				fnCallback(-1,null);
			}
		});
	};

	var chooseServerAndEnter = function(serverinfo){
		serverinfo = chooseServer();
		if(serverinfo != null){
			enterRoomReq(serverinfo);
		}
		else{
			fnCallback(-1,null);					
		}
	}

	db.get_room_addr(roomId,function(ret,ip,port){
		if(ret){
			var id = ip + ":" + port;
			var serverinfo = serverMap[id];
			if(serverinfo != null){
				checkRoomIsRuning(serverinfo,roomId,function(isRuning){
					if(isRuning){
						enterRoomReq(serverinfo);
					}
					else{
						chooseServerAndEnter(serverinfo);
					}
				});
			}
			else{
				chooseServerAndEnter(serverinfo);
			}
		}
		else{
			fnCallback(-2,null);
		}
	});
};

1.麻将服务器的http_server响应enter_room URL请求;

//加入房间
app.get('/enter_room',function(req,res){
	var userId = parseInt(req.query.userid);
	var name = req.query.name;
	var roomId = req.query.roomid;
	var sign = req.query.sign;
	if(userId == null || roomId == null || sign == null){
		http.send(res,1,"invalid parameters");
		return;
	}

	var md5 = crypto.md5(userId + name + roomId + config.ROOM_PRI_KEY);
	console.log(req.query);
	console.log(md5);
	if(md5 != sign){
		http.send(res,2,"sign check failed.");
		return;
	}

	//安排玩家坐下
	roomMgr.enterRoom(roomId,userId,name,function(ret){
		if(ret != 0){
			if(ret == 1){
				http.send(res,4,"room is full.");
			}
			else if(ret == 2){
				http.send(res,3,"can't find room.");
			}	
			return;		
		}

		var token = tokenMgr.createToken(userId,5000);
		http.send(res,0,"ok",{token:token});
	});
});

2.roomMgrenterRoom方法返回一个token给大厅服务;

大厅服务器room_service.js接收到游戏服务器http_service发送过来的token

3.大厅服务将麻将服务器的IP、端口、token及房间ID组合后返回给客户端

寻找客户端处理返回

  1. 获取麻将服务器的IP、端口、token和时间;

客户端处理创建房间消息的回调函数。

拿到服务器返回的信息后,开始进行游戏连接:

cc.vv.gameNetMgr.connectGameServer(ret)

2.连接麻将服务器:GameNetManager.js中的connectGameServer方法。

connectGameServer:function(data){
        this.dissoveData = null;
        cc.vv.net.ip = data.ip + ":" + data.port;
        console.log(cc.vv.net.ip);
        var self = this;

        var onConnectOK = function(){
            console.log("onConnectOK");
            var sd = {
                token:data.token,
                roomid:data.roomid,
                time:data.time,
                sign:data.sign,
            };
            cc.vv.net.send("login",sd);
        };
        
        var onConnectFailed = function(){
            console.log("failed.");
            cc.vv.wc.hide();
        };
        cc.vv.wc.show("正在进入房间");
        cc.vv.net.connect(onConnectOK,onConnectFailed);
    }

3: 连接成功后,发送登陆游戏服务器的命令  socket.io发送登陆login

发送长连接请求 cc.vv.net.send("login",sd);


4.获取房间信息,包括座位详情,并广播给房间内的其他玩家,通知新用户加入。
socket.emit('login_result',ret);
//通知其它客户端
userMgr.broacastInRoom('new_user_comes_push',userData,userId);

5.服务器发送login_result命令到客户端,客户端接收并保存。随后,在GameNetMgr.jsinitHandlers函数中处理login_resultlogin_finished消息。

6.服务器发送login_finished命令,客户端接收后进入麻将游戏场景。

socket.emit('login_finished');

进入到麻将游戏场景

    cc.vv.net.addHandler("login_finished",function(data){
            console.log("login_finished");
            cc.director.loadScene("mjgame",function(){
                cc.vv.net.ping();
                cc.vv.wc.hide();
            });
            self.dispatchEvent("login_finished");
        });

服务器的扩展:

 心跳/服务器负载:

这里使用load来保存当前服务器的负载信息:

gameServerInfo.load存储了roomMgr.getTotalRooms()返回的房间总数。

http.get(config.HALL_IP,config.HALL_PORT,"/register_gs"

### 回答1: Cocos Creator是一个流行的游戏开发引擎,提供了各种功能和工具,可以帮助开发者快速创建和设计小游戏。当我们提到Cocos Creator游戏源代码时,通常是指游戏源代码文件和资源文件。 Cocos Creator源代码文件由JavaScript编写,通常包括游戏的逻辑、场景组织和界面展示等方面的代码。开发者可以通过编辑源代码来修改游戏的行为,添加新的功能或调整游戏的操作方式。通过理解源代码,开发者可以深入了解游戏的工作原理和内部机制。 此外,Cocos Creator源代码还包括资源文件,如图像、声音和动画等。这些资源文件是游戏中使用的各种元素,可以通过编辑软件进行设计和修改。通过修改资源文件,开发者可以改变游戏的外观和音效,增加游戏的吸引力和乐趣。 如果我们拥有Cocos Creator游戏源代码,我们可以根据自己的需求进行定制和修改,使游戏更符合自己的创意和目标。我们可以通过学习源代码来了解游戏的设计理念和技巧,从而提高自己的游戏开发能力。 总而言之,Cocos Creator游戏源代码游戏开发过程中的重要组成部分,通过对源代码的理解和修改,我们可以定制和优化游戏,使其更具个性和品质。 ### 回答2: Cocos Creator 是一款用于开发2D和3D游戏游戏引擎。它是基于 Cocos2d-x 引擎的基础上进行开发的,同时支持 JavaScript 和 TypeScript 编程语言。使用 Cocos Creator 可以方便地创建各种类型的小游戏Cocos Creator 的小游戏源代码是指使用 Cocos Creator 编写的游戏源代码。这些源代码包含了游戏的各种各样的功能和逻辑,例如游戏场景的创建、角色控制和碰撞检测等。 在 Cocos Creator 的小游戏源代码中,你可以看到许多不同的文件。其中最重要的是场景文件,它包含了游戏中的场景布局和对象的放置。另外还有脚本文件,用于编写游戏的逻辑和功能。以及资源文件,包括游戏中使用的图片、音效和动画等。 小游戏源代码中的脚本文件是游戏的核心部分,通过编写脚本可以实现游戏中的各种功能。你可以在脚本中定义角色的移动方式、敌人的行为模式、背景音乐的播放等。同时,你还可以使用脚本文件进行碰撞检测、游戏得分的计算和关卡的切换等。 总而言之,Cocos Creator 的小游戏源代码提供了游戏的各种功能和逻辑的实现方式。通过学习和理解这些源代码,你可以自由地修改和扩展游戏的功能,以满足自己的需求。同时,你也可以参考源代码中的编程方式和设计思路,来进行自己的游戏开发。 ### 回答3: Cocos Creator是一款用于开发小型游戏游戏引擎和开发工具。它提供了适用于多平台的跨平台开发功能,以及强大的编辑器和场景编辑工具。 Cocos Creator使用JavaScript脚本语言编写游戏逻辑,并使用C++编写引擎核心功能。游戏内容可以在编辑器中创建和编辑,然后通过编译输出为可在多个平台上运行的游戏代码。 Cocos Creator游戏源代码包括引擎核心的C++部分以及游戏逻辑的JavaScript脚本代码。引擎核心代码的作用是提供游戏开发所需的基础功能,包括图形渲染、物理碰撞检测、动画控制和资源管理等。 在游戏源代码中,开发者可以编写游戏逻辑的JavaScript脚本,包括角色移动、碰撞检测、游戏进度控制等。开发者可以通过编辑器添加场景、角色和其他游戏资源,并使用JavaScript脚本将它们连接起来,实现游戏的逻辑和交互。 通过编写自定义的脚本代码,开发者可以为游戏增加各种功能和特效,比如实现角色的特殊能力、设计游戏关卡的难度、添加音效和动画效果等。 总的来说,Cocos Creator游戏源代码包含了游戏引擎的核心和游戏逻辑的脚本代码,开发者可以利用这些代码来创建和定制自己的小型游戏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值