本文聚焦“创胜系列/寰宇雀弈房卡组件”的安卓端模块结构及技术细节,涵盖了三个主要互动模块。并结合图片展示系统框架与功能结构,最后详细补充了BUG处理机制与代码实现,供研发和二次开发参考。
一、资源概览
本系列组件仅包含安卓端内容,主要形式为 APK打包资源
+ JS代码包
。文件结构清晰,适合二次打包或配合服务端调试运行。
示意图1:整体资源包文件截图
二、启动主包结构说明
主包负责核心初始化、大厅载入和子模块跳转。主要文件结构如下:
-
assets/resources/start/...
:大厅启动资源 -
assets/resources/common/...
:通用UI与逻辑封装 -
main.js
:全局启动逻辑 -
project.manifest
:资源版本控制
关键逻辑入口 main.js
:
require('src/settings');
require('src/project');
cc.game.run(option, onStart);
通过 project.js
中挂载的模块初始化逻辑,将不同玩法组件挂载到主框架。
三、万年模块结构
该模块文件夹名为 /mj_wannian/
,是麻将玩法组件。主要结构:
-
mj_wannian/script/GameWanNian.js
:玩法主逻辑 -
mj_wannian/resources/prefab/
:UI组件 -
mj_wannian/config/
:配置牌型规则
关键代码示例:
onMsg_MJ_PLAYCARD(msg) {
const card = msg.card;
this.playCard(card);
}
四、跑得快模块结构
目录为 /runfast/
,是轻竞技类组件。文件组成:
-
runfast/script/RunfastGameCtrl.js
:核心控制器 -
runfast/config/RoomConfig.js
:房间规则配置 -
runfast/prefab/
:房间UI、牌局UI
常用通信处理:
onMsg_START_GAME(msg) {
this.roomStatus = 'playing';
this.initHandCards(msg.cards);
}
五、十三水模块结构
十三水玩法目录 /shisanshui/
,文件划分更为细致,包含动画、排序、牌型评比等模块。
-
shisanshui/logic/CardSort.js
:牌型算法 -
shisanshui/view/GameView.js
:场景UI逻辑 -
shisanshui/NetHandler.js
:服务端通信模块
部分排序算法:
sortByColor(cards) {
return cards.sort((a, b) => a.color - b.color);
}
六、常见异常处理与BUG应对机制设计(附代码)
在实际开发与运营阶段,安卓端互动娱乐组件常见的问题包括:
-
玩家断线/重连
-
消息格式异常/数据字段缺失
-
房间状态紊乱/多次进入
-
非法操作(超出时限、无权限操作)
-
资源加载失败导致界面卡死
以下为客户端与服务端的处理设计方案:
1. 服务端防御性数据验证(Node.js)
function safeParse(msg) {
try {
return JSON.parse(msg);
} catch (err) {
return null;
}
}
server.on('connection', socket => {
socket.on('message', msg => {
const data = safeParse(msg);
if (!data || typeof data.cmd !== 'string') {
socket.send(JSON.stringify({ cmd: 'error', msg: '非法数据格式' }));
return;
}
handleClientMessage(socket, data);
});
});
2. 客户端断线自动重连机制(Cocos Creator)
reconnect(attempt = 0) {
if (attempt > 5) {
console.error("重连失败,提示用户退出");
this.showReconnectFailedDialog();
return;
}
this.ws = new WebSocket(this.serverURL);
this.ws.onopen = () => {
console.log("重连成功,重新发送登录数据");
this.sendLogin();
};
this.ws.onerror = () => {
setTimeout(() => this.reconnect(attempt + 1), 1000 * (attempt + 1));
};
}
3. 房间状态冗余校验机制(服务端)
function joinRoom(socket, uid, roomID) {
const room = rooms[roomID];
if (!room) {
socket.send(JSON.stringify({ cmd: "error", msg: "房间不存在" }));
return;
}
if (room.players.includes(uid)) {
socket.send(JSON.stringify({ cmd: "error", msg: "已加入该房间" }));
return;
}
if (room.players.length >= room.max) {
socket.send(JSON.stringify({ cmd: "error", msg: "房间已满" }));
return;
}
room.players.push(uid);
notifyRoomUpdate(room);
}
4. 超时与非法指令处理(服务端)
function validateAction(uid, room, actionType) {
const player = room.players.find(p => p.uid === uid);
if (!player || player.status !== 'active') {
return { error: true, msg: '非法操作' };
}
const now = Date.now();
if (now - player.lastAction < 1000) {
return { error: true, msg: '操作频繁' };
}
return { error: false };
}
客户端接收错误响应:
handleMessage(data) {
if (data.cmd === "error") {
cc.log("错误提示:" + data.msg);
this.showToast(data.msg);
}
}
5. 前端资源加载失败处理
cc.loader.loadRes("game/mahjong_ui", cc.Prefab, (err, prefab) => {
if (err) {
console.error("资源加载失败", err);
this.showToast("资源加载失败,请重启游戏");
return;
}
const ui = cc.instantiate(prefab);
this.node.addChild(ui);
});
6. 自动回滚与房间清理机制(Node.js)
function cleanupRoom(roomID) {
const room = rooms[roomID];
if (!room) return;
// 通知所有用户
room.players.forEach(uid => {
const sock = userSockets[uid];
sock?.send(JSON.stringify({ cmd: "room_closed", reason: "超时或异常" }));
});
// 移除房间
delete rooms[roomID];
}
房间定期清理:
setInterval(() => {
for (const roomID in rooms) {
const room = rooms[roomID];
if (Date.now() - room.lastActive > 300000) {
cleanupRoom(roomID);
}
}
}, 10000);