MatchMaster/assets/Script/module/Config/GameConfig.ts

1401 lines
68 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { GAMEPLAY_ATLAS_PATHS } from "../Tool/GameplayAtlasFrames";
import { MiniGameSdk } from "../../Sdk/MiniGameSdk";
import { GameTool } from "../Tool/GameTool";
import BlockAssetManager from "../Tool/BlockAssetManager";
interface GameplayEntryPreparation {
startedAt: number;
downloads: Promise<boolean>;
release: () => void;
}
const { ccclass, property } = cc._decorator;
@ccclass('GameConfig')
export class GameConfig {
//所有控制信息都通过GameAppStart内控制
private static _instance: GameConfig = null;
static GAME_DATA: any[];
//关卡数据
//用户需要存储在本地的数据, 金币,关卡等级,体力值以及恢复,道具数量。
static CUSTOM_INFO: {
moveSpeed: number; //洪峰移动速度
waitTime: number; //洪峰冲击倒计时
fastPath: number; //最短路径
}[];
static TIME_INFO: {
waterSpeed: number[]; //洪峰速度
totalTime: number; //游戏总时长
waterTime: number[]; //洪峰来的倒计时
roadSpeed: number; //河道修筑速度
ReinforceSpeed: number; //加固时间速度
Xi_SoilSpeed: number;
};
//用于盛放埋点数据上传,每次上传后清空
static CLICK_DATA: {
type: number; //上传数据类型
success: boolean; //此局游戏正确与否
round: number; //回合数轮次
getScore: number; //本轮得分,失败为0分
cumulativeScore: number; //本剧游戏总计得分
mapId: string; //地图ID
difficulty: number; //地图难度
optimizedSteps: number; //关卡最短步数
usedSteps: number; //玩家修建总步数
stepList: any[]; //U、D、L、R X 息壤 F 加固
startTime: number; //从游戏开始到玩家操作的第一步截止时间 单位毫秒
submitTime: number; //从第一步操作到提交时间,如果未提交为-1 单位毫秒
duration: number; //游戏总用时(截止到提交) 单位毫秒
drawingBack: number; //后退次数
drawingReset: number; //清空次数
timer: number; //游戏倒计时剩余时长 秒
};
static TIP_ERR: string[]; //修筑失败错误提示
static BLOCK_INFO: {}[][];
//static WALL_INFO: ({ id: number; num: number; block: number; color: number; type: number; special: number; length: number; }[] | { id: number; num: number; block: number; color: number; type: number; special: number; }[])[];
static LEVEL_INFO: ({ id: string; map: number[]; risefall?: undefined; gap?: undefined; } | { id: string; map: number[]; risefall: { pos: cc.Vec2; color: number; }[]; gap?: undefined; } | { id: string; map: number[]; gap: cc.Vec2[]; risefall?: undefined; })[];
static WALL_INFO: (({ id: number; num: number; block: number; color: number; special: number; length: number; lock?: undefined; } | { id: number; num: number; block: number; color: number; special: number; length: number; lock: boolean; })[] | ({ id: number; num: number; block: number; color: number; special: number; length: number; freeze?: undefined; } | { id: number; num: number; block: number; color: number; special: number; length: number; freeze: number; })[])[];
static PROP_INFO: ({ pos1: { x: number; y: number; z: number; }; pos2: { x: number; y: number; z: number; }; pos3: { x: number; y: number; z: number; }; pos4: { x: number; y: number; z: number; }; pos5: { x: number; y: number; z: number; }; pos6: { x: number; y: number; z: number; }; } | { pos1: { x: number; y: number; z: number; }; pos2: { x: number; y: number; z: number; }; pos3: { x: number; y: number; z: number; }; pos4: { x: number; y: number; z: number; }; pos5: { x: number; y: number; z: number; }; pos6?: undefined; })[];
private static defaultNewLevel: any[] = [];
private static newPlayerNewLevel: any[] = [];
private static defaultNewGuide: any[] = [];
static get NEW_LEVEL(): any[] {
return this.isNewPlayerB() ? this.newPlayerNewLevel : this.defaultNewLevel;
}
static get NEW_GUIDE(): any[] {
return this.isNewPlayerB()
? this.defaultNewGuide.map(item => ({ ...item, level: this.getPropUnlockLevel(item.name) }))
: this.defaultNewGuide;
}
static PASS_CHECK: any;
static PASS_CHECK_OLD: any;
static PASS_RATE: any;
static MESSAGE_MODEL: any;
static LOCAL_CACHE_PREFIX = "level_cache_";
static MAX_LOCAL_LEVEL = 100;
// 上传 Block 下的 PNG、三张公共图集对应的 plist 和 version.json,不使用 Bundle 构建产物。
static BLOCK_IMAGE_BASE_URL = "https://cdn.pay.nika4games.com/remote/Block/";
// 首次启动且远程版本不可用时的默认值;后续以远程 version.json 为准。
static BLOCK_IMAGE_VERSION = "1.0.0";
static nextEndlessLevel = 0;
static locatePositionOnHome = false; // Win 入职按钮返回首页后定位一次。
private static loadedLevelNumber = 0;
private static levelLoadRequest = 0;
private static sceneLoadRequest = 0;
private static homeWarmupRequest = 0;
private static cancelBlockLoading: () => void = null;
private static gameplayScenePreload: Promise<void> = null;
private static gameplaySceneForegroundPreload: Promise<void> = null;
private static pendingEntryDownloadRelease: () => void = null;
static gameplayEntryStartedAt = 0;
// 仅本次启动有效;地图就绪即可完成首次进关,不等待弹窗实例。
static firstGameplayEntryComplete = false;
static firstGameplayEntryPending = false;
/** 仅合并正在进行的预加载,不能把历史完成标记当作永久有效的场景缓存。 */
static preloadGameplayScene(foreground = false): Promise<void> {
const key = foreground ? "gameplaySceneForegroundPreload" : "gameplayScenePreload";
if (this[key]) return this[key];
const request = this.timeGameplayStage(foreground ? "GameScene前台文件准备" : "首页GameScene预取",
() => new Promise<void>((resolve, reject) => {
const done = (error: Error) => error ? reject(error) : resolve();
const bundle = cc.assetManager.bundles.find(bundle => !!bundle.getSceneInfo("GameScene"));
if (!bundle) { reject(new Error("GameScene 所属 Bundle 尚未加载")); return; }
// 不等待首页的低优先级任务;引擎复用已下载文件,前台请求使用 scene 调度配置。
bundle.preloadScene("GameScene", { preset: "scene", priority: 10 }, done);
}));
this[key] = request;
const clear = () => {
if (this[key] === request) this[key] = null;
};
request.then(clear, clear);
return request;
}
static async timeGameplayStage<T>(stage: string, task: () => Promise<T>): Promise<T> {
const start = Date.now();
// console.log(`[进关耗时][${stage}] 开始`);
try {
const result = await task();
// console.log(`[进关耗时][${stage}] ${result === false ? "未就绪" : "完成"},独立耗时=${Date.now() - start}ms`);
return result;
} catch (error) {
// console.log(`[进关耗时][${stage}] 失败,独立耗时=${Date.now() - start}ms`, error);
throw error;
}
}
/** 点击进关即开始不依赖关卡 JSON 的任务,所有入口共用原有下载保障。 */
static beginGameplayEntryPreparation(): GameplayEntryPreparation {
const startedAt = Date.now();
this.gameplayEntryStartedAt = startedAt;
const previousRelease = this.takeEntryDownloadRelease();
const releaseHold = BlockAssetManager.instance.holdBackgroundDownloads();
if (previousRelease) previousRelease();
const release = () => {
releaseHold();
if (this.pendingEntryDownloadRelease === release) this.pendingEntryDownloadRelease = null;
};
this.pendingEntryDownloadRelease = release;
// console.log("[进关耗时] 开始进关准备(各并行阶段耗时不能相加)");
const downloads = this.timeGameplayStage("五个弹窗分包磁盘检查/下载",
() => GameTool.ensureGameplayPopupSubpackagesDownloaded()).catch(() => false);
// 不把文件预取作为门槛;必要资源就绪后 loadScene 立即正式加载并复用已有文件。
this.preloadGameplayScene(true).catch(error => cc.warn("场景文件预取失败,正式加载时重试", error));
return { startedAt, downloads, release };
}
/** 新 Map 接管自己的暂停凭证,旧 Map 销毁不能恢复新进关的后台派发。 */
static takeEntryDownloadRelease(): () => void {
const release = this.pendingEntryDownloadRelease;
this.pendingEntryDownloadRelease = null;
return release;
}
/** 首页仅用来判断能否启动自动预加载,不暂停或接管任何在途回调。 */
static isGameplayEntryPreparing(): boolean {
return !!this.pendingEntryDownloadRelease;
}
static shouldPrepareFirstGameplayEntry(): boolean {
const scene = cc.director.getScene();
return !this.firstGameplayEntryComplete && !!scene && scene.name === "HomeScene"
&& GameTool.shouldPreloadGameplayPopupInstances();
}
static getCurrentLevelBlockDefinitions(): any[] {
const blocks = this.BLOCK_INFO && this.BLOCK_INFO[0] ? this.BLOCK_INFO[0] : [];
const level: any = this.LEVEL_INFO && this.LEVEL_INFO[0];
return this.collectLevelBlockDefinitions(blocks, level);
}
private static collectLevelBlockDefinitions(blocks: any[], level: any): any[] {
const result = blocks.slice();
const gates = level && Array.isArray(level.spawnGates) ? level.spawnGates : [];
for (const gate of gates) {
const queue = gate && Array.isArray(gate.spawnQueue) ? gate.spawnQueue : [];
for (const item of queue) {
if (item && Array.isArray(item.members)) result.push(...item.members);
}
}
return result;
}
/** HomeScene 空闲预热:低内存 iOS 只落盘,高内存 iOS 和安卓直接创建纹理。 */
static warmupHomeBlockAssets(): Promise<boolean> {
const requestId = ++this.homeWarmupRequest;
const scene = cc.director.getScene();
const otherLevel = Number(this.GM_INFO.otherLevel) || 0;
const levelNumber = otherLevel > 0 ? otherLevel : Number(this.GM_INFO.level) + 1;
const isCurrent = () => requestId === this.homeWarmupRequest
&& cc.director.getScene() === scene
&& !!scene && scene.name === "HomeScene";
if (!isCurrent() || levelNumber < 1 || levelNumber > GameTool.MAX_NORMAL_LEVEL) {
return Promise.resolve(false);
}
return this.loadLevelFromBundle(levelNumber, otherLevel === 0).then(jsonData => {
if (!isCurrent()) return false;
const blockInfo = jsonData && jsonData.BLOCK_INFO && jsonData.BLOCK_INFO[0];
const levelInfo = jsonData && jsonData.LEVEL_INFO && jsonData.LEVEL_INFO[0];
if (!Array.isArray(blockInfo) || !levelInfo) {
throw new Error(`关卡${levelNumber}配置无效`);
}
const blocks = this.collectLevelBlockDefinitions(blockInfo, levelInfo);
if (GameTool.shouldPreloadGameplayPopupInstances()) {
return BlockAssetManager.instance.prepareWindow(blocks, {
currentLevel: levelNumber,
stage: "首页内存预热",
extraPaths: GAMEPLAY_ATLAS_PATHS,
homeWarmup: true,
}).then(ready => {
if (ready && isCurrent()) {
console.log(`[Block图片][首页内存预热] 当前关${levelNumber}完成`);
}
return ready && isCurrent();
});
}
return BlockAssetManager.instance.cacheWindowFiles(blocks, GAMEPLAY_ATLAS_PATHS);
}).catch(error => {
if (isCurrent()) cc.warn(`[Block图片][首页预热] 当前关${levelNumber}失败`, error);
return false;
});
}
/** 只准备当前关图片,不预读或加载下一关图片。 */
static prepareBlockWindow(onRemoteRequired?: () => void, stage = "进关"): Promise<boolean> {
const blockInfo = this.BLOCK_INFO && this.BLOCK_INFO[0];
const levelInfo = this.LEVEL_INFO && this.LEVEL_INFO[0];
if (!blockInfo || !this.loadedLevelNumber) return Promise.reject(new Error("关卡配置尚未就绪"));
const blocks = this.getCurrentLevelBlockDefinitions();
const currentLevel = this.loadedLevelNumber;
return BlockAssetManager.instance.prepareWindow(blocks,
{ onRemoteRequired, currentLevel, stage, extraPaths: GAMEPLAY_ATLAS_PATHS }).then(ready =>
ready && this.BLOCK_INFO[0] === blockInfo && this.LEVEL_INFO[0] === levelInfo);
}
/** 创建时不显示;仅远程图片调用 open。失效请求不能打开或关闭后续请求的 Loading。 */
static createBlockLoading(isCurrent: () => boolean): { open: () => void; close: () => void } {
if (this.cancelBlockLoading) this.cancelBlockLoading();
const scene = cc.director.getScene();
const canvas = cc.find("Canvas");
const controller: any = canvas && (canvas.getComponent("JiaZai") || canvas.getComponent("SceneManager"));
let opened = false;
let closed = false;
const close = () => {
if (closed) return;
closed = true;
if (opened && controller && cc.isValid(controller, true)) controller.closeLoad();
if (this.cancelBlockLoading === close) this.cancelBlockLoading = null;
};
this.cancelBlockLoading = close;
return {
open: () => {
if (!closed && !opened && isCurrent() && cc.director.getScene() === scene
&& controller && cc.isValid(controller, true)) {
opened = true;
controller.openLoad();
}
},
close
};
}
/** 所有正式进关入口都在弹窗分包及当前关图片就绪后才切换 GameScene。 */
static enterGameSceneWhenReady(time = 0, preparation?: GameplayEntryPreparation): void {
const id = ++this.sceneLoadRequest;
const scene = cc.director.getScene();
const blocks = this.BLOCK_INFO;
const isCurrent = () => id === this.sceneLoadRequest && cc.director.getScene() === scene && this.BLOCK_INFO === blocks;
const loading = this.createBlockLoading(isCurrent);
const firstEntry = this.shouldPrepareFirstGameplayEntry();
const entry = preparation || this.beginGameplayEntryPreparation();
const { release, startedAt } = entry;
if (firstEntry || !GameTool.areGameplayPopupSubpackagesDownloaded()) loading.open();
// 只等待磁盘分包与当前关图片,不等待后台场景预加载回调。
Promise.all([
entry.downloads,
this.timeGameplayStage("当前关方块+公共图集", () => this.prepareBlockWindow(loading.open)),
]).then(([popupReady, ready]) => {
if (!isCurrent()) {
loading.close();
release();
return;
}
if (!popupReady) {
loading.close();
release();
const missing = GameTool.getMissingGameplayPopupSubpackages();
this.showBlockLoadError(
new Error(`游戏弹窗分包下载失败: ${missing.join(", ")}`),
() => this.enterGameSceneWhenReady(time),
"游戏界面资源下载失败\n请检查网络,点击此处重试"
);
return;
}
if (!ready) {
loading.close();
release();
return;
}
// console.log(`[进关耗时][进关门槛就绪] 从开始累计=${Date.now() - startedAt}ms`);
loading.close();
if (firstEntry) {
const home = cc.find("Canvas").getComponent("JiaZai");
home.playGameEntryTransition(true);
}
const transitionStartedAt = Date.now();
setTimeout(() => {
if (!isCurrent()) {
release();
return;
}
const retainPopupBundles = !!scene && scene.name === "GameScene"
&& GameTool.beginGameplayPopupGameSceneReloadRetention();
// console.log(`[进关耗时][转场等待] 独立耗时=${Date.now() - transitionStartedAt}ms`);
const sceneStartedAt = Date.now();
// console.log("[进关耗时][GameScene正式加载及激活] 开始");
try {
if (firstEntry) this.firstGameplayEntryPending = GameTool.shouldPreloadGameplayPopupInstances();
const accepted = cc.director.loadScene("GameScene", (error: Error) => {
if (retainPopupBundles) {
GameTool.finishGameplayPopupGameSceneReloadRetention();
}
if (error) {
// console.log(`[进关耗时][GameScene正式加载及激活] 失败,独立耗时=${Date.now() - sceneStartedAt}ms`, error);
release();
if (isCurrent()) {
this.firstGameplayEntryPending = false;
this.showBlockLoadError(error, () => this.enterGameSceneWhenReady(time));
}
} else {
// console.log(`[进关耗时][GameScene正式加载及激活] 完成,独立耗时=${Date.now() - sceneStartedAt}ms,从开始累计=${Date.now() - startedAt}ms`);
}
});
if (accepted === false) {
release();
if (retainPopupBundles) GameTool.finishGameplayPopupGameSceneReloadRetention();
this.firstGameplayEntryPending = false;
this.showBlockLoadError(new Error("GameScene 切换未启动"), () => this.enterGameSceneWhenReady(time));
}
} catch (error) {
release();
if (firstEntry) this.firstGameplayEntryPending = false;
if (retainPopupBundles) {
GameTool.finishGameplayPopupGameSceneReloadRetention();
}
this.showBlockLoadError(error, () => this.enterGameSceneWhenReady(time));
}
}, firstEntry ? Math.max(time, 1000) : time);
}).catch(error => {
loading.close();
release();
if (isCurrent()) this.showBlockLoadError(error, () => this.enterGameSceneWhenReady(time));
});
}
static getLoadedBlockImagePaths(): string[] {
return BlockAssetManager.instance.getLoadedPaths();
}
/** 不推进关卡、不无限卡在转场;此提示不依赖任何远程图片。 */
static showBlockLoadError(error: any, retry: () => void,
messageText = "方块图片加载失败\n请检查网络,点击此处重试"): void {
cc.error(messageText, error);
const canvas = cc.find("Canvas");
if (!canvas || canvas.getChildByName("BlockLoadRetry")) return;
const overlay = new cc.Node("BlockLoadRetry");
overlay.parent = canvas;
overlay.zIndex = cc.macro.MAX_ZINDEX;
overlay.setContentSize(canvas.getContentSize());
overlay.addComponent(cc.BlockInputEvents);
const background = overlay.addComponent(cc.Graphics);
background.fillColor = cc.color(0, 0, 0, 225);
background.rect(-overlay.width / 2, -overlay.height / 2, overlay.width, overlay.height);
background.fill();
const message = new cc.Node("message");
message.parent = overlay;
const label = message.addComponent(cc.Label);
label.string = messageText;
label.fontSize = 32;
label.lineHeight = 48;
label.horizontalAlign = cc.Label.HorizontalAlign.CENTER;
overlay.once(cc.Node.EventType.TOUCH_END, () => {
overlay.removeFromParent();
overlay.destroy();
retry();
});
}
// 旧 layer_two 实验以 A 方案结束,旧 B 实现继续保持关闭;layer_2 现用于 Jungle 解锁实验。
static readonly LEGACY_LAYER_TWO_VARIANT_B_ENABLED = false;
static readonly JUNGLE_TREASURE_UNLOCK_LEVEL = 40;
static getJungleTreasureUnlockLevel(): number {
return this.JUNGLE_TREASURE_UNLOCK_LEVEL;
}
static isNewPlayerB(): boolean {
const assignment = this.GM_INFO.abTestAssignments && this.GM_INFO.abTestAssignments.layer_1;
return !!assignment && assignment.name === "new1_50" && assignment.enabled !== false
&& ["B", "2"].includes(String(assignment.group).toUpperCase());
}
static getLevelConfigPath(level: number, mainline: boolean = true): string {
const folder = mainline && this.isNewPlayerB() && level >= 1 && level <= 50 ? "Json2" : "Json";
return `${folder}/level${level}`;
}
static getPropUnlockLevel(prop: string): number {
if (prop === "hammer") return 8;
if (prop === "time") return this.isNewPlayerB() ? 14 : 11;
return this.isNewPlayerB() ? 18 : 16;
}
// 以下功能门槛均使用已通关数。
static getFeatureUnlockLevel(feature: string): number {
const levels = this.isNewPlayerB()
? { month: 20, pass: 20, daily: 35, winStreak: 50 }
: { month: 16, pass: 21, daily: 0, winStreak: 17 };
return levels[feature];
}
static isWinStreakUnlocked(): boolean {
return !this.isNewPlayerB() || this.GM_INFO.level >= 50;
}
static shouldShowWinStreakGuide(): boolean {
return !!this.GM_INFO.winStreakFirst && this.isWinStreakUnlocked()
&& (!this.isNewPlayerB() || this.GM_INFO.winStreak >= 10);
}
static canSettleCareer(): boolean {
return !this.isNewPlayerB() || this.GM_INFO.level > 15;
}
static TA: any;
static GE: any;
static CITY: { 河北省: boolean; 山西省: boolean; 辽宁省: boolean; 吉林省: boolean; 黑龙江省: boolean; 江苏省: boolean; 浙江省: boolean; 安徽省: boolean; 福建省: boolean; 江西省: boolean; 山东省: boolean; 河南省: boolean; 湖北省: boolean; 湖南省: boolean; 广东省: boolean; 海南省: boolean; 四川省: boolean; 贵州省: boolean; 云南省: boolean; 陕西省: boolean; 甘肃省: boolean; 青海省: boolean; 港澳台: boolean; 北京: boolean; 天津: boolean; 上海: boolean; 重庆: boolean; 内蒙古: boolean; 广西: boolean; 西藏: boolean; 宁夏: boolean; 新疆: boolean; };
static GM_INFO: {
// isEnd: false,
error_message: any[]; // 错误信息
mean_Time: number; //平均放箭速度
hp: number; //体力值
review: number; //复活次数
reviewBoom: number; //炸弹复活次数
reviewDoor: number; //门复活次数
reviewRevolving: number; //转盘复活次数
reviewLongAndShort: number; //长短期复活次数
currSeed: number; //用于随机数种子
openid: string; //微信用户唯一id
gameId: string; //游戏ID
userId: number; //用户ID
scode: string; //用户code,从网页后缀获取
username: string; //用户名称
useravatar: string; //用户头像地址
useravatarIcon: string; //用户头像
useravaterkuang: string; //用户头像框
useravatarCat: string; //用户猫
testId: string //测试ID
guide: boolean; //是否有引导
url: string; //访问域名
coin: number; //用户金币
film: number; //头像抽卡代币
catArr: any[]; //用户猫数组
isFromWucai: boolean; //本次进入是否来自五彩消消乐
wucai_type: number; //五彩账号迁移状态:-1未参与,0待领奖,1待选择,2/3已完成
wucai_preview: any; //状态1登录时返回的五彩脱敏数据
wucai_current_preview: any; //状态1登录时整理的本游戏进度预览
wucai_reward_popup_pending: boolean; //选择进度后,HomeScene 奖励弹窗待确认
jungleTreasureState?: any; //登录返回的丛林宝藏状态;未触发活动的用户不存在此属性
jungleTreasureServerNow?: number; //登录接口返回状态时的服务器时间
jungleTreasureAvailable?: boolean; //本次服务端读取是否存在可展示的丛林宝藏活动
pendingJungleSettlement?: any; //到期奖励已入账、等待客户端展示并确认的结算
success: boolean; //用户游戏成功与否
matchId: any; //用于埋点上传的ID
gameState: boolean; custom: number; //用于测试跳关卡
round: number; //回合数
level: number; //具体游戏内进行到第几步
stepTimeList: number; //整局游戏用时,由于涉及场景切换,数据需要保留
successList: any[]; //整局胜负
first: boolean; //是否首次进入游戏
score: number; //总得分
scale: number; //玩家总计成功点火数
allOutTradeNo: any[]; //订单号数组
min_Time: number; //体力恢复的剩余时间
freezeAmount: number; //冻结道具次数
hammerAmount: number; //锤子道具次数
magicAmount: number; //魔法棒道具次数
musicOpen: boolean; //音乐
effectOpen: boolean; //音效
vibrateOpen: boolean; //震动
coinnum: number; //每局的金币数
paid_user: boolean; //是否是付费用户
version: string; //版本号
shushu_DistinctId: string; //数数访客ID
shushu_AccountId: string; //数数账号ID
uid: string; //用户和后端唯一id
userPowerTime: number; //用户体力恢复时间
freezeFirst: boolean; //冻结道具第一次
hammerFirst: boolean; //锤子道具第一次
magicAFirst: boolean; //魔法棒道具第一次
winStreakFirst: boolean; //每次第一次连胜
hp_Max: number; //体力最大值
doubleCoin: number; //是否双倍
rewardAdCoin: number; //是否双倍
monthTime: number; //月卡时间
revive: number; //复活礼包购买次数
otherUid: string; //其他被帮助用户id
otherLevel: number; //其他被帮助用户等级
helpLevel: number; //帮助用户等级
iosShopOrder: string; //ios订单号商城
iosJungleOrder: string; //iOS 客服旧支付的丛林宝藏订单号
iosMonthOrder: string; //ios订单号月卡
iosReviveOrder: string; //ios订单号复活
iosStarterOrder: string; //ios订单号新手
iosPassCheckOrder: string; // ios通行证订单
starter_packTime: number; // 新手礼包截止时间,秒
starterPackServerOffset: number; // 服务端时间与本地时间差,毫秒
starterPackPurchased: boolean;
starterPackLastShownAt: number; // 最近一次实际弹出时间,毫秒
starterPackReactivatedDeadline: number; // 本次会话已确认的新周期截止时间,毫秒
wxFriend: boolean; //微信好友信息授权
wxUserInfo: boolean; //微信用户信息授权
winState: boolean; //是否延续连胜状态
getProgressLevel: number; //获取进度关卡
getProgress: number; //获取进度
getItemType: number; popPassCheck: boolean; // 弹窗通行证
passCheckActivate: boolean;
winStreak: number; //连胜
tasks: { levelPass: { value: number; target: number; state: number; }; share: { value: number; target: number; state: number; }; useEnergy: { value: number; target: number; state: number; }; useProp: { value: number; target: number; state: number; }; }; addLevel: number; //每日过关数
address: string; //用户城市信息
firstTime: number; //用户注册时间
longitude: string; //用户经度
cityRank: number; //城市排名
sceneValue: string; //当前场景值
shopDouble: { gold_1: boolean; gold_2: boolean; gold_3: boolean; gold_4: boolean; gold_5: boolean; gold_6: boolean; };
randomLevel: number;
endLevelNum: number; // 通关后 记录玩家随机游戏关卡数量
GameplayType: number; //游戏类型
canIos: boolean, //ios展示是否可以
iosCanPay: boolean, //ios是否支持支付
ge_ad_id: string, //广告ID
ge_creative_id: string, //创意ID
abTests: {
layer_one: number,
layer_two: number,
layer_three: number
}, //AB测试
abTestAssignments: { [key: string]: any }, // AB测试原始分组信息
};
static bgPosition: number;
//游戏内信息
static get Instance() {
if (this._instance == null) {
this._instance = new GameConfig();
}
return this._instance;
}
//getSeedRandom
static init(Authentication) {
//@ts-ignore
this.TA = null;
this.CLICK_init();
this.GM_INFO_init();
this.CITY_init();
this.LEVEL_INFO_init(false, 0, false);
this.bgPosition = 0;
var self = this;
//GAME_DATA 废弃了,暂时不删除以防后面修改回 一整局传一次
this.GAME_DATA = [
]
// if(!Authentication) self.Authentication();
}
static generateUUID(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// 版本比较函数
static compareVersion(v1: string, v2: string): number {
const arr1 = v1.split('.');
const arr2 = v2.split('.');
const len = Math.max(arr1.length, arr2.length);
for (let i = 0; i < len; i++) {
const num1 = parseInt(arr1[i] || '0', 10);
const num2 = parseInt(arr2[i] || '0', 10);
if (num1 > num2) {
return 1;
} else if (num1 < num2) {
return -1;
}
}
return 0;
}
static GM_INFO_SET(key, value) {
this.GM_INFO[key] = value;
}
static CLICK_init() {
this.CLICK_DATA =
{
type: 1, //上传数据类型
success: false, //此局游戏正确与否
round: 0, //回合数轮次
getScore: 0, //本轮得分,失败为0分
cumulativeScore: 0, //本剧游戏总计得分
mapId: "", //地图ID
difficulty: 0, //地图难度
optimizedSteps: 0, //关卡最短步数
usedSteps: 0, //玩家修建总步数
stepList: [], //U、D、L、R X 息壤 F 加固
startTime: -1, //从游戏开始到玩家操作的第一步截止时间 单位毫秒
submitTime: -1, //从第一步操作到提交时间,如果未提交为-1 单位毫秒
duration: 0, //游戏总用时(截止到提交) 单位毫秒 如果未他移交则为时间上限
drawingBack: 0, //后退次数
drawingReset: 0, //清空次数
timer: 0 //测评倒计时剩余时间 去秒
}
}
static CLICK_SET(key, value) {
this.CLICK_DATA[key] = value;
}
//数据备用
static GM_INFO_init() {
this.GM_INFO = {
// isEnd: false,
error_message: [], // 错误信息
mean_Time: 0, //平均放箭速度
hp: 5, //体力值
review: 0, //复活次数
reviewBoom: 0, //炸弹复活次数
reviewDoor: 0, //门复活次数
reviewRevolving: 0, //转盘复活次数
reviewLongAndShort: 0, //长短期复活次数
currSeed: 200000, //用于随机数种子
openid: "", //微信用户唯一id
gameId: "100001", //游戏ID
userId: 0, //用户ID
scode: "", //用户code,从网页后缀获取
username: "user", //用户名称
useravatar: "", //用户头像地址
useravatarIcon: "icon_0", //用户头像
useravaterkuang: "kuang_1", //用户头像框
useravatarCat: "cat_1", //用户头像框
guide: true, //是否有引导
url: "https://api.sparkus.cn",//访问域名
coin: 0, //用户金币
film: 0, //头像抽卡代币(以服务端返回值为准)
catArr: [1, 2, 3], //已拥有猫咪(登录返回,首页抽猫红点本地判断使用)
isFromWucai: false, //本次进入是否来自五彩消消乐
wucai_type: -1, //五彩账号迁移状态
wucai_preview: null, //五彩账号脱敏预览
wucai_current_preview: null,//本游戏进度预览
wucai_reward_popup_pending: false,//五彩迁移奖励弹窗待确认
pendingJungleSettlement: null,//丛林宝藏到期奖励待展示结算
success: false, //用户游戏成功与否
matchId: null, //用于埋点上传的ID
gameState: false,
custom: 0, //用于测试跳关卡
round: 0, //回合数
level: 0, //具体游戏内进行到第几步
stepTimeList: 0, //整局游戏用时,由于涉及场景切换,数据需要保留
successList: [], //整局胜负
first: false, //是否首次进入游戏
score: 0, //总得分
scale: 1, //玩家总计成功点火数
allOutTradeNo: [], //订单号数组
min_Time: 0, //体力恢复的剩余时间
freezeAmount: 0, //冻结道具次数
hammerAmount: 0, //锤子道具次数
magicAmount: 0, //魔法棒道具次数
musicOpen: true, //音乐
effectOpen: true, //音效
vibrateOpen: true, //震动
coinnum: 0, //每局的金币数
paid_user: false, //是否是付费用户
version: "1.0.51", //版本号
shushu_DistinctId: "", //数数访客ID
shushu_AccountId: "", //数数账号ID
uid: "", //用户和后端唯一id
userPowerTime: 0, //用户体力恢复时间
freezeFirst: false, //冻结道具第一次
hammerFirst: false, //锤子道具第一次
magicAFirst: false, //魔法棒道具第一次
winStreakFirst: false, //每次第一次连胜
hp_Max: 5, //体力最大值
doubleCoin: 1, //是否双倍
rewardAdCoin: 1, //是否双倍
monthTime: 0, //月卡时间
revive: 0, //复活礼包购买次数
otherUid: "", //其他被帮助用户id
otherLevel: 0, //其他被帮助用户等级
helpLevel: 0, //帮助用户等级
iosShopOrder: "", //ios订单号商城
iosJungleOrder: "", //iOS 客服旧支付的丛林宝藏订单号
iosMonthOrder: "", //ios订单号月卡
iosReviveOrder: "", //ios订单号复活
iosStarterOrder: "", //ios订单号新手
iosPassCheckOrder: "", // ios通行证订单
starter_packTime: 0, // 新手礼包截止时间
starterPackServerOffset: 0,
starterPackPurchased: false,
starterPackLastShownAt: 0,
starterPackReactivatedDeadline: 0,
wxFriend: false, //微信好友信息授权
wxUserInfo: false, //微信用户信息授权
winState: false, //是否延续连胜状态
getProgressLevel: 1, //获取进度关卡
getProgress: 0, //获取进度
getItemType: 2,
popPassCheck: false, // 弹窗通行证
passCheckActivate: false,
winStreak: 0, //连胜
tasks: { levelPass: { value: 0, target: 0, state: 0 }, share: { value: 0, target: 0, state: 0 }, useEnergy: { value: 0, target: 0, state: 0 }, useProp: { value: 0, target: 0, state: 0 } },
addLevel: 0, //每日过关数
address: "", //用户城市信息
firstTime: 0, //用户注册时间
longitude: "", //用户经度
cityRank: 99, //城市排名
sceneValue: "", //当前场景值
shopDouble: {
"gold_1": false,
"gold_2": false,
"gold_3": false,
"gold_4": false,
"gold_5": false,
"gold_6": false
},
randomLevel: 0,
endLevelNum: 1,
testId: "", //测试ID
GameplayType: 0, // 0 正常模式, 1无尽模式
canIos: true, //ios展示是否可以
iosCanPay: false, //ios是否支持支付
ge_ad_id: "", //广告ID
ge_creative_id: "", //广告创意ID
abTests: {
layer_one: 0,
layer_two: 0,
layer_three: 0
}, //AB测试
abTestAssignments: {},
};
// this.setCode(this.getKey("scode"));
// this.GM_INFO.level = 0;
cc.resources.load("Json/NEW_LEVEL", (err: any, res: cc.JsonAsset) => {
if (err) {
console.error("加载 NEW_LEVEL.JSON 失败:", err);
return;
}
const newLevelData = res.json;
this.defaultNewLevel = newLevelData.NEW_LEVEL;
// console.log("____________________配置", this.NEW_LEVEL);
// 可以根据需求对 newLevelData 进行处理
// //console.log("NEW_LEVEL.JSON 加载成功:", newLevelData);
})
cc.resources.load("Json/NEW_LEVEL2", (err: any, res: cc.JsonAsset) => {
if (err) {
console.error("加载 NEW_LEVEL2.JSON 失败:", err);
return;
}
this.newPlayerNewLevel = res.json.NEW_LEVEL;
});
cc.resources.load("Json/NEW_GUIDE", (err: any, res: cc.JsonAsset) => {
if (err) {
console.error("加载 NEW_GUIDE.JSON 失败:", err);
return;
}
const newLevelData = res.json;
this.defaultNewGuide = newLevelData.NEW_GUIDE;
// 可以根据需求对 newLevelData 进行处理
// //console.log("NEW_GUIDE.JSON 加载成功:", newLevelData);
})
cc.resources.load("Json/PASS_CHECK", (err: any, res: cc.JsonAsset) => {
if (err) {
console.error("加载 PASS_CHECK.JSON 失败:", err);
return;
}
const newLevelData = res.json;
cc.resources.load("Json/PASS_CHECK_OLD", (oldError: any, oldRes: cc.JsonAsset) => {
if (oldError) {
console.error("加载 PASS_CHECK_OLD.JSON 失败:", oldError);
return;
}
this.PASS_CHECK_OLD = oldRes.json.Sheet1;
this.PASS_CHECK = newLevelData.Sheet1;
});
// 可以根据需求对 newLevelData 进行处理
// //console.log("PASS_CHECK.JSON 加载成功:", newLevelData);
})
cc.resources.load("Json/PASS_RATE", (err: any, res: cc.JsonAsset) => {
if (err) {
console.error("加载 PASS_RATE.JSON 失败:", err);
return;
}
const newLevelData = res.json;
this.PASS_RATE = newLevelData;
})
cc.resources.load("Json/MESSAGE_MODEL", (err: any, res: cc.JsonAsset) => {
if (err) {
console.error("加载 MESSAGE_MODEL.JSON 失败:", err);
return;
}
const newLevelData = res.json;
this.MESSAGE_MODEL = newLevelData;
})
cc.fx.GameConfig.GM_INFO.testId = "orm8I7N10NSQdAhN4LP04n8UP56I";
}
//原有版本
static LEVEL_INFO_init(type, time, otherLevel, endless = false) {
// 示例 围墙会根据缺的地块自动生成
// 带缺口 {"id":"1006","map":[10,11],"gap":[cc.v2(4,9),cc.v2(5,9)]},
// 带升降地块 {"id":"1004","map":[7,8],"risefall":[{pos:cc.v2(5,4),color:2},{pos:cc.v2(5,5),color:5}]},
// 如果普通的就 {"id":"1001","map":[6,7]}, 这个样子就可以了
var self = this;
const requestId = ++this.levelLoadRequest;
this.sceneLoadRequest++;
const previousEntryRelease = this.takeEntryDownloadRelease();
if (previousEntryRelease) previousEntryRelease();
if (this.cancelBlockLoading) this.cancelBlockLoading();
let name = null;
let levelNumber: number;
if (endless) {
let level = 0;
if (!cc.fx.GameConfig.GM_INFO.randomLevel || cc.fx.GameConfig.GM_INFO.randomLevel <= 0) {
cc.fx.GameConfig.GM_INFO.randomLevel = cc.fx.GameTool.getNextLevel();
}
level = cc.fx.GameConfig.GM_INFO.randomLevel;
levelNumber = level;
name = this.getLevelConfigPath(levelNumber, false);
console.log("无尽模式关卡", level);
cc.fx.GameConfig.GM_INFO.GameplayType = 1;
} else {
if (cc.fx.GameTool.maxLevel() && otherLevel == false) {
// MiniGameSdk.API.showToast("关卡每周更新,敬请期待");
// cc.fx.GameTool.requestSubscribe();
console.log("关卡更新提示")
return;
}
levelNumber = cc.fx.GameConfig.GM_INFO.level + 1;
if (cc.fx.GameConfig.GM_INFO.otherLevel > 0) {
console.log("进入特殊帮助关卡,可越过自己关卡等级");
levelNumber = cc.fx.GameConfig.GM_INFO.otherLevel;
}
name = this.getLevelConfigPath(levelNumber, !cc.fx.GameConfig.GM_INFO.otherLevel);
}
const scene = cc.director.getScene();
const isCurrent = () => requestId === this.levelLoadRequest && (!type || cc.director.getScene() === scene);
const firstEntryLoading = type && this.shouldPrepareFirstGameplayEntry() ? this.createBlockLoading(isCurrent) : null;
if (firstEntryLoading) firstEntryLoading.open();
const preparation = type ? this.beginGameplayEntryPreparation() : null;
const configStartedAt = Date.now();
// console.log(`[进关耗时][${name}/custom分包] 开始`);
let bundleName = "custom"; // 替换为实际的分包名称
cc.assetManager.loadBundle(bundleName, { priority: 10 }, (err: Error, bundle: cc.AssetManager.Bundle) => {
// console.log(`[进关耗时][${name}/custom分包] ${err ? "失败" : "完成"},独立耗时=${Date.now() - configStartedAt}ms`);
if (!isCurrent()) { if (preparation) preparation.release(); return; }
if (err) {
if (preparation) preparation.release();
if (firstEntryLoading) firstEntryLoading.close();
if (type) this.showBlockLoadError(err, () => this.LEVEL_INFO_init(type, time, otherLevel, endless));
return;
}
const jsonStartedAt = Date.now();
// console.log(`[进关耗时][${name}/JSON] 开始`);
cc.assetManager.loadAny({ path: name, type: cc.JsonAsset, bundle: bundleName }, { priority: 10 }, (err: Error, res: cc.JsonAsset) => {
// console.log(`[进关耗时][${name}/JSON] ${err ? "失败" : "完成"},独立耗时=${Date.now() - jsonStartedAt}ms`);
if (!isCurrent()) { if (preparation) preparation.release(); return; }
if (err) {
if (preparation) preparation.release();
if (firstEntryLoading) firstEntryLoading.close();
if (bundle.getInfoWithPath(name, cc.JsonAsset)) {
if (type) this.showBlockLoadError(err, () => this.LEVEL_INFO_init(type, time, otherLevel, endless));
return;
}
console.log("______________没有这个关卡:", name);
cc.fx.GameTool.addLevel(null, null, null);
if (endless) {
cc.fx.GameConfig.GM_INFO.randomLevel = cc.fx.GameConfig.GM_INFO.randomLevel + 1;
cc.fx.GameConfig.LEVEL_INFO_init(type, time, false, true);
} else {
self.LEVEL_INFO_init(type, time, false);
}
return;
}
self.applyLevelData(res.json, type, time, levelNumber, preparation);
});
});
//道具位置信息
this.PROP_INFO = [
{
"pos1": { "x": -66, "y": 60, "z": 0 },
"pos2": { "x": -19, "y": 36, "z": 0 },
"pos3": { "x": -34.362, "y": 13.246, "z": 0 },
"pos4": { "x": -17, "y": 12, "z": 0 },
"pos5": { "x": -85, "y": 70, "z": 0 },
"pos6": { "x": -5, "y": 3, "z": 0 },
},
{
"pos1": { "x": -126, "y": 61, "z": 0 },
"pos2": { "x": -25.792, "y": 34.675, "z": 0 },
"pos3": { "x": -94.792, "y": 21.675, "z": 0 },
"pos4": { "x": -20, "y": 13, "z": 0 },
"pos5": { "x": -140, "y": 68, "z": 0 },
"pos6": { "x": -2, "y": 0, "z": 0 },
},
{
"pos1": { "x": -67, "y": 122, "z": 0 },
"pos2": { "x": -20, "y": 94, "z": 0 },
"pos3": { "x": -34.792, "y": 23.675, "z": 0 },
"pos4": { "x": -14, "y": 24, "z": 0 },
"pos5": { "x": -84, "y": 128, "z": 0 },
"pos6": { "x": -5, "y": 3, "z": 0 },
},
{
"pos1": { "x": -178, "y": 61, "z": 0 },
"pos2": { "x": -34.792, "y": 37.675, "z": 0 },
"pos3": { "x": -150, "y": 23.675, "z": 0 },
"pos4": { "x": -22, "y": 16, "z": 0 },
"pos5": { "x": -200, "y": 67, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -63, "y": 178, "z": 0 },
"pos2": { "x": -17.792, "y": 166.675, "z": 0 },
"pos3": { "x": -31.792, "y": 33.675, "z": 0 },
"pos4": { "x": -14, "y": 37, "z": 0 },
"pos5": { "x": -78, "y": 182, "z": 0 },
"pos6": { "x": 0, "y": 2, "z": 0 },
},
{
"pos1": { "x": -123, "y": 124, "z": 0 },
"pos2": { "x": -25.792, "y": 99.675, "z": 0 },
"pos3": { "x": -97.792, "y": 27.675, "z": 0 },
"pos4": { "x": -27, "y": 19, "z": 0 },
"pos5": { "x": -135, "y": 127, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -64, "y": 178, "z": 0 },
"pos2": { "x": -24.792, "y": 275.675, "z": 0 },
"pos3": { "x": -31.792, "y": 35.675, "z": 0 },
"pos4": { "x": -7, "y": 39, "z": 0 },
"pos5": { "x": -77, "y": 188, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -178, "y": 186, "z": 0 },
"pos2": { "x": -31.792, "y": 163.675, "z": 0 },
"pos3": { "x": -33.792, "y": 34.675, "z": 0 },
"pos4": { "x": -18, "y": 30, "z": 0 },
"pos5": { "x": -200, "y": 192, "z": 0 },
"pos6": { "x": 0, "y": 5, "z": 0 },
},
{
"pos1": { "x": -186, "y": 178, "z": 0 },
"pos2": { "x": -25.792, "y": 38.675, "z": 0 },
"pos3": { "x": -153.792, "y": 34.675, "z": 0 },
"pos4": { "x": -23, "y": 14, "z": 0 },
"pos5": { "x": -200, "y": 185, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -183, "y": 64, "z": 0 },
"pos2": { "x": -37.792, "y": 37.675, "z": 0 },
"pos3": { "x": -36.792, "y": 26.675, "z": 0 },
"pos4": { "x": -24, "y": 17, "z": 0 },
"pos5": { "x": -212, "y": 74, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -65, "y": 177, "z": 0 },
"pos2": { "x": 93.208, "y": 276.675, "z": 0 },
"pos3": { "x": -33.792, "y": 34.675, "z": 0 },
"pos4": { "x": 3, "y": 31, "z": 0 },
"pos5": { "x": -80, "y": 190, "z": 0 },
"pos6": { "x": 0, "y": 3, "z": 0 },
},
{
"pos1": { "x": 58, "y": 179, "z": 0 },
"pos2": { "x": 205.225, "y": 154.034, "z": 0 },
"pos3": { "x": -29.642, "y": 25.691, "z": 0 },
"pos4": { "x": 7.218, "y": 29.765, "z": 0 },
"pos5": { "x": 45, "y": 185, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -68, "y": 182, "z": 0 },
"pos2": { "x": -25.792, "y": 37.675, "z": 0 },
"pos3": { "x": -35.792, "y": 33.675, "z": 0 },
"pos4": { "x": -14, "y": 12, "z": 0 },
"pos5": { "x": -82, "y": 190, "z": 0 },
"pos6": { "x": -2, "y": 1, "z": 0 },
},
{
"pos1": { "x": -184, "y": 62, "z": 0 },
"pos2": { "x": -35.792, "y": 36.675, "z": 0 },
"pos3": { "x": -271.792, "y": 24.675, "z": 0 },
"pos4": { "x": -17, "y": 20, "z": 0 },
"pos5": { "x": -200, "y": 72, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -62, "y": 175, "z": 0 },
"pos2": { "x": 87.208, "y": 164.675, "z": 0 },
"pos3": { "x": -31.792, "y": 35.675, "z": 0 },
"pos4": { "x": -6, "y": 24, "z": 0 },
"pos5": { "x": -79, "y": 172, "z": 0 },
"pos6": { "x": 0, "y": 5, "z": 0 },
},
{
"pos1": { "x": -184, "y": 72, "z": 0 },
"pos2": { "x": -33.792, "y": 38.675, "z": 0 },
"pos3": { "x": -154.792, "y": 29.675, "z": 0 },
"pos4": { "x": -29, "y": 16, "z": 0 },
"pos5": { "x": -201, "y": 85, "z": 0 },
"pos6": { "x": -1, "y": 3, "z": 0 },
},
{
"pos1": { "x": -64, "y": 181, "z": 0 },
"pos2": { "x": 95.208, "y": 155.675, "z": 0 },
"pos3": { "x": -30.792, "y": 36.675, "z": 0 },
"pos4": { "x": -12, "y": 32, "z": 0 },
"pos5": { "x": -78, "y": 190, "z": 0 },
"pos6": { "x": 0, "y": 3, "z": 0 },
},
{
"pos1": { "x": -65, "y": 178, "z": 0 },
"pos2": { "x": -21.792, "y": 156.675, "z": 0 },
"pos3": { "x": -31.792, "y": 37.675, "z": 0 },
"pos4": { "x": -12, "y": 32, "z": 0 },
"pos5": { "x": -78, "y": 188, "z": 0 },
"pos6": { "x": 0, "y": 2, "z": 0 },
},
{
"pos1": { "x": -62, "y": 183, "z": 0 },
"pos2": { "x": 88.208, "y": 162.675, "z": 0 },
"pos3": { "x": -29.792, "y": 41.675, "z": 0 },
"pos4": { "x": -12, "y": 18, "z": 0 },
"pos5": { "x": -80, "y": 188, "z": 0 },
"pos6": { "x": -4, "y": 2, "z": 0 },
},
{
"pos1": { "x": -67, "y": 80, "z": 0 },
"pos2": { "x": -26.792, "y": 32.675, "z": 0 },
"pos3": { "x": -34.792, "y": 23.675, "z": 0 },
"pos4": { "x": -12, "y": 18, "z": 0 },
"pos5": { "x": -84, "y": 90, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -184, "y": 80, "z": 0 },
"pos2": { "x": -25.792, "y": 34.675, "z": 0 },
"pos3": { "x": -155.792, "y": 25.675, "z": 0 },
"pos4": { "x": -18, "y": 26, "z": 0 },
"pos5": { "x": -196, "y": 96, "z": 0 },
"pos6": { "x": 0, "y": 0, "z": 0 },
},
{
"pos1": { "x": -62, "y": 160, "z": 0 },
"pos2": { "x": 95.208, "y": 158.675, "z": 0 },
"pos3": { "x": -33.792, "y": 29.675, "z": 0 },
"pos4": { "x": -18, "y": 26, "z": 0 },
"pos5": { "x": -78, "y": 170, "z": 0 },
"pos6": { "x": 0, "y": 2, "z": 0 },
},
{
"pos1": { "x": -68, "y": 160, "z": 0 },
"pos2": { "x": -25.792, "y": 156.675, "z": 0 },
"pos3": { "x": -35.792, "y": 27.675, "z": 0 },
"pos4": { "x": -25, "y": 40, "z": 0 },
"pos5": { "x": -82, "y": 170, "z": 0 },
"pos6": { "x": -2, "y": 2, "z": 0 },
}
];
// this.PROP_INFO = [{"pos1": {"x": -60,"y": 60,"z": 0},"pos2": {"x": -16.442,"y": 30,"z": 0},"pos3": {"x": -34.362,"y": 13.246,"z": 0},"pos4": {"x": -17,"y": 12,"z": 0}},{"pos1": {"x": -126,"y": 63,"z": 0},"pos2": {"x": -25.792,"y": 34.675,"z": 0},"pos3": {"x": -94.792,"y": 21.675,"z": 0},"pos4": {"x": -20,"y": 13,"z": 0}},{"pos1": {"x": -60,"y": 125,"z": 0},"pos2": {"x": -12.792,"y": 92.675,"z": 0},"pos3": {"x": -34.792,"y": 23.675,"z": 0},"pos4": {"x": -14,"y": 24,"z": 0}},{"pos1": {"x": -185,"y": 63,"z": 0},"pos2": {"x": -34.792,"y": 37.675,"z": 0},"pos3": {"x": -154.792,"y": 23.675,"z": 0},"pos4": {"x": -22,"y": 16,"z": 0}},{"pos1": {"x": -57,"y": 178,"z": 0},"pos2": {"x": -17.792,"y": 166.675,"z": 0},"pos3": {"x": -31.792,"y": 33.675,"z": 0},"pos4": {"x": -14,"y": 37,"z": 0}},{"pos1": {"x": -123,"y": 127,"z": 0},"pos2": {"x": -25.792,"y": 99.675,"z": 0},"pos3": {"x": -97.792,"y": 27.675,"z": 0},"pos4": {"x": -27,"y": 19,"z": 0}},{"pos1": {"x": -62,"y": 181,"z": 0},"pos2": {"x": -24.792,"y": 275.675,"z": 0},"pos3": {"x": -31.792,"y": 35.675,"z": 0},"pos4": {"x": -7,"y": 39,"z": 0}},{"pos1": {"x": -181,"y": 180,"z": 0},"pos2": {"x": -31.792,"y": 163.675,"z": 0},"pos3": {"x": -33.792,"y": 34.675,"z": 0},"pos4": {"x": -18,"y": 30,"z": 0}},{"pos1": {"x": -182,"y": 182,"z": 0},"pos2": {"x": -25.792,"y": 38.675,"z": 0},"pos3": {"x": -153.792,"y": 34.675,"z": 0},"pos4": {"x": -23,"y": 14,"z": 0}},{"pos1": {"x": -186,"y": 61,"z": 0},"pos2": {"x": -37.792,"y": 37.675,"z": 0},"pos3": {"x": -36.792,"y": 26.675,"z": 0},"pos4": {"x": -24,"y": 17,"z": 0}},{"pos1": {"x": -62,"y": 177,"z": 0},"pos2": {"x": 93.208,"y": 276.675,"z": 0},"pos3": {"x": -33.792,"y": 34.675,"z": 0},"pos4": {"x": 3,"y": 31,"z": 0}},{"pos1": {"x": 58,"y": 179,"z": 0},"pos2": {"x": 205.225,"y": 154.034,"z": 0},"pos3": {"x": -29.642,"y": 25.691,"z": 0},"pos4": {"x": 7.218,"y": 29.765,"z": 0}},{"pos1": {"x": -57,"y": 182,"z": 0},"pos2": {"x": -25.792,"y": 37.675,"z": 0},"pos3": {"x": -35.792,"y": 33.675,"z": 0},"pos4": {"x": -14,"y": 12,"z": 0}},{"pos1": {"x": -180,"y": 62,"z": 0},"pos2": {"x": -35.792,"y": 36.675,"z": 0},"pos3": {"x": -271.792,"y": 24.675,"z": 0},"pos4": {"x": -17,"y": 20,"z": 0}},{"pos1": {"x": -62,"y": 178,"z": 0},"pos2": {"x": 87.208,"y": 164.675,"z": 0},"pos3": {"x": -31.792,"y": 35.675,"z": 0},"pos4": {"x": -6,"y": 24,"z": 0}},{"pos1": {"x": -176,"y": 60,"z": 0},"pos2": {"x": -33.792,"y": 38.675,"z": 0},"pos3": {"x": -154.792,"y": 29.675,"z": 0},"pos4": {"x": -29,"y": 16,"z": 0}},{"pos1": {"x": -60,"y": 181,"z": 0},"pos2": {"x": 95.208,"y": 155.675,"z": 0},"pos3": {"x": -30.792,"y": 36.675,"z": 0},"pos4": {"x": -12,"y": 32,"z": 0}},{"pos1": {"x": -63,"y": 178,"z": 0},"pos2": {"x": -21.792,"y": 156.675,"z": 0},"pos3": {"x": -31.792,"y": 37.675,"z": 0},"pos4": {"x": -12,"y": 32,"z": 0}},{"pos1": {"x": -60,"y": 183,"z": 0},"pos2": {"x": 88.208,"y": 162.675,"z": 0},"pos3": {"x": -29.792,"y": 41.675,"z": 0},"pos4": {"x": -12,"y": 18,"z": 0}},{"pos1": {"x": -64,"y": 58,"z": 0},"pos2": {"x": -26.792,"y": 32.675,"z": 0},"pos3": {"x": -34.792,"y": 23.675,"z": 0},"pos4": {"x": -12,"y": 18,"z": 0}},{"pos1": {"x": -184,"y": 62,"z": 0},"pos2": {"x": -25.792,"y": 34.675,"z": 0},"pos3": {"x": -155.792,"y": 25.675,"z": 0},"pos4": {"x": -18,"y": 26,"z": 0}},{"pos1": {"x": -57,"y": 190,"z": 0},"pos2": {"x": 95.208,"y": 158.675,"z": 0},"pos3": {"x": -33.792,"y": 29.675,"z": 0},"pos4": {"x": -18,"y": 26,"z": 0}},{"pos1": {"x": -71,"y": 184,"z": 0},"pos2": {"x": -25.792,"y": 156.675,"z": 0},"pos3": {"x": -35.792,"y": 27.675,"z": 0},"pos4": {"x": -25,"y": 40,"z": 0}}];
}
/**
* 检查关卡是否在本地缓存中
*/
static isLevelInLocalCache(level: number): boolean {
if (level <= this.MAX_LOCAL_LEVEL) {
return true; // 前100关在本地bundle中
}
// 检查本地存储中是否有缓存
const cacheKey = this.LOCAL_CACHE_PREFIX + level;
const cachedData = cc.sys.localStorage.getItem(cacheKey);
return cachedData !== null && cachedData !== undefined;
}
/**
* 将关卡数据保存到本地缓存
*/
static saveLevelToCache(level: number, jsonData: any): void {
if (level <= this.MAX_LOCAL_LEVEL) {
return; // 前100关不需要缓存
}
const cacheKey = this.LOCAL_CACHE_PREFIX + level;
try {
cc.sys.localStorage.setItem(cacheKey, JSON.stringify(jsonData));
console.log(`关卡${level}数据已缓存到本地`);
} catch (error) {
console.error(`缓存关卡${level}数据失败:`, error);
}
}
/**
* 从本地缓存获取关卡数据
*/
static getLevelFromCache(level: number): any {
if (level <= this.MAX_LOCAL_LEVEL) {
return null; // 前100关从bundle加载
}
const cacheKey = this.LOCAL_CACHE_PREFIX + level;
try {
const cachedData = cc.sys.localStorage.getItem(cacheKey);
if (cachedData) {
console.log(`从本地缓存加载关卡${level}`);
return JSON.parse(cachedData);
}
} catch (error) {
console.error(`读取关卡${level}缓存失败:`, error);
}
return null;
}
/**
* 从CDN加载关卡数据
*/
static loadLevelFromCDN(level: number): Promise<any> {
return new Promise((resolve, reject) => {
const cdnBaseUrl = "http://cdn.pay.nika4games.com/resources/json/";
const cdnUrl = cdnBaseUrl + `level${level}.json`;
console.log(`从CDN加载关卡${level}:`, cdnUrl);
fetch(cdnUrl)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(jsonData => {
// 保存到本地缓存
this.saveLevelToCache(level, jsonData);
resolve(jsonData);
})
.catch(error => {
console.error(`CDN加载关卡${level}失败:`, error);
reject(error);
});
});
}
/**
* 从本地bundle加载关卡数据
*/
static loadLevelFromBundle(level: number, mainline: boolean = true): Promise<any> {
return new Promise((resolve, reject) => {
const bundleName = "custom";
const name = this.getLevelConfigPath(level, mainline);
cc.assetManager.loadBundle(bundleName, { priority: 10 }, (err: Error, bundle: cc.AssetManager.Bundle) => {
if (err) {
reject(new Error(`加载分包失败: ${err.message}`));
return;
}
cc.assetManager.loadAny({ path: name, type: cc.JsonAsset, bundle: bundleName }, { priority: 10 }, (err: Error, res: cc.JsonAsset) => {
if (err) {
reject(new Error(`加载关卡资源失败: ${err.message}`));
return;
}
resolve(res.json);
});
});
});
}
//新的CDN版本
// static LEVEL_INFO_init(type, time, otherLevel, endless = false) {
// // ... existing code ...
// let name = null;
// let levelNumber = 0;
// if (endless) {
// let level = 0;
// if (!cc.fx.GameConfig.GM_INFO.randomLevel || cc.fx.GameConfig.GM_INFO.randomLevel <= 0) {
// cc.fx.GameConfig.GM_INFO.randomLevel = cc.fx.GameTool.getNextLevel();
// }
// level = cc.fx.GameConfig.GM_INFO.randomLevel;
// levelNumber = level;
// name = "Json/level" + level;
// console.log("无尽模式关卡", level);
// cc.fx.GameConfig.GM_INFO.GameplayType = 1;
// } else {
// if (cc.fx.GameTool.maxLevel() && otherLevel == false) {
// console.log("关卡更新提示")
// return;
// }
// levelNumber = cc.fx.GameConfig.GM_INFO.level + 1;
// if (cc.fx.GameConfig.GM_INFO.otherLevel > 0) {
// console.log("进入特殊帮助关卡,可越过自己关卡等级");
// levelNumber = cc.fx.GameConfig.GM_INFO.otherLevel;
// }
// name = "Json/level" + levelNumber;
// }
// // 智能加载关卡数据
// this.loadLevelDataSmart(levelNumber, name, type, time, endless, otherLevel);
// }
/**
* 智能加载关卡数据
*/
static loadLevelDataSmart(levelNumber: number, name: string, type: any, time: any, endless: boolean, otherLevel: boolean) {
const self = this;
// 检查关卡数据来源
if (levelNumber <= this.MAX_LOCAL_LEVEL) {
// 前100关从本地bundle加载
console.log(`关卡${levelNumber}从本地bundle加载`);
this.loadLevelFromBundle(levelNumber)
.then(jsonData => {
this.applyLevelData(jsonData, type, time, levelNumber);
})
.catch(error => {
console.error(`本地bundle加载关卡${levelNumber}失败:`, error);
this.handleLoadFail(levelNumber, name, type, time, endless, otherLevel);
});
} else {
// 101关以后,先检查本地缓存
const cachedData = this.getLevelFromCache(levelNumber);
if (cachedData) {
// 本地缓存存在,直接使用
console.log(`关卡${levelNumber}从本地缓存加载`);
this.applyLevelData(cachedData, type, time, levelNumber);
} else {
// 本地缓存不存在,从CDN加载
console.log(`关卡${levelNumber}从CDN加载`);
this.loadLevelFromCDN(levelNumber)
.then(jsonData => {
this.applyLevelData(jsonData, type, time, levelNumber);
})
.catch(error => {
console.error(`CDN加载关卡${levelNumber}失败:`, error);
this.handleLoadFail(levelNumber, name, type, time, endless, otherLevel);
});
}
}
}
/**
* 应用关卡数据
*/
static applyLevelData(jsonData: any, type: any, time: any, levelNumber = Number(jsonData.LEVEL_INFO[0].id), preparation?: GameplayEntryPreparation) {
this.loadedLevelNumber = levelNumber;
this.BLOCK_INFO = jsonData["BLOCK_INFO"];
this.LEVEL_INFO = jsonData["LEVEL_INFO"];
this.WALL_INFO = jsonData["WALL_INFO"];
console.log("关卡配置加载完成");
if (type) {
this.enterGameSceneWhenReady(time, preparation);
}
}
static handleLoadFail(levelNumber: number, name: string, type: any, time: any, endless: boolean, otherLevel: boolean) {
const self = this;
// 尝试从本地bundle回退(对于101关以后,可能没有对应的本地资源)
console.log(`尝试回退到本地bundle加载: ${name}`);
cc.assetManager.loadBundle("custom", (err: Error, bundle: cc.AssetManager.Bundle) => {
if (err) {
console.log("本地分包加载也失败:", err);
cc.fx.GameTool.addLevel(null, null, null);
if (endless) {
cc.fx.GameConfig.GM_INFO.randomLevel = cc.fx.GameConfig.GM_INFO.randomLevel + 1;
cc.fx.GameConfig.LEVEL_INFO_init(type, time, false, true);
} else {
self.LEVEL_INFO_init(type, time, false);
}
return;
}
bundle.load(name, cc.JsonAsset, (err: Error, res: cc.JsonAsset) => {
if (err) {
console.log("______________没有这个关卡:", name);
cc.fx.GameTool.addLevel(null, null, null);
if (endless) {
cc.fx.GameConfig.GM_INFO.randomLevel = cc.fx.GameConfig.GM_INFO.randomLevel + 1;
cc.fx.GameConfig.LEVEL_INFO_init(type, time, false, true);
} else {
self.LEVEL_INFO_init(type, time, false);
}
return;
}
let jsonData: object = res.json!;
this.applyLevelData(jsonData, type, time, levelNumber);
});
});
}
static setCode(code) {
this.GM_INFO.scode = code;
}
static getKey(key) {
// var reg = new RegExp('(^|&)' + key + '=([^&]*)(&|$)', 'i');
// var r = window.location.search.substring(1).match(reg);
// if (r != null) {
// return unescape(r[2]);
// }
return "";
}
static Authentication() {
cc.fx.GameTool.Authentication();
}
static CITY_init() {
this.CITY = {
"河北省": true, "山西省": true, "辽宁省": true, "吉林省": true, "黑龙江省": true, "江苏省": true,
"浙江省": true, "安徽省": true, "福建省": true, "江西省": true, "山东省": true, "河南省": true, "湖北省": true,
"湖南省": true, "广东省": true, "海南省": true, "四川省": true, "贵州省": true, "云南省": true, "陕西省": true,
"甘肃省": true, "青海省": true, "港澳台": true, "北京": true, "天津": true, "上海": true, "重庆": true,
"内蒙古": true, "广西": true, "西藏": true, "宁夏": true, "新疆": true
};
}
}