diff --git a/assets/prefabs/PageLevel.ts b/assets/prefabs/PageLevel.ts index 748fa57..9e6fcd5 100644 --- a/assets/prefabs/PageLevel.ts +++ b/assets/prefabs/PageLevel.ts @@ -94,12 +94,20 @@ export class PageLevel extends BaseView { */ onViewLoad(): void { console.log('[PageLevel] onViewLoad'); + // 从本地存储恢复关卡进度 + this.currentLevelIndex = StorageManager.getCurrentLevelIndex(); + console.log(`[PageLevel] 恢复关卡进度: 第 ${this.currentLevelIndex + 1} 关`); this.updateLiveLabel(); - this.initLevel(); this.initIconSetting(); this.initUnlockButtons(); this.initSubmitButton(); - this.startCountdown(); + + // 异步加载关卡资源,完成后启动倒计时 + this.initLevel().then(() => { + this.startCountdown(); + }).catch(err => { + console.error('[PageLevel] 加载关卡失败:', err); + }); } /** @@ -127,10 +135,18 @@ export class PageLevel extends BaseView { } /** - * 初始化关卡(从 API 数据加载) + * 初始化关卡(从 API 数据加载,异步确保资源就绪) */ - private initLevel(): void { - const config = LevelDataManager.instance.getLevelConfig(this.currentLevelIndex); + private async initLevel(): Promise { + // 先尝试从缓存获取 + let config = LevelDataManager.instance.getLevelConfig(this.currentLevelIndex); + + if (!config) { + // 缓存中没有,异步加载 + console.log(`[PageLevel] 关卡 ${this.currentLevelIndex + 1} 资源未缓存,开始加载...`); + config = await LevelDataManager.instance.ensureLevelReady(this.currentLevelIndex); + } + if (!config) { console.warn(`[PageLevel] 没有找到关卡配置,索引: ${this.currentLevelIndex}`); return; @@ -673,7 +689,10 @@ export class PageLevel extends BaseView { /** * 进入下一关 */ - private nextLevel(): void { + private async nextLevel(): Promise { + // 保存当前关卡进度 + StorageManager.onLevelCompleted(this.currentLevelIndex); + this.currentLevelIndex++; // 检查是否还有关卡 @@ -688,7 +707,7 @@ export class PageLevel extends BaseView { } // 重置并加载下一关,重新开始倒计时 - this.initLevel(); + await this.initLevel(); this.startCountdown(); console.log(`[PageLevel] 进入关卡 ${this.currentLevelIndex + 1}`); } diff --git a/assets/prefabs/PassModal.prefab b/assets/prefabs/PassModal.prefab index e5c4f57..e7dae42 100644 --- a/assets/prefabs/PassModal.prefab +++ b/assets/prefabs/PassModal.prefab @@ -20,19 +20,37 @@ "_children": [ { "__id__": 2 + }, + { + "__id__": 10 + }, + { + "__id__": 18 + }, + { + "__id__": 26 + }, + { + "__id__": 32 + }, + { + "__id__": 38 + }, + { + "__id__": 54 } ], "_active": true, "_components": [ { - "__id__": 10 + "__id__": 70 }, { - "__id__": 12 + "__id__": 72 } ], "_prefab": { - "__id__": 14 + "__id__": 74 }, "_lpos": { "__type__": "cc.Vec3", @@ -238,6 +256,1468 @@ "targetOverrides": null, "nestedPrefabInstanceRoots": null }, + { + "__type__": "cc.Node", + "_name": "Title", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 11 + }, + { + "__id__": 13 + }, + { + "__id__": 15 + } + ], + "_prefab": { + "__id__": 17 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": -169.899, + "y": 618.714, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 10 + }, + "_enabled": true, + "__prefab": { + "__id__": 12 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 300, + "height": 75.6 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "6aZZXip+lKvrkP+3ufXo57" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 10 + }, + "_enabled": true, + "__prefab": { + "__id__": 14 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_string": "恭喜过关!", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 60, + "_fontSize": 60, + "_fontFamily": "Arial", + "_lineHeight": 60, + "_overflow": 0, + "_enableWrapText": true, + "_font": null, + "_isSystemFontUsed": true, + "_spacingX": 0, + "_isItalic": false, + "_isBold": false, + "_isUnderline": false, + "_underlineHeight": 2, + "_cacheMode": 0, + "_enableOutline": false, + "_outlineColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_outlineWidth": 2, + "_enableShadow": false, + "_shadowColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_shadowOffset": { + "__type__": "cc.Vec2", + "x": 2, + "y": 2 + }, + "_shadowBlur": 2, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "4bPFWyZpJA95VefJ1FerIw" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 10 + }, + "_enabled": true, + "__prefab": { + "__id__": 16 + }, + "_alignFlags": 0, + "_target": null, + "_left": 0, + "_right": 0, + "_top": 0, + "_bottom": 0, + "_horizontalCenter": 0, + "_verticalCenter": 0, + "_isAbsLeft": true, + "_isAbsRight": true, + "_isAbsTop": true, + "_isAbsBottom": true, + "_isAbsHorizontalCenter": true, + "_isAbsVerticalCenter": true, + "_originalWidth": 0, + "_originalHeight": 0, + "_alignMode": 2, + "_lockFlags": 0, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "66o2HImDpHAYV4he5tmiuX" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "9dwZrYU0RBEIWJB8enwRgc", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.Node", + "_name": "IconLive", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 19 + }, + { + "__id__": 21 + }, + { + "__id__": 23 + } + ], + "_prefab": { + "__id__": 25 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 137.815, + "y": 619.585, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 0.519, + "y": 0.519, + "z": 0.519 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 18 + }, + "_enabled": true, + "__prefab": { + "__id__": 20 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 169, + "height": 155 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "adCkwK7YVPc4TT13/9y+QJ" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 18 + }, + "_enabled": true, + "__prefab": { + "__id__": 22 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "5ab5c212-a4cc-4c9b-a372-0cd2f30f4aff@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 0, + "_fillType": 0, + "_sizeMode": 1, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "76AbognxxP1Khn01SIR39l" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 18 + }, + "_enabled": true, + "__prefab": { + "__id__": 24 + }, + "_alignFlags": 0, + "_target": null, + "_left": 0, + "_right": 0, + "_top": 0, + "_bottom": 0, + "_horizontalCenter": 0, + "_verticalCenter": 0, + "_isAbsLeft": true, + "_isAbsRight": true, + "_isAbsTop": true, + "_isAbsBottom": true, + "_isAbsHorizontalCenter": true, + "_isAbsVerticalCenter": true, + "_originalWidth": 0, + "_originalHeight": 0, + "_alignMode": 2, + "_lockFlags": 0, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "5cq10IWOJP070psEmWgOrO" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "b208eAXaNKQ76agOadOK/c", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 27 + }, + { + "__id__": 29 + } + ], + "_prefab": { + "__id__": 31 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 237.319, + "y": 622.262, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 26 + }, + "_enabled": true, + "__prefab": { + "__id__": 28 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 57.0068359375, + "height": 63 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "0740qRs3RNz5p57Y2m8zaF" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 26 + }, + "_enabled": true, + "__prefab": { + "__id__": 30 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_string": "+1", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 50, + "_fontSize": 50, + "_fontFamily": "Arial", + "_lineHeight": 50, + "_overflow": 0, + "_enableWrapText": true, + "_font": null, + "_isSystemFontUsed": true, + "_spacingX": 0, + "_isItalic": false, + "_isBold": false, + "_isUnderline": false, + "_underlineHeight": 2, + "_cacheMode": 0, + "_enableOutline": false, + "_outlineColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_outlineWidth": 2, + "_enableShadow": false, + "_shadowColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_shadowOffset": { + "__type__": "cc.Vec2", + "x": 2, + "y": 2 + }, + "_shadowBlur": 2, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "ccytoLetVEXJJyquCLYWtO" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "c7ywe7ClhHqqVjazViWu66", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.Node", + "_name": "test", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 33 + }, + { + "__id__": 35 + } + ], + "_prefab": { + "__id__": 37 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 127.633, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 32 + }, + "_enabled": true, + "__prefab": { + "__id__": 34 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 536, + "height": 548 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "55vTgXt4JP440c14d4n0yq" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 32 + }, + "_enabled": true, + "__prefab": { + "__id__": 36 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "d46acd4d-66e2-423b-8015-334ff99dd9f1@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 0, + "_fillType": 0, + "_sizeMode": 1, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "70w6BIY/1P/5gDj3+7X1dC" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "e3EX+B9GlNO7GvWnGUS3Zz", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.Node", + "_name": "NextLevelButton", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [ + { + "__id__": 39 + } + ], + "_active": true, + "_components": [ + { + "__id__": 45 + }, + { + "__id__": 47 + }, + { + "__id__": 49 + }, + { + "__id__": 51 + } + ], + "_prefab": { + "__id__": 53 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": -355.718, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1.931, + "y": 1.931, + "z": 1.931 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 38 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 40 + }, + { + "__id__": 42 + } + ], + "_prefab": { + "__id__": 44 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": -3.567, + "y": 2.675, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 39 + }, + "_enabled": true, + "__prefab": { + "__id__": 41 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 120, + "height": 50.4 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "37j0j8TNZI+6aXdkZD2z0g" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 39 + }, + "_enabled": true, + "__prefab": { + "__id__": 43 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_string": "下一关", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 40, + "_fontSize": 40, + "_fontFamily": "Arial", + "_lineHeight": 40, + "_overflow": 0, + "_enableWrapText": true, + "_font": null, + "_isSystemFontUsed": true, + "_spacingX": 0, + "_isItalic": false, + "_isBold": false, + "_isUnderline": false, + "_underlineHeight": 2, + "_cacheMode": 0, + "_enableOutline": false, + "_outlineColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_outlineWidth": 2, + "_enableShadow": false, + "_shadowColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_shadowOffset": { + "__type__": "cc.Vec2", + "x": 2, + "y": 2 + }, + "_shadowBlur": 2, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "020Ghj89JCzLsvgeCIPHhX" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "45UAMuoO5Nh7y/tmxbhhn+", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 38 + }, + "_enabled": true, + "__prefab": { + "__id__": 46 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 306, + "height": 77 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "a59mo9gY5AGLlqEpkOos0E" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 38 + }, + "_enabled": true, + "__prefab": { + "__id__": 48 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 0, + "_fillType": 0, + "_sizeMode": 1, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "9c+dlB+NFMhZbZcoe+uj/s" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 38 + }, + "_enabled": true, + "__prefab": { + "__id__": 50 + }, + "clickEvents": [], + "_interactable": true, + "_transition": 0, + "_normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_hoverColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_pressedColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_normalSprite": null, + "_hoverSprite": null, + "_pressedSprite": null, + "_disabledSprite": null, + "_duration": 0.1, + "_zoomScale": 1.2, + "_target": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "a6CBaO3IxAC7cOP/84NjPI" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 38 + }, + "_enabled": true, + "__prefab": { + "__id__": 52 + }, + "_alignFlags": 4, + "_target": null, + "_left": 0, + "_right": 0, + "_top": 0, + "_bottom": 649.9385, + "_horizontalCenter": 0, + "_verticalCenter": 0, + "_isAbsLeft": true, + "_isAbsRight": true, + "_isAbsTop": true, + "_isAbsBottom": true, + "_isAbsHorizontalCenter": true, + "_isAbsVerticalCenter": true, + "_originalWidth": 0, + "_originalHeight": 0, + "_alignMode": 2, + "_lockFlags": 0, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "bf7jRdFgVArq5lB0wo9+tz" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "d5L0V2wABLWpFoY9E3yRBT", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.Node", + "_name": "ShareButton", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 1 + }, + "_children": [ + { + "__id__": 55 + } + ], + "_active": true, + "_components": [ + { + "__id__": 61 + }, + { + "__id__": 63 + }, + { + "__id__": 65 + }, + { + "__id__": 67 + } + ], + "_prefab": { + "__id__": 69 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": -569.771, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1.931, + "y": 1.931, + "z": 1.931 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 54 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 56 + }, + { + "__id__": 58 + } + ], + "_prefab": { + "__id__": 60 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": -3.567, + "y": 2.675, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 1 + }, + "_mobility": 0, + "_layer": 1073741824, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 55 + }, + "_enabled": true, + "__prefab": { + "__id__": 57 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 160, + "height": 50.4 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "8fHkHMMDVBKLEM9nmbuj/j" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 55 + }, + "_enabled": true, + "__prefab": { + "__id__": 59 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_string": "邀请好友", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 40, + "_fontSize": 40, + "_fontFamily": "Arial", + "_lineHeight": 40, + "_overflow": 0, + "_enableWrapText": true, + "_font": null, + "_isSystemFontUsed": true, + "_spacingX": 0, + "_isItalic": false, + "_isBold": false, + "_isUnderline": false, + "_underlineHeight": 2, + "_cacheMode": 0, + "_enableOutline": false, + "_outlineColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_outlineWidth": 2, + "_enableShadow": false, + "_shadowColor": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_shadowOffset": { + "__type__": "cc.Vec2", + "x": 2, + "y": 2 + }, + "_shadowBlur": 2, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "dbfqahFWRJT4kHAnXgRQfb" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "7fAP2H3zNILqeRakD5Sn32", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 54 + }, + "_enabled": true, + "__prefab": { + "__id__": 62 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 306, + "height": 77 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "3dHGGtVCNOZoohqMo+1rDg" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 54 + }, + "_enabled": true, + "__prefab": { + "__id__": 64 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 0, + "_fillType": 0, + "_sizeMode": 1, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "b2SMxe56RDebTpy5OBm/cF" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 54 + }, + "_enabled": true, + "__prefab": { + "__id__": 66 + }, + "clickEvents": [], + "_interactable": true, + "_transition": 0, + "_normalColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_hoverColor": { + "__type__": "cc.Color", + "r": 211, + "g": 211, + "b": 211, + "a": 255 + }, + "_pressedColor": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_disabledColor": { + "__type__": "cc.Color", + "r": 124, + "g": 124, + "b": 124, + "a": 255 + }, + "_normalSprite": null, + "_hoverSprite": null, + "_pressedSprite": null, + "_disabledSprite": null, + "_duration": 0.1, + "_zoomScale": 1.2, + "_target": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "17jncxyVRIeZn4XVfiULc5" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 54 + }, + "_enabled": true, + "__prefab": { + "__id__": 68 + }, + "_alignFlags": 4, + "_target": null, + "_left": 0, + "_right": 0, + "_top": 0, + "_bottom": 435.8855000000001, + "_horizontalCenter": 0, + "_verticalCenter": 0, + "_isAbsLeft": true, + "_isAbsRight": true, + "_isAbsTop": true, + "_isAbsBottom": true, + "_isAbsHorizontalCenter": true, + "_isAbsVerticalCenter": true, + "_originalWidth": 0, + "_originalHeight": 0, + "_alignMode": 2, + "_lockFlags": 0, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "d2CvRBObFMpqqAwuVyhLvA" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "d8e0bStPlJ4aX1E2fkemEH", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, { "__type__": "cc.UITransform", "_name": "", @@ -248,7 +1728,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 11 + "__id__": 71 }, "_contentSize": { "__type__": "cc.Size", @@ -276,7 +1756,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 13 + "__id__": 73 }, "_alignFlags": 45, "_target": null, diff --git a/assets/resources/images/pageLevel/ButtonBg.png b/assets/resources/images/pageLevel/ButtonBg.png new file mode 100644 index 0000000..c4d9ac5 Binary files /dev/null and b/assets/resources/images/pageLevel/ButtonBg.png differ diff --git a/assets/resources/images/pageLevel/ButtonBg.png.meta b/assets/resources/images/pageLevel/ButtonBg.png.meta new file mode 100644 index 0000000..039241a --- /dev/null +++ b/assets/resources/images/pageLevel/ButtonBg.png.meta @@ -0,0 +1,134 @@ +{ + "ver": "1.0.27", + "importer": "image", + "imported": true, + "uuid": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26", + "files": [ + ".json", + ".png" + ], + "subMetas": { + "6c48a": { + "importer": "texture", + "uuid": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@6c48a", + "displayName": "ButtonBg", + "id": "6c48a", + "name": "texture", + "userData": { + "wrapModeS": "clamp-to-edge", + "wrapModeT": "clamp-to-edge", + "imageUuidOrDatabaseUri": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26", + "isUuid": true, + "visible": false, + "minfilter": "linear", + "magfilter": "linear", + "mipfilter": "none", + "anisotropy": 0 + }, + "ver": "1.0.22", + "imported": true, + "files": [ + ".json" + ], + "subMetas": {} + }, + "f9941": { + "importer": "sprite-frame", + "uuid": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@f9941", + "displayName": "ButtonBg", + "id": "f9941", + "name": "spriteFrame", + "userData": { + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0.5, + "trimX": 1, + "trimY": 0, + "width": 306, + "height": 77, + "rawWidth": 308, + "rawHeight": 78, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "packable": true, + "pixelsToUnit": 100, + "pivotX": 0.5, + "pivotY": 0.5, + "meshType": 0, + "vertices": { + "rawPosition": [ + -153, + -38.5, + 0, + 153, + -38.5, + 0, + -153, + 38.5, + 0, + 153, + 38.5, + 0 + ], + "indexes": [ + 0, + 1, + 2, + 2, + 1, + 3 + ], + "uv": [ + 1, + 78, + 307, + 78, + 1, + 1, + 307, + 1 + ], + "nuv": [ + 0.003246753246753247, + 0.01282051282051282, + 0.9967532467532467, + 0.01282051282051282, + 0.003246753246753247, + 1, + 0.9967532467532467, + 1 + ], + "minPos": [ + -153, + -38.5, + 0 + ], + "maxPos": [ + 153, + 38.5, + 0 + ] + }, + "isUuid": true, + "imageUuidOrDatabaseUri": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@6c48a", + "atlasUuid": "", + "trimType": "auto" + }, + "ver": "1.0.12", + "imported": true, + "files": [ + ".json" + ], + "subMetas": {} + } + }, + "userData": { + "type": "sprite-frame", + "fixAlphaTransparencyArtifacts": false, + "hasAlpha": true, + "redirect": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@6c48a" + } +} diff --git a/assets/resources/images/pageLevel/test.png b/assets/resources/images/pageLevel/test.png new file mode 100644 index 0000000..d296ae1 Binary files /dev/null and b/assets/resources/images/pageLevel/test.png differ diff --git a/assets/resources/images/pageLevel/test.png.meta b/assets/resources/images/pageLevel/test.png.meta new file mode 100644 index 0000000..1fc95fb --- /dev/null +++ b/assets/resources/images/pageLevel/test.png.meta @@ -0,0 +1,134 @@ +{ + "ver": "1.0.27", + "importer": "image", + "imported": true, + "uuid": "d46acd4d-66e2-423b-8015-334ff99dd9f1", + "files": [ + ".json", + ".png" + ], + "subMetas": { + "6c48a": { + "importer": "texture", + "uuid": "d46acd4d-66e2-423b-8015-334ff99dd9f1@6c48a", + "displayName": "test", + "id": "6c48a", + "name": "texture", + "userData": { + "wrapModeS": "clamp-to-edge", + "wrapModeT": "clamp-to-edge", + "imageUuidOrDatabaseUri": "d46acd4d-66e2-423b-8015-334ff99dd9f1", + "isUuid": true, + "visible": false, + "minfilter": "linear", + "magfilter": "linear", + "mipfilter": "none", + "anisotropy": 0 + }, + "ver": "1.0.22", + "imported": true, + "files": [ + ".json" + ], + "subMetas": {} + }, + "f9941": { + "importer": "sprite-frame", + "uuid": "d46acd4d-66e2-423b-8015-334ff99dd9f1@f9941", + "displayName": "test", + "id": "f9941", + "name": "spriteFrame", + "userData": { + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0, + "trimX": 0, + "trimY": 0, + "width": 536, + "height": 548, + "rawWidth": 536, + "rawHeight": 548, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "packable": true, + "pixelsToUnit": 100, + "pivotX": 0.5, + "pivotY": 0.5, + "meshType": 0, + "vertices": { + "rawPosition": [ + -268, + -274, + 0, + 268, + -274, + 0, + -268, + 274, + 0, + 268, + 274, + 0 + ], + "indexes": [ + 0, + 1, + 2, + 2, + 1, + 3 + ], + "uv": [ + 0, + 548, + 536, + 548, + 0, + 0, + 536, + 0 + ], + "nuv": [ + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1 + ], + "minPos": [ + -268, + -274, + 0 + ], + "maxPos": [ + 268, + 274, + 0 + ] + }, + "isUuid": true, + "imageUuidOrDatabaseUri": "d46acd4d-66e2-423b-8015-334ff99dd9f1@6c48a", + "atlasUuid": "", + "trimType": "auto" + }, + "ver": "1.0.12", + "imported": true, + "files": [ + ".json" + ], + "subMetas": {} + } + }, + "userData": { + "type": "sprite-frame", + "fixAlphaTransparencyArtifacts": false, + "hasAlpha": false, + "redirect": "d46acd4d-66e2-423b-8015-334ff99dd9f1@6c48a" + } +} diff --git a/assets/scripts/utils/StorageManager.ts b/assets/scripts/utils/StorageManager.ts index 3232f79..740775e 100644 --- a/assets/scripts/utils/StorageManager.ts +++ b/assets/scripts/utils/StorageManager.ts @@ -1,5 +1,15 @@ import { sys } from 'cc'; +/** + * 用户进度数据结构 + */ +interface UserProgress { + /** 当前关卡索引(0-based) */ + currentLevelIndex: number; + /** 已通关的最高关卡索引 */ + maxUnlockedLevelIndex: number; +} + /** * 本地存储管理器 * 统一管理用户数据的本地持久化存储 @@ -8,12 +18,24 @@ export class StorageManager { /** 生命值存储键 */ private static readonly KEY_LIVES = 'game_lives'; + /** 用户进度存储键 */ + private static readonly KEY_PROGRESS = 'game_progress'; + /** 默认生命值 */ private static readonly DEFAULT_LIVES = 10; /** 最小生命值 */ private static readonly MIN_LIVES = 0; + /** 默认进度 */ + private static readonly DEFAULT_PROGRESS: UserProgress = { + currentLevelIndex: 0, + maxUnlockedLevelIndex: 0 + }; + + /** 进度缓存(避免重复读取 localStorage) */ + private static _progressCache: UserProgress | null = null; + // ==================== 生命值管理 ==================== /** @@ -84,4 +106,134 @@ export class StorageManager { StorageManager.setLives(StorageManager.DEFAULT_LIVES); console.log('[StorageManager] 生命值已重置为默认值'); } + + // ==================== 关卡进度管理 ==================== + + /** + * 获取用户进度数据(带缓存) + * @returns 用户进度对象的副本 + */ + private static _getProgress(): UserProgress { + // 返回缓存副本 + if (StorageManager._progressCache !== null) { + return { ...StorageManager._progressCache }; + } + + const stored = sys.localStorage.getItem(StorageManager.KEY_PROGRESS); + if (stored === null || stored === '') { + // 新用户,返回默认进度 + StorageManager._progressCache = { ...StorageManager.DEFAULT_PROGRESS }; + return { ...StorageManager._progressCache }; + } + + try { + const progress = JSON.parse(stored) as UserProgress; + // 验证数据有效性 + if (typeof progress.currentLevelIndex !== 'number' || + typeof progress.maxUnlockedLevelIndex !== 'number' || + progress.currentLevelIndex < 0 || + progress.maxUnlockedLevelIndex < 0) { + console.warn('[StorageManager] 进度数据无效,使用默认值'); + StorageManager._progressCache = { ...StorageManager.DEFAULT_PROGRESS }; + } else { + StorageManager._progressCache = progress; + } + return { ...StorageManager._progressCache }; + } catch (e) { + console.warn('[StorageManager] 解析进度数据失败,使用默认值'); + StorageManager._progressCache = { ...StorageManager.DEFAULT_PROGRESS }; + return { ...StorageManager._progressCache }; + } + } + + /** + * 保存用户进度数据 + * @param progress 进度对象 + */ + private static _saveProgress(progress: UserProgress): void { + StorageManager._progressCache = progress; + sys.localStorage.setItem(StorageManager.KEY_PROGRESS, JSON.stringify(progress)); + } + + /** + * 获取当前关卡索引 + * @returns 当前关卡索引(0-based) + */ + static getCurrentLevelIndex(): number { + return StorageManager._getProgress().currentLevelIndex; + } + + /** + * 设置当前关卡索引 + * @param index 关卡索引 + */ + static setCurrentLevelIndex(index: number): void { + if (index < 0) { + console.warn('[StorageManager] 关卡索引不能为负数'); + return; + } + const progress = StorageManager._getProgress(); + progress.currentLevelIndex = index; + StorageManager._saveProgress(progress); + console.log(`[StorageManager] 当前关卡已更新: ${progress.currentLevelIndex}`); + } + + /** + * 获取已解锁的最高关卡索引 + * @returns 最高关卡索引(0-based) + */ + static getMaxUnlockedLevelIndex(): number { + return StorageManager._getProgress().maxUnlockedLevelIndex; + } + + /** + * 通关后更新进度 + * 当玩家通关第 N 关后,设置当前关卡为 N+1,解锁关卡更新为 max(N, 已解锁) + * @param completedLevelIndex 刚通关的关卡索引 + */ + static onLevelCompleted(completedLevelIndex: number): void { + if (completedLevelIndex < 0) { + console.warn('[StorageManager] 通关关卡索引不能为负数'); + return; + } + const progress = StorageManager._getProgress(); + const nextLevelIndex = completedLevelIndex + 1; + + // 更新当前关卡为下一关 + progress.currentLevelIndex = nextLevelIndex; + + // 更新最高解锁关卡 + progress.maxUnlockedLevelIndex = Math.max(progress.maxUnlockedLevelIndex, completedLevelIndex); + + StorageManager._saveProgress(progress); + console.log(`[StorageManager] 通关第 ${completedLevelIndex + 1} 关,下一关: ${nextLevelIndex + 1}`); + } + + /** + * 检查指定关卡是否已解锁 + * @param levelIndex 关卡索引 + * @returns 是否已解锁 + */ + static isLevelUnlocked(levelIndex: number): boolean { + const progress = StorageManager._getProgress(); + return levelIndex <= progress.maxUnlockedLevelIndex; + } + + /** + * 重置所有进度 + */ + static resetProgress(): void { + StorageManager._progressCache = null; + sys.localStorage.removeItem(StorageManager.KEY_PROGRESS); + console.log('[StorageManager] 进度已重置'); + } + + /** + * 重置所有数据(生命值 + 进度) + */ + static resetAll(): void { + StorageManager.resetLives(); + StorageManager.resetProgress(); + console.log('[StorageManager] 所有数据已重置'); + } }