MX Player - Docking of Battle Games (双人对战游戏接入)
1. Game Init (游戏初始化)
After the game is loaded, execute it in the entry class: (游戏加载完成后在入口类中执行)
onGameInit();
onGameStart();
/**
* !#en Game initialization
* !#zh 游戏初始化
*/
export let onGameInit = function () {
if (!DeviceUtil.IsMXGame) {
return;
}
//获取游戏配置
let info = gameManager.onGameInit();
let gameConfig: GameConfig = JSON.parse(info);
gameId_ = gameConfig.gameId;
//!#zh 如需接入商城,userId_===""时为未登录用户,需要提示用户登录之后才能打开商城
//!#en If you need to access the mall, userId_==="" is a non-login user, you need to prompt the user to log in before opening the mall
userId_ = gameConfig.userId;
//!#zh isFirstOpen===true 用户首次打开游戏,如需新手引导可用此字段判断
//!#en isFirstOpen===true The user opens the game for the first time, if you need novice guidance, you can use this field to judge
if (gameConfig.isFirstOpen !== null && gameConfig.isFirstOpen !== undefined) {
is_Guide = gameConfig.isFirstOpen;
}
gameInitComplete = true;
};
/**
* !#en Game Start If the loading image is used in the game zip package, you need to call this method to clear the loading image
* !#zh 游戏开始 如果游戏zip包中用了loading图需要调用此方法清除loading图片
*/
export let onGameStart = function () {
if (!DeviceUtil.IsMXGame) {
return;
}
gameManager.onGameStart();
};
2. Start matching(开始匹配)
Call the
onGameLoaded()
method to start matching, and the matching data will be returned bycc.game.emit("commonEventInterface")
.
After obtaining the matching data, you need to callonGameCleanPosters()
to close the App layer matching interface, and then perform the in-game matching animation and connect to the in-game server.调用 *
onGameLoaded()
方法开始匹配,匹配数据会通过cc.game.emit("commonEventInterface")*
返回 。
获取到匹配数据后需调用onGameCleanPosters()
**关闭App层匹配界面,然后进行游戏内匹配动画和连接游戏内server。
/**
* !#en The game is loaded, the App layer matching page is displayed and the matching starts
* !#zh 游戏加载完成,App层匹配页面显示并开始匹配
*/
export let onGameLoaded = function () {
console.log("---------------:" + game_version);
if (!DeviceUtil.IsMXGame) {
return;
}
let info = { GameVersion: game_version };
gameManager.onGameLoaded(JSON.stringify(info));
//!#en Record the start time of the game
//!#zh 记录游戏开始时间
game_start_time = Date.now();
//!#en App will emit a commonEventInterface event to return events and data
//!#zh App会发射commonEventInterface事件返回事件和数据
cc.game.on("commonEventInterface", commonEventInterface_battle, this);
};
/**
* !#en General event interface
* !#zh 通用事件接口
* @param event_name 事件名
* @param info 信息
*/
export let commonEventInterface_battle = function (event_name: string, info: any) {
switch (event_name) {
case "backPressed": {
cc.game.emit("userGamePausedCall");
cc.game.emit("userPausedViewShowCall");
break;
}
case "screenOn": {
break;
}
case "screenOff": {
cc.game.emit("userGamePausedCall");
cc.game.emit("userPausedViewShowCall");
break;
}
case "pagePause": {
cc.game.emit("eventGamePausedCall");
cc.game.emit("eventMusicPausedCall");
break;
}
case "pageResume": {
cc.game.emit("eventGameResumeCall");
cc.game.emit("eventMusicResumeCall");
break;
}
case "userPresent": {
//解锁屏幕
break;
}
//!#en Battle data
//!#zh 对战数据
case "userMatched": {
battleInfo(info);
break;
}
}
};
/**
* !#en Close App layer matching interface
* !#zh 关闭App层匹配界面
*/
export let onGameCleanPosters = function () {
if (!DeviceUtil.IsMXGame) {
return;
}
gameManager.onGameCleanPosters();
};
3. Battle Game Over(游戏结束)
Call
onBattleGameOver()
at the end of the game, you can also call this method if you want to force the end of the game.游戏结束调用
onBattleGameOver()
,想强行结束游戏也可调用此方法。
/**
* !#en GameOver
* !#zh 游戏结束
*/
export let onBattleGameOver = function () {
if (!DeviceUtil.IsMXGame) {
return;
}
if (is_over) {
return;
}
is_over = true;
let myScore = 0;
let otherScore = 0;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (gameStore.player1Data.completeBlockArr[i][j] === 1) {
myScore++;
}
if (gameStore.player2Data.completeBlockArr[i][j] === 1) {
otherScore++;
}
}
}
let info = {
gameId: gameId_,
battleId: battleId_,
roomId: roomId_,
battle_info: {
currentscore: myScore,
oppoScore: otherScore,
winStatus: gameStore.winType,
numA: gameStore.selfMoveCount,
numB: gameStore.otherMoveCount,
numC: gameStore.createPropsNum,
numD: gameStore.usePauseSkillCount,
numE: gameStore.useSwapSkillCount,
numF: gameStore.useRandomSkillCount,
numG: gameStore.beUsedPauseSkillCount,
numH: gameStore.beUsedRandomSkillCount,
numI: gameStore.selfGetPropNum,
numJ: gameStore.otherGetPropNum,
oppoType: gameStore.isAI,
oppoUserID: gameStore.player2Data.id,
},
};
//!#en Quit the game report
//!#zh 退出游戏打点
/**********************************************************************************************/
let rInfo = {
roomID: battleId_,
playtime: Math.round((Date.now() - game_start_time) / 1000)
};
gameManager.onTrack("gameExit", JSON.stringify(rInfo));
/**********************************************************************************************/
//!#en This is a custom report and can be ignored
//!#zh 此为自定义打点,可忽略
const emojiClickedInfo = JSON.stringify(gameStore.expressionStatistic);
gameManager.onTrack("emojiClicked", emojiClickedInfo);
//!#en info is the reported data at the end of the game
//!#zh info是游戏结束的上报数据
gameManager.onBattleGameOver(JSON.stringify(info));
};
Attach the complete code at the end:
最后附上完整代码:
import { conditionId } from "../Manager/DataManager";
import SocketManager from "../Manager/SocketManager";
import UIManager from "../Manager/UIManager";
import { gameStore, WinType } from "../store/GameStore";
import MatchUI from "../UI/Match/MatchUI";
import DeviceUtil from "../utils/DeviceUtil";
//!#en The game version is synchronized with the server
//!#zh 游戏版本与服务器同步
export let game_version: string = "1.0.0";
//!#en Game ID
//!#zh 游戏ID
export let gameId_: string = "";
//!#en Battle ID
//!#zh 对战ID
export let battleId_: string = "";
//!#en Room ID
//!#zh 房间ID
export let roomId_: string = "4f4b7518761dc9533f9f2cc4c77b561d_c4d2cgjqgkce9tkehg5g";
//!#en User ID
//!#zh 用户ID
export let userId_: string = "";
//!#en Game start time,Used to end the reported game duration
//!#zh 游戏开始时间,用于结束上报游戏时长
export let game_start_time: number = 0;
//!#en Novice guidance Or Not
//!#zh 是否新手引导
export let is_Guide: boolean = false;
//!#en Is game init complete?
//!#zh 初始化游戏配置是否获取完成
export let gameInitComplete: boolean = false;
/**
* !#en GameInit return Object
*/
export interface GameConfig {
highestScore: number;
lastLevel: number;
roomType: string;
gameId: string;
gameName: string;
userId: string;
isFirstOpen: boolean;
source: string;
startType: string;
rewardType: string;
appVersion: number;
appId: string;
trackInfo: string;
roomId?: string;
tournamentId?: string;
}
/**
* Battle data Object
*/
interface info {
status: string,
roomId: string,
connectUrl: string,
mapId: number,
gameVersion: string,
users: user[],
battleId: string,
gameId: string,
selfUserId: string
}
/**
* User data Object
*/
interface user {
type: string,
userId: string,
playerId: string,
name: string,
avatar: string,
score: number,
playerData?: any
}
export let setGameId = function (id: string) {
gameId_ = id;
};
export let setBattleId = function (id: string) {
battleId_ = id;
};
export let setRoomId = function (id: string) {
roomId_ = id;
};
export let setGuide = function (b: boolean) {
is_Guide = b;
};
/**
* !#en Game initialization
* !#zh 游戏初始化
*/
export let onGameInit = function () {
if (!DeviceUtil.IsMXGame) {
return;
}
//获取游戏配置
let info = gameManager.onGameInit();
let gameConfig: GameConfig = JSON.parse(info);
gameId_ = gameConfig.gameId;
//!#zh 如需接入商城,userId_===""时为未登录用户,需要提示用户登录之后才能打开商城
//!#en If you need to access the mall, userId_==="" is a non-login user, you need to prompt the user to log in before opening the mall
userId_ = gameConfig.userId;
//!#zh isFirstOpen===true 用户首次打开游戏,如需新手引导可用此字段判断
//!#en isFirstOpen===true The user opens the game for the first time, if you need novice guidance, you can use this field to judge
if (gameConfig.isFirstOpen !== null && gameConfig.isFirstOpen !== undefined) {
is_Guide = gameConfig.isFirstOpen;
}
gameInitComplete = true;
};
/**
* !#en Game Start If the loading image is used in the game zip package, you need to call this method to clear the loading image
* !#zh 游戏开始 如果游戏zip包中用了loading图需要调用此方法清除loading图片
*/
export let onGameStart = function () {
if (!DeviceUtil.IsMXGame) {
return;
}
gameManager.onGameStart();
};
/**
* !#en The game is loaded, the App layer matching page is displayed and the matching starts
* !#zh 游戏加载完成,App层匹配页面显示并开始匹配
*/
export let onGameLoaded = function () {
console.log("---------------:" + game_version);
if (!DeviceUtil.IsMXGame) {
return;
}
let info = { GameVersion: game_version };
gameManager.onGameLoaded(JSON.stringify(info));
//记录游戏开始时间
game_start_time = Date.now();
cc.game.on("commonEventInterface", commonEventInterface_battle, this);
};
export let is_over: boolean = false;
/**
* !#en Close App layer matching interface
* !#zh 关闭App层匹配界面
*/
export let onGameCleanPosters = function () {
if (!DeviceUtil.IsMXGame) {
return;
}
gameManager.onGameCleanPosters();
};
/**
* !#en GameOver
* !#zh 游戏结束
*/
export let onBattleGameOver = function () {
if (!DeviceUtil.IsMXGame) {
return;
}
if (is_over) {
return;
}
is_over = true;
let myScore = 0;
let otherScore = 0;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (gameStore.player1Data.completeBlockArr[i][j] === 1) {
myScore++;
}
if (gameStore.player2Data.completeBlockArr[i][j] === 1) {
otherScore++;
}
}
}
let info = {
gameId: gameId_,
battleId: battleId_,
roomId: roomId_,
battle_info: {
currentscore: myScore,
oppoScore: otherScore,
winStatus: gameStore.winType,
numA: gameStore.selfMoveCount,
numB: gameStore.otherMoveCount,
numC: gameStore.createPropsNum,
numD: gameStore.usePauseSkillCount,
numE: gameStore.useSwapSkillCount,
numF: gameStore.useRandomSkillCount,
numG: gameStore.beUsedPauseSkillCount,
numH: gameStore.beUsedRandomSkillCount,
numI: gameStore.selfGetPropNum,
numJ: gameStore.otherGetPropNum,
oppoType: gameStore.isAI,
oppoUserID: gameStore.player2Data.id,
},
};
//!#en Quit the game report
//!#zh 退出游戏打点
/**********************************************************************************************/
let rInfo = {
roomID: battleId_,
playtime: Math.round((Date.now() - game_start_time) / 1000)
};
gameManager.onTrack("gameExit", JSON.stringify(rInfo));
/**********************************************************************************************/
//!#en This is a custom report and can be ignored
//!#zh 此为自定义打点,可忽略
const emojiClickedInfo = JSON.stringify(gameStore.expressionStatistic);
gameManager.onTrack("emojiClicked", emojiClickedInfo);
//!#en info is the reported data at the end of the game
//!#zh info是游戏结束的上报数据
gameManager.onBattleGameOver(JSON.stringify(info));
};
/**
* !#en General event interface
* !#zh 通用事件接口
* @param event_name 事件名
* @param info 信息
*/
export let commonEventInterface_battle = function (event_name: string, info: any) {
switch (event_name) {
case "backPressed": {
cc.game.emit("userGamePausedCall");
cc.game.emit("userPausedViewShowCall");
break;
}
case "screenOn": {
break;
}
case "screenOff": {
cc.game.emit("userGamePausedCall");
cc.game.emit("userPausedViewShowCall");
break;
}
case "pagePause": {
cc.game.emit("eventGamePausedCall");
cc.game.emit("eventMusicPausedCall");
break;
}
case "pageResume": {
cc.game.emit("eventGameResumeCall");
cc.game.emit("eventMusicResumeCall");
break;
}
case "userPresent": {
//解锁屏幕
break;
}
//!#en Battle data
//!#zh 对战数据
case "userMatched": {
battleInfo(info);
break;
}
}
};
/**
* !#en Battle data analysis
* !#zh 对战数据解析
* @param info
*/
export let battleInfo = (info: any) => {
console.log("battleinfo" + info)
let obj: info = JSON.parse(info);
setGameId(obj.gameId);
setBattleId(obj.battleId);
setRoomId(obj.roomId);
let selfUserId: string = obj.selfUserId; // 自己的 用户ID
let my_index = 0;
let other_index = 1;
if (obj.users[1].userId == selfUserId) {
my_index = 1;
other_index = 0;
}
gameStore.player1Data.setId(obj.users[my_index].playerId);
gameStore.player1Data.setNickName(obj.users[my_index].name);
gameStore.player1Data.setAvatar(obj.users[my_index].avatar);
gameStore.player2Data.setId(obj.users[other_index].playerId);
gameStore.player2Data.setNickName(obj.users[other_index].name);
gameStore.player2Data.setAvatar(obj.users[other_index].avatar);
//!#en Can get the other party's data, such as the skin used by the other party
//!#zh 可获取对方数据,如对方使用的皮肤
let playerData = obj.users[other_index].playerData;
if (playerData && playerData[conditionId.UseSkin]) {
let player2BlockSkin = playerData[conditionId.UseSkin].split("|")[0];
gameStore.setPlayer2BlockSkinId(Number(player2BlockSkin) % 100000);
} else {
gameStore.setPlayer2BlockSkinId(1);
}
//!#en websocket address
//!#zh websocket地址
SocketManager.instance.connecturl = obj.connectUrl;
//!#en game start report
//!#zh 游戏开始打点
let rInfo = {
roomID: battleId_,
};
gameManager.onTrack("gameStart", JSON.stringify(rInfo));
//!#en Close App layer matching interface,If there is a matching animation in the game, it can be called after this
//!#zh 关闭平台匹配页面,如游戏内有匹配动画,可在此之后调用
onGameCleanPosters();
UIManager.instance.OnMsg(MatchUI, "", null);
};
mx.d.ts
declare namespace gameManager {
declare function onGameLoaded(paramStr: string): void;
declare function onGameCleanPosters(): void;
declare function onTrack(eventName: string, paramStr: string): void;
declare function onBattleGameOver(paramStr: string): void;
declare function onGameStart(): void;
declare function onGameInit(): string;
}