情怀麻将网络通讯
要点:
- express 框架的基本用法
- socket.io 的原理与使用方法
- Creator 源码阅读的高效技巧
- 解析达达麻将的游客登录机制
达达麻将服务器配置
- express:Node.js 中的轻量级高效 Web 框架,达达麻将使用 HTTP 协议构建的 Web 服务器。
- socket.io:Node.js 的网络模块,将网络通讯封装为事件模式。
- account_server:负责账号验证的服务器,基于 express 框架 (1 个实例)。
- hall_server:大厅服务器,使用 express 作为通讯框架 (2 个实例)。
- mj_server:游戏服务器,采用 socket.io 与 express 结合的网络架构 (1 个实例)。
- 客户端:通过调用 API 函数进行 HTTP 请求。
express 安装步骤
- 通过 npm 安装 express 模块:
npm install express
express
创建一个应用实例:const express = require("express");
const app = express();
// 启动服务器,监听 8090 端口
app.listen(8090, () => {
console.log("服务器已启动,监听端口 8090");
});
// 使用 HTTP 协议的 GET 请求来发送数据
app.get("/login", (req, res) => {
res.send("----ok----");
});
// 启动 Node.js 服务器并运行 Express 框架
// 执行命令:node webserver.js
// 在浏览器中输入以下地址进行访问测试
// http://127.0.0.1:8090/login
// 页面将显示:----ok----
3: 配置好 webserver 的端口;
const express = require("express");
const app = express();
// 监听 8090 端口
app.listen(8090, () => {
console.log("服务器正在监听端口 8090...");
});
// 定义 GET 请求,用于响应 /login 路由
app.get("/login", (req, res) => {
res.send("----ok----");
// 处理带参数的请求,并在控制台输出参数内容
console.log("收到请求参数:", req.query);
});
4配置静态资源路径;
5设置 HTTP GET 请求服务;
6配置 HTTP POST 请求服务;
7检查达达麻将 account
服务器的整体结构;
//G:\..\..\js_ddmj\server\server\account_server\app.js
var db = require('../utils/db');
var configs = require(process.argv[2]);
//init db pool.
//连接数据库(初始化)
db.init(configs.mysql());
//
//获得账号服务器account_server的配置文件
var config = configs.account_server();
var as = require('./account_server');
as.start(config);
//启动服务器
var dapi = require('./dealer_api');
dapi.start(config);
-------------------------------------------
//G:\..\..\js_ddmj\server\server\account_server\account_server.js
var crypto = require('../utils/crypto');
var express = require('express');
var db = require('../utils/db');
var http = require("../utils/http");
//生成一个基于express的对象,来完成web服务,作为web服务器
//通过http协议,和客户端交互数据
var app = express();
var hallAddr = "";
function send(res,ret){
var str = JSON.stringify(ret);
res.send(str)
}
var config = null;
//启动account server账号服务器
exports.start = function(cfg){
config = cfg;
hallAddr = config.HALL_IP + ":" + config.HALL_CLIENT_PORT;
app.listen(config.CLIENT_PORT);
console.log("account server is listening on " + config.CLIENT_PORT);
}
//----函数功能----
//等待客户端的请求,URL----register注册
app.get('/register',function(req,res){
//等待客户端的请求,URL----get_version获取版本
app.get('/get_version',function(req,res){
//等待客户端的请求,URL----get_serverinfo获取服务器信息
app.get('/get_serverinfo',function(req,res){
//等待客户端的请求,URL----guest游客登录
app.get('/guest',function(req,res){
//等待客户端的请求,URL----微信登录的获取auth
app.get('/auth',function(req,res){
//微信登录相关信息
var appInfo = {
//微信登录获取access_token
function get_access_token(code,os,callback){
//微信登录,获取state_info
function get_state_info(access_token,openid,callback){
//微信登录,获取wechat_auth
app.get('/wechat_auth',function(req,res){
//等待客户端的请求,URL----base_info获取基础信息
app.get('/base_info',function(req,res){
------------------------------------------------------------------------------
//G:\..\..\js_ddmj\server\server\configs_local.js
var HALL_IP = "127.0.0.1";
var HALL_CLIENT_PORT = 9001;
var HALL_ROOM_PORT = 9002;
var ACCOUNT_PRI_KEY = "^&*#$%()@";
var ROOM_PRI_KEY = "~!@#$(*&^%$&";
var LOCAL_IP = 'localhost';
exports.mysql = function(){
return {
HOST:'127.0.0.1',
USER:'root',
PSWD:'123456',
DB:'dd_mj',
PORT:3306,
}
}
//账号服配置
exports.account_server = function(){
return {
CLIENT_PORT:9000,
HALL_IP:HALL_IP,
HALL_CLIENT_PORT:HALL_CLIENT_PORT,
ACCOUNT_PRI_KEY:ACCOUNT_PRI_KEY,
//
DEALDER_API_IP:LOCAL_IP,
DEALDER_API_PORT:12581,
VERSION:'20161227',
APP_WEB:'http://fir.im/2f17',
};
};
G:\..\..\js_ddmj\server\server\hall_server\app.js
var client_service = require("./client_service");
var room_service = require("./room_service");
var configs = require(process.argv[2]);
//获取大厅的配置文件
var config = configs.hall_server();
var db = require('../utils/db');
//初始化数据库
db.init(configs.mysql());
//启动客户端的大厅web服务器的请求
client_service.start(config);
//启动客户端的房间web服务器的请求
room_service.start(config);
-----------------------------------------------------------
G:\..\..\js_ddmj\server\server\hall_server\client_service.js
//http协议下的数据交互
var app = express();
var config = null;
//配置好响应请求:登录到大厅服务器;
app.get('/login',function(req,res){
//创建一个用户
app.get('/create_user',function(req,res){
//创建一个房间
app.get('/create_private_room',function(req,res){
//进入一个房间
app.get('/enter_private_room',function(req,res){
//获取历史记录
app.get('/get_history_list',function(req,res){
//获取游戏房间
app.get('/get_games_of_room',function(req,res){
//获取游戏房间详细信息
app.get('/get_detail_of_game',function(req,res){
//获取玩家状态
app.get('/get_user_status',function(req,res){
//获取消息
app.get('/get_message',function(req,res){
//查询服务器是否在线
app.get('/is_server_online',function(req,res){
//启动函数
exports.start = function($config){
config = $config;
app.listen(config.CLEINT_PORT);
console.log("client service is listening on port " + config.CLEINT_PORT);
};
//设置跨域访问
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1');
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
-----------------------------------------------------------
G:\..\..\js_ddmj\server\server\hall_server\room_service.js
//注册
app.get('/register_gs',function(req,res){
//启动函数
exports.start = function($config){
config = $config;
app.listen(config.ROOM_PORT,config.FOR_ROOM_IP);
console.log("room service is listening on " + config.FOR_ROOM_IP + ":" + config.ROOM_PORT);
};
-----------------------------------------------------------
G:\..\..\js_ddmj\server\server\majiang_server\app.js
var http_service = require("./http_service");
var socket_service = require("./socket_service");
//从配置文件获取服务器信息
var configs = require(process.argv[2]);
var config = configs.game_server();
var db = require('../utils/db');
db.init(configs.mysql());
//开启HTTP服务
http_service.start(config);
//开启外网SOCKET服务
socket_service.start(config);
//require('./gamemgr');
G:\..\..\js_ddmj\server\server\majiang_server\http_service.js
//获取服务器信息
app.get('/get_server_info',function(req,res){
//创建房间
app.get('/create_room',function(req,res){
//加入房间
app.get('/enter_room',function(req,res){
//ping检查
app.get('/ping',function(req,res){
//房间是否允许中
app.get('/is_room_runing',function(req,res){
//向大厅服定时心跳
function update(){
if(lastTickTime + config.HTTP_TICK_TIME < Date.now()){
lastTickTime = Date.now();
gameServerInfo.load = roomMgr.getTotalRooms();
http.get(config.HALL_IP,config.HALL_PORT,"/register_gs",gameServerInfo,function(ret,data){
if(ret == true){
if(data.errcode != 0){
console.log(data.errmsg);
}
if(data.ip != null){
serverIp = data.ip;
}
}
else{
//
lastTickTime = 0;
}
});
var mem = process.memoryUsage();
var format = function(bytes) {
return (bytes/1024/1024).toFixed(2)+'MB';
};
//console.log('Process: heapTotal '+format(mem.heapTotal) + ' heapUsed ' + format(mem.heapUsed) + ' rss ' + format(mem.rss));
}
}
//启动函数
exports.start = function($config){
config = $config;
//
gameServerInfo = {
id:config.SERVER_ID,
clientip:config.CLIENT_IP,
clientport:config.CLIENT_PORT,
httpPort:config.HTTP_PORT,
load:roomMgr.getTotalRooms(),
};
setInterval(update,1000);
app.listen(config.HTTP_PORT,config.FOR_HALL_IP);
console.log("game server is listening on " + config.FOR_HALL_IP + ":" + config.HTTP_PORT);
};
socket.io
1:socket.io把网络的接受数据,看作是网络事件,发送端发送一个事件,接收端接受这个事件;
2: 接受的时候可以带着数据,这样,就能够进行数据交换;
3: socket.io能支持tcp, ws两种,开发人员不用关心,这个也就是为什么他会在node.js里流行的模型;
4: socket.io的简单使用: 监听事件,触发事件;
5: 达达麻将服务器的socket.io的代码;
6: 有人收就有人发,要善于查代码,来看逻辑;
G:\..\..\js_ddmj\server\server\majiang_server\socket_service.js
//启动服务
exports.start = function(config,mgr){
io = require('socket.io')(config.CLIENT_PORT);
//监听是否有客户端连接进来,如果有客户连接进来就会调用这个函数
//为这个客户创建一个socket通道
io.sockets.on('connection',function(socket){
//监听一个事件,然后data,客户端发送过来的数据
//数据使用的是json协议的编码,来进行数据交换;底层发送json文本;
socket.on('login',function(data){
//转成json格式数据
data = JSON.parse(data);
if(socket.userId != null){
//已经登陆过的就忽略
return;
}
//emit发送一个事件
socket.emit('login_result',{errcode:2,errmsg:"login failed. invalid sign!"});
socket.io----事件的模式,事件+事件数据;监听事件,事件数据;使用emit来发送;
//json协议的编码:转成json格式数据
data = JSON.parse(data);
----------------------------------------------------------------------------------
var crypto = require('../utils/crypto');
var db = require('../utils/db');
var tokenMgr = require('./tokenmgr');
var roomMgr = require('./roommgr');
var userMgr = require('./usermgr');
var io = null;
//启动服务
exports.start = function(config,mgr){
io = require('socket.io')(config.CLIENT_PORT);
//监听是否有客户端连接进来,如果有客户连接进来就会调用这个函数
//为这个客户创建一个socket通道
io.sockets.on('connection',function(socket){
//监听一个事件,然后data,客户端发送过来的数据
socket.on('login',function(data){
data = JSON.parse(data);
if(socket.userId != null){
//已经登陆过的就忽略
return;
}
var token = data.token;
var roomId = data.roomid;
var time = data.time;
var sign = data.sign;
console.log(roomId);
console.log(token);
console.log(time);
console.log(sign);
//检查参数合法性
if(token == null || roomId == null || sign == null || time == null){
console.log(1);
socket.emit('login_result',{errcode:1,errmsg:"invalid parameters"});
return;
}
//检查参数是否被篡改
var md5 = crypto.md5(roomId + token + time + config.ROOM_PRI_KEY);
if(md5 != sign){
console.log(2);
//emit发送一个事件
socket.emit('login_result',{errcode:2,errmsg:"login failed. invalid sign!"});
return;
}
//检查token是否有效
if(tokenMgr.isTokenValid(token)==false){
console.log(3);
socket.emit('login_result',{errcode:3,errmsg:"token out of time."});
return;
}
//检查房间合法性
var userId = tokenMgr.getUserID(token);
var roomId = roomMgr.getUserRoom(userId);
userMgr.bind(userId,socket);
socket.userId = userId;
//返回房间信息
var roomInfo = roomMgr.getRoom(roomId);
var seatIndex = roomMgr.getUserSeat(userId);
roomInfo.seats[seatIndex].ip = socket.handshake.address;
var userData = null;
var seats = [];
for(var i = 0; i < roomInfo.seats.length; ++i){
var rs = roomInfo.seats[i];
var online = false;
if(rs.userId > 0){
online = userMgr.isOnline(rs.userId);
}
seats.push({
userid:rs.userId,
ip:rs.ip,
score:rs.score,
name:rs.name,
online:online,
ready:rs.ready,
seatindex:i
});
if(userId == rs.userId){
userData = seats[i];
}
}
//通知前端
var ret = {
errcode:0,
errmsg:"ok",
data:{
roomid:roomInfo.id,
conf:roomInfo.conf,
numofgames:roomInfo.numOfGames,
seats:seats
}
};
socket.emit('login_result',ret);
//通知其它客户端
userMgr.broacastInRoom('new_user_comes_push',userData,userId);
socket.gameMgr = roomInfo.gameMgr;
//玩家上线,强制设置为TRUE
socket.gameMgr.setReady(userId);
socket.emit('login_finished');
if(roomInfo.dr != null){
var dr = roomInfo.dr;
var ramaingTime = (dr.endTime - Date.now()) / 1000;
var data = {
time:ramaingTime,
states:dr.states
}
userMgr.sendMsg(userId,'dissolve_notice_push',data);
}
});
socket.on('ready',function(data){
var userId = socket.userId;
if(userId == null){
return;
}
socket.gameMgr.setReady(userId);
userMgr.broacastInRoom('user_ready_push',{userid:userId,ready:true},userId,true);
});
//换牌
socket.on('huanpai',function(data){
if(socket.userId == null){
return;
}
if(data == null){
return;
}
if(typeof(data) == "string"){
data = JSON.parse(data);
}
var p1 = data.p1;
var p2 = data.p2;
var p3 = data.p3;
if(p1 == null || p2 == null || p3 == null){
console.log("invalid data");
return;
}
socket.gameMgr.huanSanZhang(socket.userId,p1,p2,p3);
});
//定缺
socket.on('dingque',function(data){
if(socket.userId == null){
return;
}
var que = data;
socket.gameMgr.dingQue(socket.userId,que);
});
//出牌
socket.on('chupai',function(data){
if(socket.userId == null){
return;
}
var pai = data;
socket.gameMgr.chuPai(socket.userId,pai);
});
//碰
socket.on('peng',function(data){
if(socket.userId == null){
return;
}
socket.gameMgr.peng(socket.userId);
});
//杠
socket.on('gang',function(data){
if(socket.userId == null || data == null){
return;
}
var pai = -1;
if(typeof(data) == "number"){
pai = data;
}
else if(typeof(data) == "string"){
pai = parseInt(data);
}
else{
console.log("gang:invalid param");
return;
}
socket.gameMgr.gang(socket.userId,pai);
});
//胡
socket.on('hu',function(data){
if(socket.userId == null){
return;
}
socket.gameMgr.hu(socket.userId);
});
//过 遇上胡,碰,杠的时候,可以选择过
socket.on('guo',function(data){
if(socket.userId == null){
return;
}
socket.gameMgr.guo(socket.userId);
});
//聊天
socket.on('chat',function(data){
if(socket.userId == null){
return;
}
var chatContent = data;
userMgr.broacastInRoom('chat_push',{sender:socket.userId,content:chatContent},socket.userId,true);
});
//快速聊天
socket.on('quick_chat',function(data){
if(socket.userId == null){
return;
}
var chatId = data;
userMgr.broacastInRoom('quick_chat_push',{sender:socket.userId,content:chatId},socket.userId,true);
});
//语音聊天
socket.on('voice_msg',function(data){
if(socket.userId == null){
return;
}
console.log(data.length);
userMgr.broacastInRoom('voice_msg_push',{sender:socket.userId,content:data},socket.userId,true);
});
//表情
socket.on('emoji',function(data){
if(socket.userId == null){
return;
}
var phizId = data;
userMgr.broacastInRoom('emoji_push',{sender:socket.userId,content:phizId},socket.userId,true);
});
//语音使用SDK不出现在这里
//退出房间
socket.on('exit',function(data){
var userId = socket.userId;
if(userId == null){
return;
}
var roomId = roomMgr.getUserRoom(userId);
if(roomId == null){
return;
}
//如果游戏已经开始,则不可以
if(socket.gameMgr.hasBegan(roomId)){
return;
}
//如果是房主,则只能走解散房间
if(roomMgr.isCreator(userId)){
return;
}
//通知其它玩家,有人退出了房间
userMgr.broacastInRoom('exit_notify_push',userId,userId,false);
roomMgr.exitRoom(userId);
userMgr.del(userId);
socket.emit('exit_result');
socket.disconnect();
});
//解散房间
socket.on('dispress',function(data){
var userId = socket.userId;
if(userId == null){
return;
}
var roomId = roomMgr.getUserRoom(userId);
if(roomId == null){
return;
}
//如果游戏已经开始,则不可以
if(socket.gameMgr.hasBegan(roomId)){
return;
}
//如果不是房主,则不能解散房间
if(roomMgr.isCreator(roomId,userId) == false){
return;
}
userMgr.broacastInRoom('dispress_push',{},userId,true);
userMgr.kickAllInRoom(roomId);
roomMgr.destroy(roomId);
socket.disconnect();
});
//解散房间
socket.on('dissolve_request',function(data){
var userId = socket.userId;
console.log(1);
if(userId == null){
console.log(2);
return;
}
var roomId = roomMgr.getUserRoom(userId);
if(roomId == null){
console.log(3);
return;
}
//如果游戏未开始,则不可以
if(socket.gameMgr.hasBegan(roomId) == false){
console.log(4);
return;
}
var ret = socket.gameMgr.dissolveRequest(roomId,userId);
if(ret != null){
var dr = ret.dr;
var ramaingTime = (dr.endTime - Date.now()) / 1000;
var data = {
time:ramaingTime,
states:dr.states
}
console.log(5);
userMgr.broacastInRoom('dissolve_notice_push',data,userId,true);
}
console.log(6);
});
socket.on('dissolve_agree',function(data){
var userId = socket.userId;
if(userId == null){
return;
}
var roomId = roomMgr.getUserRoom(userId);
if(roomId == null){
return;
}
var ret = socket.gameMgr.dissolveAgree(roomId,userId,true);
if(ret != null){
var dr = ret.dr;
var ramaingTime = (dr.endTime - Date.now()) / 1000;
var data = {
time:ramaingTime,
states:dr.states
}
userMgr.broacastInRoom('dissolve_notice_push',data,userId,true);
var doAllAgree = true;
for(var i = 0; i < dr.states.length; ++i){
if(dr.states[i] == false){
doAllAgree = false;
break;
}
}
if(doAllAgree){
socket.gameMgr.doDissolve(roomId);
}
}
});
socket.on('dissolve_reject',function(data){
var userId = socket.userId;
if(userId == null){
return;
}
var roomId = roomMgr.getUserRoom(userId);
if(roomId == null){
return;
}
var ret = socket.gameMgr.dissolveAgree(roomId,userId,false);
if(ret != null){
userMgr.broacastInRoom('dissolve_cancel_push',{},userId,true);
}
});
//断开链接
socket.on('disconnect',function(data){
var userId = socket.userId;
if(!userId){
return;
}
var data = {
userid:userId,
online:false
};
//通知房间内其它玩家
userMgr.broacastInRoom('user_state_push',data,userId);
//清除玩家的在线信息
userMgr.del(userId);
socket.userId = null;
});
socket.on('game_ping',function(data){
var userId = socket.userId;
if(!userId){
return;
}
//console.log('game_ping');
socket.emit('game_pong');
});
});
console.log("game server is listening on " + config.CLIENT_PORT);
};
游客登陆源码分析
1:学会搜索;
2: creator从节点触发找脚本;
客户端发送数据:
cc.vv.http.sendRequest
启动场景:
G:\..\..\js_ddmj\ddmj_20161230\client\assets\resources\scenes\loading.fire
通过场景来寻找对应的JS脚本,如上图;
cc.vv 的出处在此:
G:\..\..\js_ddmj\ddmj_20161230\client\assets\scripts\components\LoadingLogic.js
initMgr:function(){
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();
cc.args = this.urlParse();
},
数据驱动场景,依据场景定位相应的 JS 脚本文件;
cc.vv的出处:
服务器消息处理:
成功之后走self.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);
},
将登录请求发送至 hall_server
的 client_service.js
文件:
cc.vv.http.sendRequest("/login", { account: this.account, sign: this.sign
db.get_user_data(account, function(data) {
调用 utils
目录下 db.js
中的 exports.get_user_data = function(account, callback) {
来查找玩家数据,并从数据库中执行相应的查询操作。
接着根据该玩家的 UserID
来判断其是否在游戏房间中,
通过 db.get_room_id_of_user(data.userid, function(roomId) {
进行房间ID的查询操作;
若房间不存在或玩家已不在房间内,则清理相应的数据,并返回登录成功消息。
http.send(res, 0, "ok", ret);
当账号 ID 不存在时,跳转到创建角色界面;若已有玩家信息,则直接跳转至 hall
场景,并发送登录 hall
的请求。
cc.director.loadScene("createrole"); // 进入创建角色界面
cc.director.loadScene("hall"); // 进入大厅场景
cc.vv.http.sendRequest("/login", { account: this.account, sign: this.sign }, onLogin); // 发送登录大厅的请求
创建角色场景及其关联的 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 () {
if(!cc.sys.isNative && cc.sys.isMobile){
var cvs = this.node.getComponent(cc.Canvas);
cvs.fitHeight = true;
cvs.fitWidth = true;
}
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) {
// },
});
通过随机生成名称,调用 cc.vv.userMgr.create(name);
进行创建操作;
hall_server
负责处理创建角色的相关请求消息。
通过以下方式检查玩家是否存在:db.is_user_exist(account, function(ret) {
若玩家不存在,则执行创建操作:db.create_user(account, name, coins, gems, 0, null, function(ret) {
跳转到 hall
场景,并关联 Hall.js
脚本文件:.