diff --git a/AGENTS.md b/AGENTS.md index 3b8ec04..bfd31c6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,62 +40,78 @@ Git 历史采用 Conventional Commits,且摘要多为中文,例如 `feat: # Memory Context -# $CMEM mp-xieyingeng 2026-05-11 11:01pm GMT+8 +# [mp-xieyingeng] recent context, 2026-05-12 7:49pm GMT+8 -Legend: 🎯session 🔴bugfix 🟣feature 🔄refactor ✅change 🔵discovery ⚖️decision +Legend: 🎯session 🔴bugfix 🟣feature 🔄refactor ✅change 🔵discovery ⚖️decision 🚨security_alert 🔐security_note Format: ID TIME TYPE TITLE Fetch details: get_observations([IDs]) | Search: mem-search skill -Stats: 47 obs (10,663t read) | 538,681t work | 98% savings +Stats: 50 obs (11,836t read) | 1,674,484t work | 99% savings -### Apr 24, 2026 -101 8:46a 🟣 Live label display format updated to X/Y format -114 6:40p 🟣 Dynamic Input Layout Initialization in PageLevel Prefab -115 6:41p 🟣 Dynamic Punch Block Layout for PageLevel.prefab -116 " 🔵 Layout Component Configuration for Input and Punch Blocks -119 6:42p 🟣 Dynamic Input Blocks and Punch Layout System Implemented -121 " 🟣 PageLevel Prefab Updated with punchLayout Property -122 " 🔄 Cleanup After Dynamic Block Refactoring -124 " ✅ TypeScript Compilation Check in Progress -126 6:43p ✅ TypeScript Compilation Check Extended -127 " 🔄 Complete Diff of PageLevel.ts Dynamic Block System -128 " 🔵 PageLevel.prefab Changes Not Persisted -129 6:44p 🟣 PageLevel Prefab Correctly Updated with punchLayout -130 " ✅ TypeScript Compilation Blocked - Permission Required -133 6:45p 🔄 Extracted getPunchBlockLabel Helper Method -134 " 🔄 Template Node Hiding Logic Improved -136 6:48p ⚖️ TypeScript diagnostics disabled, using IDE/linter instead -138 " 🔄 PageLevel 输入方式从单框改为逐字格子 -139 " 🔄 谐音梗展示从 Label 改为动态 Block 节点 -140 " ✅ PageLevel.prefab 布局位置微调 -165 8:08p 🟣 PageLevel input layout simplified to single-character boxes with auto-distribution -167 8:09p 🔵 PageLevel.ts input block structure and callback stubs discovered -168 " 🟣 Auto-distribute characters across input boxes and auto-submit on completion implemented -169 " 🔴 PageLevel.ts node cleanup now calls removeFromParent before destroy -170 8:10p 🔄 PageLevel.ts full diff: single EditBox replaced with per-character block system -171 " 🔴 distributeInputText() wrapped in try/finally to guarantee flag reset -179 8:23p ✅ Game011_3.ttf font relocated from resources/ to dedicated fonts/ bundle directory -180 " 🟣 PageLoading.ts now loads fonts as a dynamic bundle after level data, before UI -181 " 🔄 AssetManager import switched to type-only import in PageLoading.ts -182 8:31p 🟣 PageLevel input UX improvement: full-string editing support -183 " 🟣 PageLevel input UX: full-string editing implemented -186 8:34p 🔴 PageLevel: clear input text on wrong answer -187 8:35p 🟣 PageLevel: delay pass modal to show punchline -189 8:36p 🔄 PageLevel: level completion reporting made fire-and-forget -191 8:45p 🔴 PageLevel: punchline block cleanup improved -192 8:46p 🟣 PageLevel.ts TitleLevel Label variable reserved -193 8:47p 🔵 PageLevel.ts level number tracking mechanism discovered -195 " 🟣 PageLevel.ts TitleLevel dynamic label update implemented -196 8:53p 🔵 PageLevel punchline not updated from enterLevel API -198 " 🔴 LevelDataManager updateLevelDetails now includes punchline -199 " 🔴 PageLevel punchline flow and empty state layout fixed -200 8:54p 🔴 LevelDataManager preserves existing punchline when enter returns null -203 9:06p 🟣 PageLevel.ts 新增图片描述标签绑定字段 -205 9:07p 🟣 PageLevel.ts 图片描述标签字段对接完成 -206 9:09p ✅ PageLevel.ts 回退图片描述标签字段命名 -208 9:11p 🟣 LevelDataManager 增加图片描述字段存储 -214 9:40p 🟣 拼图游戏关卡内 Punch Layout 显隐控制 -216 " 🟣 PageLevel.ts punchline 显隐控制逻辑对接完成 +### Apr 26, 2026 +S1309 移除 PageLevel.ts 进入关卡时弹出体力扣减 toast (Apr 26 at 5:16 PM) +1343 5:17p 🔴 进度条圆角畸形问题已修复 +1345 " ⚖️ 否决 Mask 方案,确认最小进度值方案最优 +### Apr 27, 2026 +1346 9:21a 🔴 移除进入游戏后的体力扣减 toast 提示 +1347 " 🔴 移除进入游戏后的体力扣减 toast 提示 +1348 " 🟣 首页添加体力值显示功能 +S1308 移除进入游戏关卡时弹出体力扣减的 toast 提示 (Apr 27 at 9:21 AM) +S1310 移除进入游戏体力扣减 toast 并在首页添加体力显示 (Apr 27 at 9:22 AM) +S1311 移除体力扣减 toast 并完善首页体验 (Apr 27 at 9:23 AM) +1349 9:25a ✅ PageHome.ts 添加 ToastManager 导入 +1350 " ✅ PK按钮点击改为提示"功能开发中" +S1313 Implement object-fit: cover image scaling in Cocos Creator to prevent downloaded images from being distorted (Apr 27 at 9:26 AM) +1351 9:32a 🟣 Stamina animation system for level entry +1352 " 🔵 Cocos Creator game project structure discovered +1354 " 🟣 StarGame 按钮点击动画需求 +1356 " 🔵 体力系统架构发现 +1353 9:33a 🔵 StaminaManager API confirmed for stamina operations +1355 9:37a 🔵 项目结构和现有代码发现 +1357 9:38a 🔵 EnterLevelData 结构分析 +1359 9:39a 🟣 Stamina animation system implemented for game entry flow +1358 9:41a ⚖️ 体力值飞行动画实现计划制定完成 +1362 9:45a 🟣 Image Cover Mode Scaling in Cocos Creator +S1312 Fix image distortion in PageLevel.ts by implementing object-fit: cover behavior for downloaded images (Apr 27 at 9:45 AM) +1360 " ✅ Cocos Creator animation imports added to PageHome.ts +1361 " ✅ Animation constants added to PageHome class +1363 " ✅ Start game button integrated with stamina check and animation flow +1364 " 🟣 Stamina consumption animation fully implemented in PageHome +S1314 Implement stamina consumption animation in Cocos Creator game - when clicking StarGame button, IconLive node flies to button with floating "-1" text, then navigates to level (Apr 27 at 9:45 AM) +1365 9:46a 🔴 Animation completes but navigation to PageLevel fails +S1315 为 PageLevel.ts 的 mainImage 和 mainImage2 节点实现 CSS cover 模式图片缩放 (Apr 27 at 9:46 AM) +1366 9:50a 🔴 Cocos Creator tween chain broken by premature node destroy +1367 9:55a 🔴 Navigation still failing after first tween chain fix - further debugging needed +1368 " 🔴 Decoupled fly animation from float text timing using setTimeout +1369 9:56a 🔴 Cocos Creator tween chain broken by any node state change mid-animation +1370 9:59a 🟣 CSS cover-style image scaling for PageLevel images +1371 10:01a ✅ PageLevel.ts imports extended for cover-style image scaling +1372 " 🟣 CSS cover-mode image scaling implemented for PageLevel images +S1316 Debug cover mode image overflow in PageLevel.ts - image exceeds container bounds despite Mask applied (Apr 27 at 10:02 AM) +1373 10:02a 🔴 Cover mode image overflows container bounds +1374 10:06a 🔵 GRAPHICS_RECT vs GRAPHICS_STENCIL for Mask in Cocos Creator +1375 10:08a 🔴 Mask.Type.RECT does not exist in Cocos Creator API +1376 " 🔵 MaskType enum found in Cocos Creator 3.8 engine declarations +1378 " 🔵 MaskType enum values confirmed - GRAPHICS_RECT exists +1377 10:09a 🔵 MaskType enum definition found at line 46015 +1379 10:10a 🔴 Reverted Mask.Type to GRAPHICS_RECT +S1317 Implement CSS cover-mode image scaling for PageLevel.ts mainImage nodes (Apr 27 at 10:10 AM) +### Apr 29, 2026 +1481 6:33p 🟣 Implementing rounded corner images in PageLevel.ts +1482 " 🔵 RoundedRectMask component already exists for image corner rounding +1485 6:34p 🟣 Implemented rounded corners for PageLevel main images +1484 " 🔄 RoundedRectMask component improved with quality standards +1487 6:37p 🔵 TypeScript verification confirms no errors in new rounded corners implementation +### May 12, 2026 +1542 4:39p 🟣 CommonModal prefab adds conditional dual-button support +1543 " 🔵 CommonModal prefab contains both button node variants +1544 4:40p 🟣 CommonModal prefab upgraded with dual-button support +1545 4:41p 🟣 CommonModal prefab restructured with dual-button ActionDouble container +1546 " 🔵 BaseModal provides modal animation infrastructure +1547 4:43p 🟣 CommonModal.ts upgraded with dual-button support and backward compatibility +1548 4:44p 🟣 CommonModal dual-button implementation completed +1549 " ✅ CommonModal dual-button feature ready for testing +1550 4:45p 🟣 CommonModal dual-button feature completed and validated -Access 539k tokens of past work via get_observations([IDs]) or mem-search skill. +Access 1674k tokens of past work via get_observations([IDs]) or mem-search skill. diff --git a/assets/prefabs/CommonModal.prefab b/assets/prefabs/CommonModal.prefab index 4ba215f..eb15e5e 100644 --- a/assets/prefabs/CommonModal.prefab +++ b/assets/prefabs/CommonModal.prefab @@ -28,17 +28,17 @@ "_active": true, "_components": [ { - "__id__": 76 + "__id__": 116 }, { - "__id__": 78 + "__id__": 118 }, { - "__id__": 80 + "__id__": 120 } ], "_prefab": { - "__id__": 82 + "__id__": 122 }, "_lpos": { "__type__": "cc.Vec3", @@ -267,19 +267,22 @@ }, { "__id__": 51 + }, + { + "__id__": 71 } ], "_active": true, "_components": [ { - "__id__": 71 + "__id__": 111 }, { - "__id__": 73 + "__id__": 113 } ], "_prefab": { - "__id__": 75 + "__id__": 115 }, "_lpos": { "__type__": "cc.Vec3", @@ -608,7 +611,7 @@ }, "_contentSize": { "__type__": "cc.Size", - "width": 286, + "width": 146, "height": 94.2 }, "_anchorPoint": { @@ -644,7 +647,7 @@ "b": 255, "a": 255 }, - "_string": "温馨提示", + "_string": "提示", "_horizontalAlign": 1, "_verticalAlign": 1, "_actualFontSize": 70, @@ -870,7 +873,7 @@ }, { "__type__": "cc.Node", - "_name": "ButtonHint", + "_name": "ButtonConfirm", "_objFlags": 0, "__editorExtras__": {}, "_parent": { @@ -1749,6 +1752,979 @@ "targetOverrides": null, "nestedPrefabInstanceRoots": null }, + { + "__type__": "cc.Node", + "_name": "ActionDouble", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 10 + }, + "_children": [ + { + "__id__": 72 + }, + { + "__id__": 90 + } + ], + "_active": true, + "_components": [ + { + "__id__": 108 + } + ], + "_prefab": { + "__id__": 110 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": -108.2, + "y": 0, + "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.Node", + "_name": "ButtonConfirm", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 71 + }, + "_children": [ + { + "__id__": 73 + } + ], + "_active": true, + "_components": [ + { + "__id__": 81 + }, + { + "__id__": 83 + }, + { + "__id__": 85 + }, + { + "__id__": 87 + } + ], + "_prefab": { + "__id__": 89 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 430.44, + "y": -605.564, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 0.694 + }, + "_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__": 72 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 74 + }, + { + "__id__": 76 + }, + { + "__id__": 78 + } + ], + "_prefab": { + "__id__": 80 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 7.598, + "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__": 73 + }, + "_enabled": true, + "__prefab": { + "__id__": 75 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 330, + "height": 136 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "bcCX5/BQ9CWKUSePyzQcZE" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 73 + }, + "_enabled": true, + "__prefab": { + "__id__": 77 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_string": "继续挑战", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 80, + "_fontSize": 80, + "_fontFamily": "Arial", + "_lineHeight": 100, + "_overflow": 0, + "_enableWrapText": true, + "_font": { + "__uuid__": "fb4acba6-6bc7-4eb3-be34-8f2ac9823a80", + "__expectedType__": "cc.TTFFont" + }, + "_isSystemFontUsed": false, + "_spacingX": 0, + "_isItalic": false, + "_isBold": true, + "_isUnderline": false, + "_underlineHeight": 2, + "_cacheMode": 0, + "_enableOutline": true, + "_outlineColor": { + "__type__": "cc.Color", + "r": 72, + "g": 158, + "b": 35, + "a": 255 + }, + "_outlineWidth": 5, + "_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": "76McmuKOlPxYSbxe4aQrXD" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 73 + }, + "_enabled": true, + "__prefab": { + "__id__": 79 + }, + "_alignFlags": 18, + "_target": null, + "_left": 0, + "_right": 0, + "_top": 0, + "_bottom": 0, + "_horizontalCenter": 0, + "_verticalCenter": 7.598, + "_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": "09Phkz+C1GMpcnBqzOPlgl" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "ddemfzZk1AM7mh/Y+fu34m", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 72 + }, + "_enabled": true, + "__prefab": { + "__id__": 82 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 580, + "height": 234 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "35uLnrQzxC1opjyuOcP+So" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 72 + }, + "_enabled": true, + "__prefab": { + "__id__": 84 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "f87d228a-c520-499a-bf3a-e66cbb6def64@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "a6DuR7yYFDZ5sp8UWw+KJL" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 72 + }, + "_enabled": true, + "__prefab": { + "__id__": 86 + }, + "_alignFlags": 12, + "_target": null, + "_left": 190.44, + "_right": 0, + "_top": 0, + "_bottom": -672.564, + "_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": "a3hhtxi5NIjpeINW5Z3G2v" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 72 + }, + "_enabled": true, + "__prefab": { + "__id__": 88 + }, + "clickEvents": [], + "_interactable": true, + "_transition": 3, + "_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": "e8UqtGSLRFNbW+9cOB0pak" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "51QhSQheNOdaugG3nzOEyr", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.Node", + "_name": "ButtonCancel", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 71 + }, + "_children": [ + { + "__id__": 91 + } + ], + "_active": true, + "_components": [ + { + "__id__": 99 + }, + { + "__id__": 101 + }, + { + "__id__": 103 + }, + { + "__id__": 105 + } + ], + "_prefab": { + "__id__": 107 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": -213.17200000000003, + "y": -609.906, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 1, + "y": 1, + "z": 0.687 + }, + "_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__": 90 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 92 + }, + { + "__id__": 94 + }, + { + "__id__": 96 + } + ], + "_prefab": { + "__id__": 98 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 7.598, + "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__": 91 + }, + "_enabled": true, + "__prefab": { + "__id__": 93 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 170, + "height": 136 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "124h2/A7JLmLrbMEQGKV0O" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 91 + }, + "_enabled": true, + "__prefab": { + "__id__": 95 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_string": "取消", + "_horizontalAlign": 1, + "_verticalAlign": 1, + "_actualFontSize": 80, + "_fontSize": 80, + "_fontFamily": "Arial", + "_lineHeight": 100, + "_overflow": 0, + "_enableWrapText": true, + "_font": { + "__uuid__": "fb4acba6-6bc7-4eb3-be34-8f2ac9823a80", + "__expectedType__": "cc.TTFFont" + }, + "_isSystemFontUsed": false, + "_spacingX": 0, + "_isItalic": false, + "_isBold": true, + "_isUnderline": false, + "_underlineHeight": 2, + "_cacheMode": 0, + "_enableOutline": true, + "_outlineColor": { + "__type__": "cc.Color", + "r": 179, + "g": 127, + "b": 1, + "a": 255 + }, + "_outlineWidth": 5, + "_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": "3cXrSEqD9A9JsPWQDH5W7p" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 91 + }, + "_enabled": true, + "__prefab": { + "__id__": 97 + }, + "_alignFlags": 18, + "_target": null, + "_left": 0, + "_right": 0, + "_top": 0, + "_bottom": 0, + "_horizontalCenter": 0, + "_verticalCenter": 7.598, + "_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": "fcWZ4zYt1CQqe8rloSTAa6" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "cdS4FjWZhEcLaHHD5Ywr6O", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 90 + }, + "_enabled": true, + "__prefab": { + "__id__": 100 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 580, + "height": 234 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "2dj1eh5ZhEUpGlS7F7v0uN" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 90 + }, + "_enabled": true, + "__prefab": { + "__id__": 102 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "ba58112d-788c-465d-a2f3-46b468026d03@f9941", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "6c+ZUsYNVN5JaW1YSlzMLJ" + }, + { + "__type__": "cc.Widget", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 90 + }, + "_enabled": true, + "__prefab": { + "__id__": 104 + }, + "_alignFlags": 12, + "_target": null, + "_left": -453.172, + "_right": 0, + "_top": 0, + "_bottom": -676.906, + "_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": "c54ta1PX9DPpj0q9VPPLo7" + }, + { + "__type__": "cc.Button", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 90 + }, + "_enabled": true, + "__prefab": { + "__id__": 106 + }, + "clickEvents": [], + "_interactable": true, + "_transition": 3, + "_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": "99QsBWy9lMnZxgHAxX8Y8c" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "45/G04SudBk7ZlgsBN2dQ9", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 71 + }, + "_enabled": true, + "__prefab": { + "__id__": 109 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 100, + "height": 100 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "a5MnuAzU9O3JdTGLyQtdhV" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "a4NJtsKllKn5djdZ/7Vf1f", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, { "__type__": "cc.UITransform", "_name": "", @@ -1759,7 +2735,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 72 + "__id__": 112 }, "_contentSize": { "__type__": "cc.Size", @@ -1787,7 +2763,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 74 + "__id__": 114 }, "_customMaterial": null, "_srcBlendFactor": 2, @@ -1845,7 +2821,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 77 + "__id__": 117 }, "_contentSize": { "__type__": "cc.Size", @@ -1873,7 +2849,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 79 + "__id__": 119 }, "_alignFlags": 45, "_target": null, @@ -1909,7 +2885,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 81 + "__id__": 121 }, "animationNodes": [], "backdropNode": null, @@ -1921,15 +2897,30 @@ "contentLabel": { "__id__": 30 }, - "buttonHintLabel": { + "buttonConfirmLabel": { "__id__": 37 }, + "actionConfirmLabel": { + "__id__": 76 + }, + "buttonCancelLabel": { + "__id__": 94 + }, "closeBtn": { "__id__": 11 }, - "buttonHint": { + "buttonConfirm": { "__id__": 33 }, + "actionDouble": { + "__id__": 71 + }, + "actionConfirm": { + "__id__": 72 + }, + "actionCancel": { + "__id__": 90 + }, "_id": "" }, { diff --git a/assets/prefabs/CommonModal.ts b/assets/prefabs/CommonModal.ts index 08bdff9..0c70163 100644 --- a/assets/prefabs/CommonModal.ts +++ b/assets/prefabs/CommonModal.ts @@ -8,8 +8,10 @@ export type CommonModalAction = () => void | boolean; export interface CommonModalCallbacks { /** 点击关闭按钮回调,返回 false 可阻止默认关闭 */ onClose?: CommonModalAction; - /** 点击主按钮回调,返回 false 可阻止默认关闭 */ + /** 点击确认按钮回调,返回 false 可阻止默认关闭 */ onConfirm?: CommonModalAction; + /** 点击取消按钮回调,返回 false 可阻止默认关闭 */ + onCancel?: CommonModalAction; } export interface CommonModalParams extends CommonModalCallbacks { @@ -17,14 +19,16 @@ export interface CommonModalParams extends CommonModalCallbacks { title?: string; /** 弹窗内容 */ content?: string; - /** 主按钮文案 */ - buttonHint?: string; - /** 主按钮文案别名,方便业务侧按 buttonText 调用 */ - buttonText?: string; + /** 确认按钮文案 */ + buttonConfirm?: string; + /** 取消按钮文案,传入后展示双按钮区域 */ + buttonCancel?: string; /** 点击关闭按钮后是否自动关闭弹窗,默认 true */ closeOnClose?: boolean; - /** 点击主按钮后是否自动关闭弹窗,默认 true */ + /** 点击确认按钮后是否自动关闭弹窗,默认 true */ closeOnConfirm?: boolean; + /** 点击取消按钮后是否自动关闭弹窗,默认 true */ + closeOnCancel?: boolean; /** 关闭时是否销毁节点,默认 true */ destroyOnClose?: boolean; /** 弹窗层级,默认 CommonModal.MODAL_Z_INDEX */ @@ -37,7 +41,8 @@ export class CommonModal extends BaseModal { private static readonly DEFAULT_TITLE = '温馨提示'; private static readonly DEFAULT_CONTENT = ''; - private static readonly DEFAULT_BUTTON_HINT = '确定'; + private static readonly DEFAULT_BUTTON_CONFIRM = '确定'; + private static readonly DEFAULT_BUTTON_CANCEL = '取消'; @property({ type: Label, tooltip: '标题文本' }) titleLabel: Label | null = null; @@ -45,22 +50,40 @@ export class CommonModal extends BaseModal { @property({ type: Label, tooltip: '内容文本' }) contentLabel: Label | null = null; - @property({ type: Label, tooltip: '主按钮文本' }) - buttonHintLabel: Label | null = null; + @property({ type: Label, tooltip: '确认按钮文本' }) + buttonConfirmLabel: Label | null = null; + + @property({ type: Label, tooltip: '双按钮确认文本' }) + actionConfirmLabel: Label | null = null; + + @property({ type: Label, tooltip: '取消按钮文本' }) + buttonCancelLabel: Label | null = null; @property({ type: Node, tooltip: '关闭按钮节点' }) closeBtn: Node | null = null; - @property({ type: Node, tooltip: '主按钮节点' }) - buttonHint: Node | null = null; + @property({ type: Node, tooltip: '单确认按钮节点' }) + buttonConfirm: Node | null = null; + + @property({ type: Node, tooltip: '双按钮容器节点' }) + actionDouble: Node | null = null; + + @property({ type: Node, tooltip: '双按钮确认节点' }) + actionConfirm: Node | null = null; + + @property({ type: Node, tooltip: '双按钮取消节点' }) + actionCancel: Node | null = null; private _title: string = CommonModal.DEFAULT_TITLE; private _content: string = CommonModal.DEFAULT_CONTENT; - private _buttonHintText: string = CommonModal.DEFAULT_BUTTON_HINT; + private _buttonConfirmText: string = CommonModal.DEFAULT_BUTTON_CONFIRM; + private _buttonCancelText: string = CommonModal.DEFAULT_BUTTON_CANCEL; private _callbacks: CommonModalCallbacks = {}; private _closeOnClose: boolean = true; private _closeOnConfirm: boolean = true; + private _closeOnCancel: boolean = true; private _destroyOnClose: boolean = true; + private _useDoubleActions: boolean = false; private _screenSize: Size | null = null; private _loaded: boolean = false; @@ -71,7 +94,7 @@ export class CommonModal extends BaseModal { * CommonModal.show(this.commonModalPrefab, { * title: '提示', * content: '是否继续?', - * buttonHint: '继续', + * buttonConfirm: '继续', * onConfirm: () => this.startGame() * }); */ @@ -116,14 +139,18 @@ export class CommonModal extends BaseModal { setConfig(params: CommonModalParams = {}): void { this._title = params.title ?? CommonModal.DEFAULT_TITLE; this._content = params.content ?? CommonModal.DEFAULT_CONTENT; - this._buttonHintText = params.buttonHint ?? params.buttonText ?? CommonModal.DEFAULT_BUTTON_HINT; + this._buttonConfirmText = params.buttonConfirm ?? CommonModal.DEFAULT_BUTTON_CONFIRM; + this._buttonCancelText = params.buttonCancel ?? CommonModal.DEFAULT_BUTTON_CANCEL; this._callbacks = { onClose: params.onClose, - onConfirm: params.onConfirm + onConfirm: params.onConfirm, + onCancel: params.onCancel }; this._closeOnClose = params.closeOnClose ?? true; this._closeOnConfirm = params.closeOnConfirm ?? true; + this._closeOnCancel = params.closeOnCancel ?? true; this._destroyOnClose = params.destroyOnClose ?? true; + this._useDoubleActions = this._shouldUseDoubleActions(params); this._applyContent(); } @@ -137,8 +164,14 @@ export class CommonModal extends BaseModal { this._applyContent(); } - setButtonHint(buttonHint: string): void { - this._buttonHintText = buttonHint; + setButtonConfirm(buttonConfirm: string): void { + this._buttonConfirmText = buttonConfirm; + this._applyContent(); + } + + setButtonCancel(buttonCancel: string): void { + this._buttonCancelText = buttonCancel; + this._useDoubleActions = true; this._applyContent(); } @@ -193,16 +226,26 @@ export class CommonModal extends BaseModal { this.animationNodes = this.animationNodes.length > 0 ? this.animationNodes : (panelNode ? [panelNode] : []); this.closeBtn = this.closeBtn ?? this._findNode('dialogPanel/closeBtn'); - this.buttonHint = this.buttonHint ?? this._findNode('dialogPanel/ButtonHint'); + this.buttonConfirm = this.buttonConfirm ?? this._findNode('dialogPanel/ButtonConfirm'); + this.actionDouble = this.actionDouble ?? this._findNode('dialogPanel/ActionDouble'); + this.actionConfirm = this.actionConfirm ?? this._findNode('dialogPanel/ActionDouble/ButtonConfirm'); + this.actionCancel = this.actionCancel ?? this._findNode('dialogPanel/ActionDouble/ButtonCancel'); this.titleLabel = this.titleLabel ?? this._findNode('dialogPanel/Title')?.getComponent(Label) ?? null; this.contentLabel = this.contentLabel ?? this._findNode('dialogPanel/Content')?.getComponent(Label) ?? null; - this.buttonHintLabel = this.buttonHintLabel - ?? this._findNode('dialogPanel/ButtonHint/Label')?.getComponent(Label) + this.buttonConfirmLabel = this.buttonConfirmLabel + ?? this._findNode('dialogPanel/ButtonConfirm/Label')?.getComponent(Label) + ?? null; + this.actionConfirmLabel = this.actionConfirmLabel + ?? this._findNode('dialogPanel/ActionDouble/ButtonConfirm/Label')?.getComponent(Label) + ?? null; + this.buttonCancelLabel = this.buttonCancelLabel + ?? this._findNode('dialogPanel/ActionDouble/ButtonCancel/Label')?.getComponent(Label) ?? null; } private _applyContent(): void { this._resolveNodes(); + this._applyActionMode(); if (this.titleLabel) { this.titleLabel.string = this._title; @@ -212,8 +255,16 @@ export class CommonModal extends BaseModal { this.contentLabel.string = this._content; } - if (this.buttonHintLabel) { - this.buttonHintLabel.string = this._buttonHintText; + if (this.buttonConfirmLabel) { + this.buttonConfirmLabel.string = this._buttonConfirmText; + } + + if (this.actionConfirmLabel) { + this.actionConfirmLabel.string = this._buttonConfirmText; + } + + if (this.buttonCancelLabel) { + this.buttonCancelLabel.string = this._buttonCancelText; } } @@ -235,8 +286,16 @@ export class CommonModal extends BaseModal { this.closeBtn.on(Node.EventType.TOUCH_END, this._onCloseClick, this); } - if (this.buttonHint) { - this.buttonHint.on(Node.EventType.TOUCH_END, this._onConfirmClick, this); + if (this.buttonConfirm) { + this.buttonConfirm.on(Node.EventType.TOUCH_END, this._onConfirmClick, this); + } + + if (this.actionConfirm) { + this.actionConfirm.on(Node.EventType.TOUCH_END, this._onConfirmClick, this); + } + + if (this.actionCancel) { + this.actionCancel.on(Node.EventType.TOUCH_END, this._onCancelClick, this); } } @@ -245,8 +304,16 @@ export class CommonModal extends BaseModal { this.closeBtn.off(Node.EventType.TOUCH_END, this._onCloseClick, this); } - if (this.buttonHint?.isValid) { - this.buttonHint.off(Node.EventType.TOUCH_END, this._onConfirmClick, this); + if (this.buttonConfirm?.isValid) { + this.buttonConfirm.off(Node.EventType.TOUCH_END, this._onConfirmClick, this); + } + + if (this.actionConfirm?.isValid) { + this.actionConfirm.off(Node.EventType.TOUCH_END, this._onConfirmClick, this); + } + + if (this.actionCancel?.isValid) { + this.actionCancel.off(Node.EventType.TOUCH_END, this._onCancelClick, this); } } @@ -264,6 +331,27 @@ export class CommonModal extends BaseModal { } } + private _onCancelClick(): void { + const shouldContinue = this._callbacks.onCancel?.(); + if (shouldContinue !== false && this._closeOnCancel) { + this.close(); + } + } + + private _applyActionMode(): void { + if (this.buttonConfirm?.isValid) { + this.buttonConfirm.active = !this._useDoubleActions; + } + + if (this.actionDouble?.isValid) { + this.actionDouble.active = this._useDoubleActions; + } + } + + private _shouldUseDoubleActions(params: CommonModalParams): boolean { + return params.buttonCancel !== undefined; + } + private _findNode(path: string): Node | null { const names = path.split('/').filter(Boolean); let current: Node | null = this.node; diff --git a/assets/prefabs/PageLevel.ts b/assets/prefabs/PageLevel.ts index 7fb0671..e9f5136 100644 --- a/assets/prefabs/PageLevel.ts +++ b/assets/prefabs/PageLevel.ts @@ -2132,13 +2132,17 @@ export class PageLevel extends BaseView { } const modal = CommonModal.show(this.commonModalPrefab, { - title: '切换下一题', - content: '确认进入下一题吗?', - buttonHint: '确认', + title: '提示', + content: '还有时间,确认进入下一题吗?', + buttonConfirm: '确认', + buttonCancel: '再想想', zIndex: CommonModal.MODAL_Z_INDEX + 1, onClose: () => { this._commonModalNode = null; }, + onCancel: () => { + this._commonModalNode = null; + }, onConfirm: () => { this._commonModalNode = null; onConfirm();