feat: 支持关卡详情页 UI
This commit is contained in:
23
AGENTS.md
23
AGENTS.md
@@ -12,6 +12,27 @@
|
||||
## 测试与验证
|
||||
仓库当前未配置 Jest、Vitest 一类自动化测试。提交前至少完成三项验证:1. 编辑器预览主流程可进入页面;2. 目标平台构建成功;3. 涉及微信能力时,在真机或开发者工具验证登录、分享、隐私授权等流程。若修改接口或体力/关卡逻辑,补充手动验证步骤到 PR 描述。
|
||||
|
||||
## 好友分享挑战链路
|
||||
当前好友分享挑战是独立于普通闯关的一条链路,核心入口和数据流如下。
|
||||
|
||||
1. 选题入口在首页 `PageHome`,点击 `PK` 按钮后进入 `PageWriteLevels`,不是从普通 `PageLevel` 内发起。[assets/prefabs/PageHome.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageHome.ts#L153)
|
||||
2. `PageWriteLevels` 会通过 `CompletedLevelsManager.fetch()` 拉取当前用户“已通关关卡”列表,只允许从这些题里选题;当前规则要求必须选满 `6` 关才能预览或正式创建分享。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L140) [assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L507)
|
||||
3. 预览按钮只做本地预览:把 `selectedIndices` 和 `shareTitle` 传给 `PagePreviewLevels`,后者再从 `CompletedLevelsManager` 缓存中按索引读取答案、提示和封面图展示,不会请求后端。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L525) [assets/prefabs/PagePreviewLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PagePreviewLevels.ts#L108)
|
||||
4. 正式分享时,`PageWriteLevels` 会把选中索引转成 `levelIds`,调用 `ShareManager.createShare(title, levelIds)` 命中 `POST /share` 创建挑战,服务端返回 `shareCode`。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L536) [assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L53)
|
||||
5. 创建成功后,页面会尝试补充一次发起者头像昵称信息,再调用 `WxSDK.shareAppMessage` 发起微信转发;真正落到分享卡片上的关键信息只有标题和 `query=shareCode=xxx`,没有把题目内容塞进 query。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L563) [assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L219)
|
||||
6. 被分享用户从微信卡片进入小游戏时,启动页 `PageLoading` 通过 `WxSDK.getShareCodeFromLaunch()` 读取启动参数。如果拿到 `shareCode` 且登录成功,会先调用 `ShareManager.joinShare(code)` 命中加入分享接口,再跳过首页直接打开 `PageLevel`,并带上 `params.shareMode = true`。[assets/PageLoading.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/PageLoading.ts#L82) [assets/scripts/utils/WxSDK.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/WxSDK.ts#L302)
|
||||
7. `ShareManager.joinShare()` 会把服务端返回的分享关卡列表转成运行时 `RuntimeLevelConfig[]`,缓存到内存里;这里不会再走普通闯关的 `AuthManager.nextLevel` / `LevelDataManager` / `enterLevel` 链路,首关图片会被预加载,后续关卡按需懒加载。[assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L73) [assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L150)
|
||||
8. `PageLevel` 在 `shareMode` 下会把 `_shareLevelIndex` 置为 `0`,进入 `_enterAndInitLevel()` 时直接从 `ShareManager.ensureShareLevelReady(index)` 取当前题配置,跳过普通模式里的 `StaminaManager.enterLevel()`,因此分享挑战不消耗体力,也不依赖普通闯关的 enter 接口回填答案和提示。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L258) [assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L330)
|
||||
9. 分享挑战里的作答判定仍然完全在 `PageLevel.onSubmitAnswer()` 本地完成,即把用户输入与当前 `config.answer` 做字符串相等比较;答对后走成功弹窗和下一题,答错后走错误弹窗。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1504)
|
||||
10. 分享模式通关后只会上报 `POST /share/progress`,参数是 `shareCode + levelId + passed + timeSpent`。当前代码只在答对时调用,超时和答错不会上报失败结果,所以服务端拿到的是“成功通关进度”,不是完整作答事件流。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1566) [assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L187)
|
||||
11. 分享模式切下一题时只是 `_shareLevelIndex++`,直到分享题单做完后清掉 `ShareManager` 的内存态并 `replace('PageHome')` 返回首页。中途从超时弹窗回首页,也会先清理分享态。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1831) [assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1880)
|
||||
|
||||
## 已知约束与缺口
|
||||
1. `PageLevel` 的分享模式标题显示的是“第 1 关、第 2 关”这种分享内序号,不是原题库真实关卡号。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1004)
|
||||
2. `PassModal` 和 `TimeoutModal` 里的分享按钮仍然发的是普通 `level=...` query,不是 `shareCode` 挑战链路;这两处分享目前不能把用户重新带回当前好友挑战,只是普通分享文案。[assets/prefabs/PassModal.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PassModal.ts#L453) [assets/prefabs/TimeoutModal.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/TimeoutModal.ts#L136)
|
||||
3. `ShareManager.joinShare()` 构造 `RuntimeLevelConfig` 时没有填 `timeLimit`,而 `PageLevel` 会用 `config.timeLimit ?? 60` 兜底,所以分享题当前统一按 60 秒处理,除非后端后续补字段、前端同步接入。[assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L91) [assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L416)
|
||||
4. `PagePreviewLevels` 和 `PageWriteLevels` 的选题/预览都依赖“索引对应同一份 completed list”的前提。如果列表数据在两个页面生命周期之间发生变化,按索引取题会有错位风险,更稳妥的做法其实是直接传 `levelIds` 或完整快照。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L528) [assets/prefabs/PagePreviewLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PagePreviewLevels.ts#L192)
|
||||
|
||||
## 提交与 Pull Request 规范
|
||||
Git 历史采用 Conventional Commits,且摘要多为中文,例如 `feat: 支持分享关卡通关上报`、`fix: 修复关卡排序`、`docs: 添加设计文档`。请继续使用 `feat:`、`fix:`、`perf:`、`docs:` 前缀,首行聚焦单一变更。PR 需说明改动范围、影响页面或模块、验证方式;涉及 UI 请附截图或录屏,涉及微信环境差异请写明复现条件与平台。
|
||||
|
||||
@@ -77,4 +98,4 @@ Stats: 47 obs (10,663t read) | 538,681t work | 98% savings
|
||||
216 " 🟣 PageLevel.ts punchline 显隐控制逻辑对接完成
|
||||
|
||||
Access 539k tokens of past work via get_observations([IDs]) or mem-search skill.
|
||||
</claude-mem-context>
|
||||
</claude-mem-context>
|
||||
|
||||
23
CLAUDE.md
23
CLAUDE.md
@@ -37,3 +37,26 @@ assets/
|
||||
- 继承 `cc.Component` 基类
|
||||
- 生命周期方法: `onLoad` -> `start` -> `update` -> `onDestroy`
|
||||
- 使用 `cc.` 命名空间访问引擎 API(如 `cc.view`, `cc.Node`, `cc.Component` 等)
|
||||
|
||||
## Friend Share Challenge Flow
|
||||
|
||||
当前项目里的好友分享挑战链路不是普通闯关的变体,而是一条单独的模式切换链路。
|
||||
|
||||
1. 发起入口在首页 `PageHome` 的 `PK` 按钮,点击后进入 `PageWriteLevels` 进行选题,而不是从普通关卡页直接发起。[assets/prefabs/PageHome.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageHome.ts#L153)
|
||||
2. `PageWriteLevels` 只允许从当前用户“已通关关卡”中选题,数据来自 `CompletedLevelsManager.fetch()`;当前产品规则要求必须选满 `6` 关。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L140) [assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L507)
|
||||
3. 预览只是本地页面跳转:`PageWriteLevels` 把 `selectedIndices + shareTitle` 传给 `PagePreviewLevels`,后者再从 `CompletedLevelsManager` 当前缓存里按索引读答案、提示和封面图,不会请求后端。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L525) [assets/prefabs/PagePreviewLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PagePreviewLevels.ts#L108)
|
||||
4. 正式分享时,`PageWriteLevels` 会把选中的索引转成 `levelIds`,调用 `ShareManager.createShare(title, levelIds)`,命中 `POST /share` 创建挑战并拿到 `shareCode`。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L536) [assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L53)
|
||||
5. 创建成功后,前端会尝试上传一次发起者头像昵称,再调用 `WxSDK.shareAppMessage` 发微信卡片;关键 query 只有 `shareCode`,好友侧是靠这个码重新拉题单。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L563) [assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L219)
|
||||
6. 好友从微信卡片打开小游戏时,启动页 `PageLoading` 会从 `WxSDK.getShareCodeFromLaunch()` 读取启动参数;只要拿到 `shareCode` 且登录成功,就会调用 `ShareManager.joinShare(code)`,然后跳过首页,直接以 `shareMode=true` 打开 `PageLevel`。[assets/PageLoading.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/PageLoading.ts#L82) [assets/scripts/utils/WxSDK.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/WxSDK.ts#L302)
|
||||
7. `ShareManager.joinShare()` 会把后端返回的分享关卡列表转成内存里的 `RuntimeLevelConfig[]`,首关图立即预加载,后续关卡按需懒加载;这条链路不会走普通模式的 `AuthManager.nextLevel`、`LevelDataManager`、`enterLevel`。[assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L73) [assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L150)
|
||||
8. `PageLevel` 进入分享模式后,当前题数据直接来自 `ShareManager.ensureShareLevelReady(index)`,不会调用 `StaminaManager.enterLevel()`,因此分享挑战不消耗体力,也不依赖 enter 接口补答案和提示。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L258) [assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L330)
|
||||
9. 作答判定仍在 `PageLevel.onSubmitAnswer()` 本地完成,本质就是把用户输入和 `config.answer` 做字符串比较;答对后显示通关链路并切到下一题,答错则弹错误弹窗。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1504)
|
||||
10. 分享模式下只有答对时会调用 `ShareManager.reportLevelProgress(levelId, true, timeSpent)` 上报 `POST /share/progress`。当前没有把答错或超时作为失败事件上报,所以服务端拿到的是“成功进度”,不是完整挑战行为流。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1566) [assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L187)
|
||||
11. 分享模式下切下一题只会 `_shareLevelIndex++`;全部做完后清空分享态并回首页。超时弹窗点回首页时也会先清理分享态,避免脏状态残留。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1831) [assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1880)
|
||||
|
||||
## Current Gaps
|
||||
|
||||
1. 分享模式标题展示的是分享内序号 `第 1 关 / 第 2 关`,不是题库真实关卡号。[assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L1004)
|
||||
2. `PassModal` 和 `TimeoutModal` 内部的分享按钮发的是普通 `level=...` query,不是好友挑战 `shareCode`,所以它们目前不属于这条好友分享挑战链路。[assets/prefabs/PassModal.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PassModal.ts#L453) [assets/prefabs/TimeoutModal.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/TimeoutModal.ts#L136)
|
||||
3. `ShareManager.joinShare()` 当前没有把后端题目的 `timeLimit` 写入 `RuntimeLevelConfig`,而 `PageLevel` 会用 `config.timeLimit ?? 60` 兜底,因此分享题默认统一 60 秒。[assets/scripts/utils/ShareManager.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/scripts/utils/ShareManager.ts#L91) [assets/prefabs/PageLevel.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageLevel.ts#L416)
|
||||
4. 选题页和预览页通过 `selectedIndices` 对同一份 completed list 建立映射,若列表在页面间发生刷新或顺序变化,存在按索引错位的风险;更稳妥的传参应该是 `levelIds` 或完整快照。[assets/prefabs/PageWriteLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PageWriteLevels.ts#L528) [assets/prefabs/PagePreviewLevels.ts](/Users/richard/Documents/code/cocosProject/mp-xieyingeng/assets/prefabs/PagePreviewLevels.ts#L192)
|
||||
|
||||
@@ -9471,6 +9471,36 @@
|
||||
"titleLevelLabel": {
|
||||
"__id__": 22
|
||||
},
|
||||
"bgNode": {
|
||||
"__id__": 2
|
||||
},
|
||||
"pkBgNode": {
|
||||
"__id__": 10
|
||||
},
|
||||
"titleLevelNode": {
|
||||
"__id__": 18
|
||||
},
|
||||
"pkTitleLevelNode": {
|
||||
"__id__": 32
|
||||
},
|
||||
"pkTitleLevelLabel": {
|
||||
"__id__": 36
|
||||
},
|
||||
"liveNode": {
|
||||
"__id__": 106
|
||||
},
|
||||
"pkLevelProgressNode": {
|
||||
"__id__": 130
|
||||
},
|
||||
"pkLevelProgressLabel": {
|
||||
"__id__": 140
|
||||
},
|
||||
"bottomLayoutNode": {
|
||||
"__id__": 248
|
||||
},
|
||||
"pkNextLevelButton": {
|
||||
"__id__": 364
|
||||
},
|
||||
"clickAudio": {
|
||||
"__uuid__": "a68a6314-fb7c-48a9-bd6c-0a65ef665d50",
|
||||
"__expectedType__": "cc.AudioClip"
|
||||
|
||||
@@ -132,6 +132,46 @@ export class PageLevel extends BaseView {
|
||||
@property(Label)
|
||||
titleLevelLabel: Label | null = null;
|
||||
|
||||
/** 普通模式背景 */
|
||||
@property(Node)
|
||||
bgNode: Node | null = null;
|
||||
|
||||
/** 分享 / PK 模式背景 */
|
||||
@property(Node)
|
||||
pkBgNode: Node | null = null;
|
||||
|
||||
/** 普通模式标题容器 */
|
||||
@property(Node)
|
||||
titleLevelNode: Node | null = null;
|
||||
|
||||
/** 分享 / PK 模式标题容器 */
|
||||
@property(Node)
|
||||
pkTitleLevelNode: Node | null = null;
|
||||
|
||||
/** 分享 / PK 模式标题标签 */
|
||||
@property(Label)
|
||||
pkTitleLevelLabel: Label | null = null;
|
||||
|
||||
/** 普通模式体力区域容器 */
|
||||
@property(Node)
|
||||
liveNode: Node | null = null;
|
||||
|
||||
/** 分享 / PK 模式进度容器 */
|
||||
@property(Node)
|
||||
pkLevelProgressNode: Node | null = null;
|
||||
|
||||
/** 分享 / PK 模式进度标签 */
|
||||
@property(Label)
|
||||
pkLevelProgressLabel: Label | null = null;
|
||||
|
||||
/** 普通模式底部按钮区域 */
|
||||
@property(Node)
|
||||
bottomLayoutNode: Node | null = null;
|
||||
|
||||
/** 分享 / PK 模式底部下一题按钮 */
|
||||
@property(Node)
|
||||
pkNextLevelButton: Node | null = null;
|
||||
|
||||
// ========== 配置属性 ==========
|
||||
@property(AudioClip)
|
||||
clickAudio: AudioClip | null = null;
|
||||
@@ -273,10 +313,12 @@ export class PageLevel extends BaseView {
|
||||
}
|
||||
}
|
||||
|
||||
this._refreshModeUI();
|
||||
this.updateStaminaLabel();
|
||||
this.initIconSetting();
|
||||
this.initUnlockButtons();
|
||||
this.initSubmitButton();
|
||||
this.initPkNextLevelButton();
|
||||
|
||||
// 异步加载关卡资源并调用进入关卡接口,完成后启动倒计时
|
||||
this._enterAndInitLevel().catch(err => {
|
||||
@@ -289,8 +331,11 @@ export class PageLevel extends BaseView {
|
||||
*/
|
||||
onViewShow(): void {
|
||||
console.log('[PageLevel] onViewShow');
|
||||
this._refreshModeUI();
|
||||
this.updateStaminaLabel();
|
||||
this._startStaminaRecoverTimer();
|
||||
if (!this._isShareMode) {
|
||||
this._startStaminaRecoverTimer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,6 +364,7 @@ export class PageLevel extends BaseView {
|
||||
this.unLockTipsBtn?.off(Node.EventType.TOUCH_END);
|
||||
this.addTimeBtn?.off(Node.EventType.TOUCH_END);
|
||||
this.submitButton?.off(Node.EventType.TOUCH_END, this.onSubmitAnswer, this);
|
||||
this.pkNextLevelButton?.off(Node.EventType.TOUCH_END, this.onPkNextLevelClick, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -428,6 +474,7 @@ export class PageLevel extends BaseView {
|
||||
|
||||
// 设置关卡标题
|
||||
this.updateTitleLevelLabel();
|
||||
this.updatePkLevelProgressLabel();
|
||||
|
||||
// 隐藏包袱答案,通关后再按 punchline 展示
|
||||
this.hidePunchline();
|
||||
@@ -853,6 +900,24 @@ export class PageLevel extends BaseView {
|
||||
console.log('[PageLevel] 提交按钮事件已绑定');
|
||||
}
|
||||
|
||||
private initPkNextLevelButton(): void {
|
||||
if (!this.pkNextLevelButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pkNextLevelButton.on(Node.EventType.TOUCH_END, this.onPkNextLevelClick, this);
|
||||
console.log('[PageLevel] PK 下一题按钮事件已绑定');
|
||||
}
|
||||
|
||||
private onPkNextLevelClick(): void {
|
||||
if (!this._isShareMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.playClickSound();
|
||||
void this.goToNextLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击解锁线索(顺序解锁:先线索2,再线索3;全部解锁后切换为查看答案入口)
|
||||
*/
|
||||
@@ -993,9 +1058,64 @@ export class PageLevel extends BaseView {
|
||||
}
|
||||
|
||||
private updateTitleLevelLabel(): void {
|
||||
if (!this.titleLevelLabel) return;
|
||||
const titleText = `第 ${this.getDisplayLevelNumber()} 关`;
|
||||
|
||||
this.titleLevelLabel.string = `第 ${this.getDisplayLevelNumber()} 关`;
|
||||
if (this.titleLevelLabel) {
|
||||
this.titleLevelLabel.string = titleText;
|
||||
}
|
||||
|
||||
if (this.pkTitleLevelLabel) {
|
||||
this.pkTitleLevelLabel.string = titleText;
|
||||
}
|
||||
}
|
||||
|
||||
private updatePkLevelProgressLabel(): void {
|
||||
if (!this.pkLevelProgressLabel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._isShareMode) {
|
||||
this.pkLevelProgressLabel.string = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const totalLevels = ShareManager.instance.getShareLevelCount();
|
||||
const currentIndex = this._shareLevelIndex + 1;
|
||||
this.pkLevelProgressLabel.string = totalLevels > 0
|
||||
? `${currentIndex}/${totalLevels}`
|
||||
: `${currentIndex}`;
|
||||
}
|
||||
|
||||
private _refreshModeUI(): void {
|
||||
const isPkMode = this._isShareMode;
|
||||
|
||||
if (this.bgNode) {
|
||||
this.bgNode.active = !isPkMode;
|
||||
}
|
||||
if (this.pkBgNode) {
|
||||
this.pkBgNode.active = isPkMode;
|
||||
}
|
||||
if (this.titleLevelNode) {
|
||||
this.titleLevelNode.active = !isPkMode;
|
||||
}
|
||||
if (this.pkTitleLevelNode) {
|
||||
this.pkTitleLevelNode.active = isPkMode;
|
||||
}
|
||||
if (this.liveNode) {
|
||||
this.liveNode.active = !isPkMode;
|
||||
}
|
||||
if (this.pkLevelProgressNode) {
|
||||
this.pkLevelProgressNode.active = isPkMode;
|
||||
}
|
||||
if (this.bottomLayoutNode) {
|
||||
this.bottomLayoutNode.active = !isPkMode;
|
||||
}
|
||||
if (this.pkNextLevelButton) {
|
||||
this.pkNextLevelButton.active = isPkMode;
|
||||
}
|
||||
|
||||
this.updateTitleLevelLabel();
|
||||
this.updatePkLevelProgressLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1434,6 +1554,10 @@ export class PageLevel extends BaseView {
|
||||
* 更新体力值显示(仅值变化时更新 UI)
|
||||
*/
|
||||
private updateStaminaLabel(): void {
|
||||
if (this._isShareMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.liveLabel) {
|
||||
const stamina = StaminaManager.instance.getStamina();
|
||||
const maxStamina = this._getStaminaMax(stamina);
|
||||
@@ -1449,6 +1573,10 @@ export class PageLevel extends BaseView {
|
||||
* 启动体力恢复倒计时 UI
|
||||
*/
|
||||
private _startStaminaRecoverTimer(): void {
|
||||
if (this._isShareMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._stopStaminaRecoverTimer();
|
||||
|
||||
const stamina = StaminaManager.instance.getStamina();
|
||||
@@ -1889,6 +2017,8 @@ export class PageLevel extends BaseView {
|
||||
ViewManager.instance.replace('PageHome');
|
||||
return;
|
||||
}
|
||||
|
||||
this._refreshModeUI();
|
||||
} else {
|
||||
// 正常模式:使用 complete 返回的 nextLevel
|
||||
if (!this._nextLevelData) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
assets/resources/images/Banner3.png
Normal file
BIN
assets/resources/images/Banner3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
134
assets/resources/images/Banner3.png.meta
Normal file
134
assets/resources/images/Banner3.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "dd4fde67-0616-40da-b10f-92d9babea9fa",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "dd4fde67-0616-40da-b10f-92d9babea9fa@6c48a",
|
||||
"displayName": "Banner3",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "dd4fde67-0616-40da-b10f-92d9babea9fa",
|
||||
"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": "dd4fde67-0616-40da-b10f-92d9babea9fa@f9941",
|
||||
"displayName": "Banner3",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 828,
|
||||
"height": 156,
|
||||
"rawWidth": 828,
|
||||
"rawHeight": 156,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-414,
|
||||
-78,
|
||||
0,
|
||||
414,
|
||||
-78,
|
||||
0,
|
||||
-414,
|
||||
78,
|
||||
0,
|
||||
414,
|
||||
78,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
156,
|
||||
828,
|
||||
156,
|
||||
0,
|
||||
0,
|
||||
828,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-414,
|
||||
-78,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
414,
|
||||
78,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "dd4fde67-0616-40da-b10f-92d9babea9fa@6c48a",
|
||||
"atlasUuid": "",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"hasAlpha": true,
|
||||
"fixAlphaTransparencyArtifacts": false,
|
||||
"redirect": "dd4fde67-0616-40da-b10f-92d9babea9fa@6c48a"
|
||||
}
|
||||
}
|
||||
BIN
assets/resources/images/bg_purple.jpg
Normal file
BIN
assets/resources/images/bg_purple.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 162 KiB |
134
assets/resources/images/bg_purple.jpg.meta
Normal file
134
assets/resources/images/bg_purple.jpg.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "4ff19088-ea59-400a-a9f3-2653dbc63acf",
|
||||
"files": [
|
||||
".jpg",
|
||||
".json"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "4ff19088-ea59-400a-a9f3-2653dbc63acf@6c48a",
|
||||
"displayName": "bg_purple",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "4ff19088-ea59-400a-a9f3-2653dbc63acf",
|
||||
"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": "4ff19088-ea59-400a-a9f3-2653dbc63acf@f9941",
|
||||
"displayName": "bg_purple",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 1376,
|
||||
"height": 3064,
|
||||
"rawWidth": 1376,
|
||||
"rawHeight": 3064,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-688,
|
||||
-1532,
|
||||
0,
|
||||
688,
|
||||
-1532,
|
||||
0,
|
||||
-688,
|
||||
1532,
|
||||
0,
|
||||
688,
|
||||
1532,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
3064,
|
||||
1376,
|
||||
3064,
|
||||
0,
|
||||
0,
|
||||
1376,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-688,
|
||||
-1532,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
688,
|
||||
1532,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "4ff19088-ea59-400a-a9f3-2653dbc63acf@6c48a",
|
||||
"atlasUuid": "",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"fixAlphaTransparencyArtifacts": false,
|
||||
"hasAlpha": false,
|
||||
"redirect": "4ff19088-ea59-400a-a9f3-2653dbc63acf@6c48a"
|
||||
}
|
||||
}
|
||||
BIN
assets/resources/images/pagePK/ChampionPanel.png
Normal file
BIN
assets/resources/images/pagePK/ChampionPanel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 675 KiB |
134
assets/resources/images/pagePK/ChampionPanel.png.meta
Normal file
134
assets/resources/images/pagePK/ChampionPanel.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "b3eda29c-df8d-4d9a-8093-bd91f623da16",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "b3eda29c-df8d-4d9a-8093-bd91f623da16@6c48a",
|
||||
"displayName": "ChampionPanel",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "b3eda29c-df8d-4d9a-8093-bd91f623da16",
|
||||
"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": "b3eda29c-df8d-4d9a-8093-bd91f623da16@f9941",
|
||||
"displayName": "ChampionPanel",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 1471,
|
||||
"height": 1156,
|
||||
"rawWidth": 1471,
|
||||
"rawHeight": 1156,
|
||||
"borderTop": 443,
|
||||
"borderBottom": 196,
|
||||
"borderLeft": 193,
|
||||
"borderRight": 400,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-735.5,
|
||||
-578,
|
||||
0,
|
||||
735.5,
|
||||
-578,
|
||||
0,
|
||||
-735.5,
|
||||
578,
|
||||
0,
|
||||
735.5,
|
||||
578,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
1156,
|
||||
1471,
|
||||
1156,
|
||||
0,
|
||||
0,
|
||||
1471,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-735.5,
|
||||
-578,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
735.5,
|
||||
578,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "b3eda29c-df8d-4d9a-8093-bd91f623da16@6c48a",
|
||||
"atlasUuid": "",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"hasAlpha": true,
|
||||
"fixAlphaTransparencyArtifacts": false,
|
||||
"redirect": "b3eda29c-df8d-4d9a-8093-bd91f623da16@6c48a"
|
||||
}
|
||||
}
|
||||
BIN
assets/resources/images/pagePK/capsule.png
Normal file
BIN
assets/resources/images/pagePK/capsule.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
134
assets/resources/images/pagePK/capsule.png.meta
Normal file
134
assets/resources/images/pagePK/capsule.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "754d81bb-f9d1-440c-9e35-206886101438",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "754d81bb-f9d1-440c-9e35-206886101438@6c48a",
|
||||
"displayName": "capsule",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "754d81bb-f9d1-440c-9e35-206886101438",
|
||||
"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": "754d81bb-f9d1-440c-9e35-206886101438@f9941",
|
||||
"displayName": "capsule",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 468,
|
||||
"height": 163,
|
||||
"rawWidth": 468,
|
||||
"rawHeight": 163,
|
||||
"borderTop": 81,
|
||||
"borderBottom": 81,
|
||||
"borderLeft": 100,
|
||||
"borderRight": 100,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-234,
|
||||
-81.5,
|
||||
0,
|
||||
234,
|
||||
-81.5,
|
||||
0,
|
||||
-234,
|
||||
81.5,
|
||||
0,
|
||||
234,
|
||||
81.5,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
0,
|
||||
163,
|
||||
468,
|
||||
163,
|
||||
0,
|
||||
0,
|
||||
468,
|
||||
0
|
||||
],
|
||||
"nuv": [
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"minPos": [
|
||||
-234,
|
||||
-81.5,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
234,
|
||||
81.5,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "754d81bb-f9d1-440c-9e35-206886101438@6c48a",
|
||||
"atlasUuid": "",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"hasAlpha": true,
|
||||
"fixAlphaTransparencyArtifacts": false,
|
||||
"redirect": "754d81bb-f9d1-440c-9e35-206886101438@6c48a"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user