1430 lines
69 KiB
TypeScript
1430 lines
69 KiB
TypeScript
import { rainbowTexturePaths } from "../../RainbowRules";
|
||
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;
|
||
private static defaultPassRate: any[] = [];
|
||
private static newPlayerPassRate: any[] = [];
|
||
static get PASS_RATE(): any[] {
|
||
return this.isNewPlayerB() ? this.newPlayerPassRate : this.defaultPassRate;
|
||
}
|
||
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: this.gameplayBlockExtraPaths(blocks),
|
||
homeWarmup: true,
|
||
}).then(ready => {
|
||
if (ready && isCurrent()) {
|
||
console.log(`[Block图片][首页内存预热] 当前关${levelNumber}完成`);
|
||
}
|
||
return ready && isCurrent();
|
||
});
|
||
}
|
||
return BlockAssetManager.instance.cacheWindowFiles(blocks, this.gameplayBlockExtraPaths(blocks));
|
||
}).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: this.gameplayBlockExtraPaths(blocks) }).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];
|
||
}
|
||
|
||
// 临时测试:强制彩虹 B 方案,输赢、退出均保持十连胜;false 恢复真实 AB 和正常连胜规则。
|
||
static forceRainbowWinStreakB = false;
|
||
|
||
static isRainbowWinStreak(): boolean {
|
||
if (this.forceRainbowWinStreakB) return true;
|
||
return !!this.GM_INFO && !!this.GM_INFO.abTests && this.GM_INFO.abTests.layer_two === 2;
|
||
}
|
||
|
||
static isRainbowRewardActive(): boolean {
|
||
return this.isRainbowWinStreak() && this.isWinStreakUnlocked()
|
||
&& this.GM_INFO.winStreak >= 10 && !(this.GM_INFO.otherLevel > 0);
|
||
}
|
||
|
||
static gameplayBlockExtraPaths(blocks: any[]): string[] {
|
||
return GAMEPLAY_ATLAS_PATHS.concat(this.isRainbowRewardActive() ? rainbowTexturePaths(blocks) : []);
|
||
}
|
||
|
||
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.62", //版本号
|
||
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: this.forceRainbowWinStreakB, //测试模式从十连胜状态启动
|
||
getProgressLevel: 1, //获取进度关卡
|
||
getProgress: 0, //获取进度
|
||
getItemType: 2,
|
||
popPassCheck: false, // 弹窗通行证
|
||
passCheckActivate: false,
|
||
winStreak: this.forceRainbowWinStreakB ? 10 : 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.defaultPassRate = newLevelData;
|
||
})
|
||
cc.resources.load("Json/PASS_RATE2", (err: any, res: cc.JsonAsset) => {
|
||
if (err) {
|
||
console.error("加载 PASS_RATE2.JSON 失败:", err);
|
||
return;
|
||
}
|
||
this.newPlayerPassRate = res.json;
|
||
});
|
||
|
||
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
|
||
};
|
||
}
|
||
}
|