Compare commits
12 Commits
394b8d2faf
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
411ca8c772 | ||
|
|
b9f3dce173 | ||
|
|
8d2fbbbcf0 | ||
|
|
7355cb9c2e | ||
|
|
332ec0081d | ||
|
|
3bfce30607 | ||
|
|
2a599b0356 | ||
|
|
43afe6085d | ||
|
|
165fef318f | ||
|
|
d78c29000d | ||
|
|
40f7be5200 | ||
|
|
dcbd32b0cd |
122
AGENTS.md
122
AGENTS.md
@@ -40,62 +40,80 @@ Git 历史采用 Conventional Commits,且摘要多为中文,例如 `feat:
|
||||
<claude-mem-context>
|
||||
# Memory Context
|
||||
|
||||
# $CMEM mp-xieyingeng 2026-05-13 8:12am GMT+8
|
||||
# [mp-xieyingeng] recent context, 2026-06-01 11:37am 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 (15,736t read) | 2,461,717t 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)
|
||||
### Apr 27, 2026
|
||||
S1308 移除进入游戏关卡时弹出体力扣减的 toast 提示 (Apr 27 at 9:21 AM)
|
||||
S1310 移除进入游戏体力扣减 toast 并在首页添加体力显示 (Apr 27 at 9:22 AM)
|
||||
S1311 移除体力扣减 toast 并完善首页体验 (Apr 27 at 9:23 AM)
|
||||
S1313 Implement object-fit: cover image scaling in Cocos Creator to prevent downloaded images from being distorted (Apr 27 at 9:26 AM)
|
||||
S1312 Fix image distortion in PageLevel.ts by implementing object-fit: cover behavior for downloaded images (Apr 27 at 9:45 AM)
|
||||
1363 9:45a ✅ 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
|
||||
1551 4:46p 🔄 CommonModal API refactoring: remove buttonHint, clean button logic
|
||||
1552 4:47p 🔄 CommonModal dual-button refactor complete with cleaner API
|
||||
### May 14, 2026
|
||||
1630 4:59p 🟣 PagePKDetail.prefab 新增参与人数标签节点
|
||||
1631 " 🟣 PagePKDetail 新增参与人数标签
|
||||
### Jun 1, 2026
|
||||
1771 11:07a 🔵 List Height Adaptation Issue on Different Resolution Phones in PageWriteLevels
|
||||
1772 " 🔵 PageWriteLevels ScrollView Height Calculation Architecture Fully Mapped
|
||||
1773 " 🔵 LevelList ScrollView Widget Has Only Top Alignment — View Node Has No Widget
|
||||
1774 " 🔵 Root Cause Confirmed: VIEW_HEIGHT=1300 Floor Causes List Overflow on Short Phones
|
||||
1775 11:13a 🔵 PageWriteLevels Prefab Structure Confirmed Clean
|
||||
1777 " 🔄 _resizeScrollViewport Delegates Layout to Cocos Widget System
|
||||
1776 11:14a 🔵 PageWriteLevels Prefab Contains 233 JSON Array Entries
|
||||
1778 11:15a 🟣 PageWriteLevels ScrollView View Node Gets cc.Widget for Auto-Layout
|
||||
1779 " 🔵 PageWriteLevels Layout Node Tree Verified After Widget Changes
|
||||
1780 11:16a 🔵 TypeScript Check Requires Cocos Creator to Generate temp/declarations First
|
||||
1781 " 🔵 New Widget Bottom Inset Produces Shorter Viewport on Small Screens vs Old Minimum
|
||||
1783 " 🔵 PageWriteLevels Bottom Control Layout Constraints Mapped
|
||||
1784 " ✅ ScrollView Widget Bottom Inset Revised from 559.076 to 752.53
|
||||
1782 " 🔵 PageWriteLevels Prefab __id__ Reference Integrity Confirmed Valid
|
||||
1785 11:19a ✅ PageWriteLevels Widget Layout Refactor Complete — Final Diff Confirmed
|
||||
|
||||
Access 539k tokens of past work via get_observations([IDs]) or mem-search skill.
|
||||
Access 2462k tokens of past work via get_observations([IDs]) or mem-search skill.
|
||||
</claude-mem-context>
|
||||
|
||||
17
CLAUDE.md
17
CLAUDE.md
@@ -29,6 +29,23 @@ assets/
|
||||
- **运行预览**: 在 Cocos Creator 编辑器中点击 "Play" 按钮
|
||||
- **构建**: 使用编辑器菜单 `Project > Build` 或快捷键 `Cmd+B`
|
||||
|
||||
## Editor Operations (强制约定)
|
||||
|
||||
**凡是涉及 prefab、scene、node、component 或 Cocos 编辑器内的任何操作,必须使用 `cocos-creator` MCP,不要手工编辑 `.prefab` / `.scene` 的 YAML/JSON 文件。**
|
||||
|
||||
适用范围(非穷举):
|
||||
|
||||
- 创建 / 修改 / 删除 prefab:`mcp__cocos-creator__prefab_*`
|
||||
- 场景增删改、打开/保存场景:`mcp__cocos-creator__scene_*`
|
||||
- 节点结构(增删、移动、改 transform、改属性):`mcp__cocos-creator__node_*`
|
||||
- 组件挂载、属性赋值、引用绑定(Sprite/Label/Button/自定义脚本等):`mcp__cocos-creator__component_*`
|
||||
- 资源管理(导入、查询 UUID、刷新、引用校验):`mcp__cocos-creator__project_*` / `mcp__cocos-creator__assetAdvanced_*`
|
||||
- 场景脚本执行、调试日志、性能数据:`mcp__cocos-creator__debug_*` / `mcp__cocos-creator__sceneAdvanced_*`
|
||||
|
||||
允许直接编辑的文件仍是:`.ts` 脚本源代码(`assets/**/*.ts`)、纯文本配置(`tsconfig.json`、`package.json` 等)。`.prefab` / `.scene` / `.meta` 一律走 MCP,避免 UUID 错位、引用丢失、序列化格式被破坏。
|
||||
|
||||
操作前先用 `scene_get_current_scene` / `node_get_all_nodes` / `prefab_get_prefab_info` 等查询类工具确认当前编辑器状态,不要凭记忆操作。
|
||||
|
||||
## TypeScript Coding
|
||||
|
||||
遵循 Cocos Creator 3.x 组件系统架构:
|
||||
|
||||
BIN
assets/.DS_Store
vendored
BIN
assets/.DS_Store
vendored
Binary file not shown.
@@ -4,6 +4,7 @@ import { ViewManager } from './scripts/core/ViewManager';
|
||||
import { LevelDataManager } from './scripts/utils/LevelDataManager';
|
||||
import { AuthManager } from './scripts/utils/AuthManager';
|
||||
import { ShareManager } from './scripts/utils/ShareManager';
|
||||
import { ShareLaunchHandler } from './scripts/utils/ShareLaunchHandler';
|
||||
import { WxSDK } from './scripts/utils/WxSDK';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@@ -92,6 +93,9 @@ export class PageLoading extends Component {
|
||||
this._updateStatusLabel('正在加载挑战关卡...');
|
||||
const joinSuccess = await ShareManager.instance.joinShare(shareCode);
|
||||
if (joinSuccess) {
|
||||
// 把启动 shareCode 同步给 ShareLaunchHandler,
|
||||
// 避免 wx.onShow 在初始展示时拿到同一个 code 又走一遍 join。
|
||||
ShareLaunchHandler.instance.markActiveShareCode(shareCode);
|
||||
this._updateProgress(1);
|
||||
this._updateStatusLabel('加载完成');
|
||||
// 跳过首页,直接进入分享挑战关卡
|
||||
@@ -134,6 +138,20 @@ export class PageLoading extends Component {
|
||||
this._updateProgress(1);
|
||||
this._updateStatusLabel('加载完成');
|
||||
|
||||
// 兜底:如果在 PageLoading 还在 preload 期间,wx.onShow 已经把游戏切到了分享态
|
||||
// (ShareLaunchHandler 已经 joinShare 成功),这里就不应再覆盖回首页,
|
||||
// 否则用户点了好友分享卡片却看到 PageHome。
|
||||
if (ShareManager.instance.isShareMode) {
|
||||
console.log('[PageLoading] 检测到分享态已激活,跳过首页直达 PageLevel');
|
||||
ViewManager.instance.open('PageLevel', {
|
||||
params: { shareMode: true },
|
||||
onComplete: () => {
|
||||
this.node.destroy();
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
ViewManager.instance.open('PageHome', {
|
||||
onComplete: () => {
|
||||
this.node.destroy();
|
||||
|
||||
@@ -503,6 +503,10 @@
|
||||
"__uuid__": "1b94d42b-a4db-4c0a-8281-4275786810af",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
},
|
||||
"pagePKDetailPrefab": {
|
||||
"__uuid__": "335e525c-17ae-4608-8fe0-23b3fc8a5608",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
},
|
||||
"pagePKEndPrefab": {
|
||||
"__uuid__": "4fc485cf-8c22-47f2-80d0-ae366a380cb6",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
@@ -511,6 +515,10 @@
|
||||
"__uuid__": "cff2809d-6daa-4749-a911-bb99e97b4b54",
|
||||
"__expectedType__": "cc.Prefab"
|
||||
},
|
||||
"buttonClickAudio": {
|
||||
"__uuid__": "798824f1-0e20-48b7-ad8a-fb24d55bf986",
|
||||
"__expectedType__": "cc.AudioClip"
|
||||
},
|
||||
"_id": "c2b3nbzv9JuZmP2jxQyN72"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { _decorator, Component, Prefab } from 'cc';
|
||||
import { _decorator, Component, Prefab, AudioClip } from 'cc';
|
||||
import { ViewManager } from './scripts/core/ViewManager';
|
||||
import { ToastManager } from './scripts/utils/ToastManager';
|
||||
import { AudioManager } from './scripts/utils/AudioManager';
|
||||
import { ShareLaunchHandler } from './scripts/utils/ShareLaunchHandler';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
@@ -24,12 +26,18 @@ export class main extends Component {
|
||||
@property({ type: Prefab, tooltip: '挑战数据页面预制体' })
|
||||
pagePKDataPrefab: Prefab | null = null;
|
||||
|
||||
@property({ type: Prefab, tooltip: '挑战详情页面预制体' })
|
||||
pagePKDetailPrefab: Prefab | null = null;
|
||||
|
||||
@property({ type: Prefab, tooltip: '挑战结算页面预制体' })
|
||||
pagePKEndPrefab: Prefab | null = null;
|
||||
|
||||
@property({ type: Prefab, tooltip: 'Toast 预制体' })
|
||||
toastPrefab: Prefab | null = null;
|
||||
|
||||
@property({ type: AudioClip, tooltip: '通用按钮点击音效' })
|
||||
buttonClickAudio: AudioClip | null = null;
|
||||
|
||||
/**
|
||||
* onLoad 比 start 更早执行
|
||||
* 确保 ViewManager 在 PageLoading.start() 之前初始化
|
||||
@@ -86,6 +94,14 @@ export class main extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.pagePKDetailPrefab) {
|
||||
ViewManager.instance.register('PagePKDetail', {
|
||||
prefab: this.pagePKDetailPrefab,
|
||||
cache: true,
|
||||
zIndex: 4
|
||||
});
|
||||
}
|
||||
|
||||
if (this.pagePKEndPrefab) {
|
||||
ViewManager.instance.register('PagePKEnd', {
|
||||
prefab: this.pagePKEndPrefab,
|
||||
@@ -98,5 +114,12 @@ export class main extends Component {
|
||||
if (this.toastPrefab) {
|
||||
ToastManager.instance.init(this.toastPrefab, this.node);
|
||||
}
|
||||
|
||||
AudioManager.instance.init(this.buttonClickAudio, this.node);
|
||||
|
||||
// 注册 wx.onShow / wx.onHide:
|
||||
// 用户把小游戏退到后台后再点击好友分享卡片,能拿到最新的 shareCode 并直达分享挑战关卡。
|
||||
// 必须在 PageLoading 跑之前注册,这样初始 launch 中的 shareCode 也会被作为种子记下。
|
||||
ShareLaunchHandler.instance.init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5471,7 +5471,7 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 442.03125,
|
||||
"width": 461.40625,
|
||||
"height": 75.6
|
||||
},
|
||||
"_anchorPoint": {
|
||||
@@ -5507,7 +5507,7 @@
|
||||
"b": 0,
|
||||
"a": 255
|
||||
},
|
||||
"_string": "还差3题获得冷场小白2级",
|
||||
"_string": "还差3题,解锁新成就等级",
|
||||
"_horizontalAlign": 1,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 40,
|
||||
|
||||
@@ -7,6 +7,8 @@ import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
||||
import { StaminaInfo } from 'db://assets/scripts/types/ApiTypes';
|
||||
import { AuthManager } from 'db://assets/scripts/utils/AuthManager';
|
||||
import { AchievementTitleManager } from 'db://assets/scripts/utils/AchievementTitleManager';
|
||||
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
||||
import { AudioManager } from 'db://assets/scripts/utils/AudioManager';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
@@ -59,7 +61,7 @@ export class PageHome extends BaseView {
|
||||
/** 是否正在播放体力消耗动画 */
|
||||
private _isAnimating: boolean = false;
|
||||
|
||||
/** 进度游标 0% 时的本地 X 坐标,使用 prefab 当前摆放位置作为起点 */
|
||||
/** 进度游标 0% 时的本地 X 坐标,根据 ProgressBar Bar 子节点的左端推导出来 */
|
||||
private _progressAnchorStartX: number | null = null;
|
||||
|
||||
/**
|
||||
@@ -102,6 +104,7 @@ export class PageHome extends BaseView {
|
||||
private _onStartGameClick(): void {
|
||||
if (this._isAnimating) return;
|
||||
|
||||
AudioManager.instance.playButtonClick();
|
||||
console.log('[PageHome] 开始游戏按钮点击');
|
||||
|
||||
// 体力检查
|
||||
@@ -110,15 +113,23 @@ export class PageHome extends BaseView {
|
||||
return;
|
||||
}
|
||||
|
||||
// 兜底:清空可能残留的好友分享挑战状态,确保进入的是纯主线挑战
|
||||
// 场景:用户从微信好友分享卡片进入挑战 → 退出回首页 → 再次点击开始游戏
|
||||
// 若不清理,缓存的 PageLevel 仍会读到 ShareManager 的分享态数据
|
||||
if (ShareManager.instance.isShareMode) {
|
||||
console.log('[PageHome] 检测到残留的分享挑战状态,清理后再进入主线挑战');
|
||||
ShareManager.instance.clearShareMode();
|
||||
}
|
||||
|
||||
this._isAnimating = true;
|
||||
this._playStaminaCostAnimation()
|
||||
.then(() => {
|
||||
ViewManager.instance.open('PageLevel');
|
||||
ViewManager.instance.open('PageLevel', { params: { shareMode: false } });
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('[PageHome] 体力消耗动画异常:', err);
|
||||
// 异常兜底:直接进入关卡
|
||||
ViewManager.instance.open('PageLevel');
|
||||
ViewManager.instance.open('PageLevel', { params: { shareMode: false } });
|
||||
})
|
||||
.finally(() => {
|
||||
this._isAnimating = false;
|
||||
@@ -129,6 +140,7 @@ export class PageHome extends BaseView {
|
||||
* PK按钮点击回调
|
||||
*/
|
||||
private _onPkClick(): void {
|
||||
AudioManager.instance.playButtonClick();
|
||||
console.log('[PageHome] PK按钮点击');
|
||||
ViewManager.instance.open('PageWriteLevels');
|
||||
}
|
||||
@@ -351,11 +363,23 @@ export class PageHome extends BaseView {
|
||||
}
|
||||
|
||||
private _cacheProgressAnchorStartX(): void {
|
||||
if (this._progressAnchorStartX !== null || !this.progressAnchor) {
|
||||
if (this._progressAnchorStartX !== null || !this.titleProgressBar) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._progressAnchorStartX = this.progressAnchor.position.x;
|
||||
const barSprite = this.titleProgressBar.barSprite;
|
||||
if (!barSprite) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bar 节点 anchor 为 (0, 0.5),其本地 position.x 即为进度条可视左端。
|
||||
// ProgressBar 与 ProgressAnchor 共享同一父节点(TitleLevel),
|
||||
// 因此把 Bar 的本地 X 按 ProgressBar 自身的位移与缩放映射到父节点空间,
|
||||
// 才是真正的「0% 起点」。直接拿 progressAnchor.position.x 当起点会导致
|
||||
// 气泡始终被 prefab 摆放偏移量带跑(实测偏右 ~24px)。
|
||||
const progressBarNode = this.titleProgressBar.node;
|
||||
const barLocalX = barSprite.node.position.x;
|
||||
this._progressAnchorStartX = progressBarNode.position.x + barLocalX * progressBarNode.scale.x - 30;
|
||||
}
|
||||
|
||||
private _updateProgressAnchor(progress: number): void {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -37,20 +37,20 @@
|
||||
"__id__": 180
|
||||
},
|
||||
{
|
||||
"__id__": 266
|
||||
"__id__": 272
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 282
|
||||
"__id__": 288
|
||||
},
|
||||
{
|
||||
"__id__": 284
|
||||
"__id__": 290
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 286
|
||||
"__id__": 292
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -4347,20 +4347,20 @@
|
||||
"__id__": 197
|
||||
},
|
||||
{
|
||||
"__id__": 257
|
||||
"__id__": 263
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 263
|
||||
"__id__": 269
|
||||
},
|
||||
{
|
||||
"__id__": 194
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 265
|
||||
"__id__": 271
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -4417,7 +4417,7 @@
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 256
|
||||
"__id__": 262
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -4724,11 +4724,11 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 253
|
||||
"__id__": 259
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 255
|
||||
"__id__": 261
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -4937,27 +4937,27 @@
|
||||
{
|
||||
"__id__": 206
|
||||
},
|
||||
{
|
||||
"__id__": 230
|
||||
},
|
||||
{
|
||||
"__id__": 236
|
||||
},
|
||||
{
|
||||
"__id__": 242
|
||||
},
|
||||
{
|
||||
"__id__": 248
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 248
|
||||
"__id__": 254
|
||||
},
|
||||
{
|
||||
"__id__": 250
|
||||
"__id__": 256
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 252
|
||||
"__id__": 258
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -5005,19 +5005,22 @@
|
||||
},
|
||||
{
|
||||
"__id__": 219
|
||||
},
|
||||
{
|
||||
"__id__": 225
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 225
|
||||
"__id__": 231
|
||||
},
|
||||
{
|
||||
"__id__": 227
|
||||
"__id__": 233
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 229
|
||||
"__id__": 235
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -5456,6 +5459,165 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "RankNumber",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 206
|
||||
},
|
||||
"_children": [],
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 226
|
||||
},
|
||||
{
|
||||
"__id__": 228
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 230
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -9.887,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2.387,
|
||||
"y": 2.387,
|
||||
"z": 2.387
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 225
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 227
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 65.615234375,
|
||||
"height": 136
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "afc2A9N6FGc7UuXiK197iF"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Label",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 225
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 229
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 236,
|
||||
"g": 236,
|
||||
"b": 236,
|
||||
"a": 255
|
||||
},
|
||||
"_string": "4",
|
||||
"_horizontalAlign": 1,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 100,
|
||||
"_fontSize": 100,
|
||||
"_fontFamily": "Arial",
|
||||
"_lineHeight": 100,
|
||||
"_overflow": 0,
|
||||
"_enableWrapText": true,
|
||||
"_font": null,
|
||||
"_isSystemFontUsed": true,
|
||||
"_spacingX": 0,
|
||||
"_isItalic": false,
|
||||
"_isBold": true,
|
||||
"_isUnderline": false,
|
||||
"_underlineHeight": 2,
|
||||
"_cacheMode": 0,
|
||||
"_enableOutline": true,
|
||||
"_outlineColor": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 0,
|
||||
"g": 0,
|
||||
"b": 0,
|
||||
"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": "59LYxrApZB/bVeRXmT+WzJ"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "afXTpxGqpP+IgoyzMhucMS",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
@@ -5466,7 +5628,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 226
|
||||
"__id__": 232
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -5494,7 +5656,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 228
|
||||
"__id__": 234
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -5554,14 +5716,14 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 231
|
||||
"__id__": 237
|
||||
},
|
||||
{
|
||||
"__id__": 233
|
||||
"__id__": 239
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 235
|
||||
"__id__": 241
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -5598,15 +5760,15 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 230
|
||||
"__id__": 236
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 232
|
||||
"__id__": 238
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 490,
|
||||
"width": 549.0625,
|
||||
"height": 88.2
|
||||
},
|
||||
"_anchorPoint": {
|
||||
@@ -5626,11 +5788,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 230
|
||||
"__id__": 236
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 234
|
||||
"__id__": 240
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -5642,15 +5804,15 @@
|
||||
"b": 29,
|
||||
"a": 255
|
||||
},
|
||||
"_string": "西瓜太郎的挑战",
|
||||
"_horizontalAlign": 1,
|
||||
"_string": "西瓜太郎12",
|
||||
"_horizontalAlign": 0,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 70,
|
||||
"_fontSize": 70,
|
||||
"_fontFamily": "Arial",
|
||||
"_lineHeight": 70,
|
||||
"_overflow": 0,
|
||||
"_enableWrapText": true,
|
||||
"_overflow": 1,
|
||||
"_enableWrapText": false,
|
||||
"_font": {
|
||||
"__uuid__": "fb4acba6-6bc7-4eb3-be34-8f2ac9823a80",
|
||||
"__expectedType__": "cc.TTFFont"
|
||||
@@ -5716,14 +5878,14 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 237
|
||||
"__id__": 243
|
||||
},
|
||||
{
|
||||
"__id__": 239
|
||||
"__id__": 245
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 241
|
||||
"__id__": 247
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -5760,11 +5922,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 236
|
||||
"__id__": 242
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 238
|
||||
"__id__": 244
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -5788,11 +5950,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 236
|
||||
"__id__": 242
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 240
|
||||
"__id__": 246
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -5852,14 +6014,14 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 243
|
||||
"__id__": 249
|
||||
},
|
||||
{
|
||||
"__id__": 245
|
||||
"__id__": 251
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 247
|
||||
"__id__": 253
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -5896,11 +6058,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 242
|
||||
"__id__": 248
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 244
|
||||
"__id__": 250
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -5924,11 +6086,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 242
|
||||
"__id__": 248
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 246
|
||||
"__id__": 252
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -6012,7 +6174,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 249
|
||||
"__id__": 255
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6040,7 +6202,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 251
|
||||
"__id__": 257
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -6098,7 +6260,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 254
|
||||
"__id__": 260
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6154,14 +6316,14 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 258
|
||||
"__id__": 264
|
||||
},
|
||||
{
|
||||
"__id__": 260
|
||||
"__id__": 266
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 262
|
||||
"__id__": 268
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -6198,11 +6360,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 257
|
||||
"__id__": 263
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 259
|
||||
"__id__": 265
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6226,11 +6388,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 257
|
||||
"__id__": 263
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 261
|
||||
"__id__": 267
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -6288,7 +6450,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 264
|
||||
"__id__": 270
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6329,26 +6491,26 @@
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 267
|
||||
"__id__": 273
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 273
|
||||
},
|
||||
{
|
||||
"__id__": 275
|
||||
},
|
||||
{
|
||||
"__id__": 277
|
||||
},
|
||||
{
|
||||
"__id__": 279
|
||||
},
|
||||
{
|
||||
"__id__": 281
|
||||
},
|
||||
{
|
||||
"__id__": 283
|
||||
},
|
||||
{
|
||||
"__id__": 285
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 281
|
||||
"__id__": 287
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -6385,20 +6547,20 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 266
|
||||
"__id__": 272
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 268
|
||||
"__id__": 274
|
||||
},
|
||||
{
|
||||
"__id__": 270
|
||||
"__id__": 276
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 272
|
||||
"__id__": 278
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -6435,11 +6597,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 267
|
||||
"__id__": 273
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 269
|
||||
"__id__": 275
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6463,11 +6625,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 267
|
||||
"__id__": 273
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 271
|
||||
"__id__": 277
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -6547,11 +6709,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 266
|
||||
"__id__": 272
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 274
|
||||
"__id__": 280
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6575,11 +6737,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 266
|
||||
"__id__": 272
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 276
|
||||
"__id__": 282
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -6620,11 +6782,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 266
|
||||
"__id__": 272
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 278
|
||||
"__id__": 284
|
||||
},
|
||||
"_alignFlags": 20,
|
||||
"_target": null,
|
||||
@@ -6656,11 +6818,11 @@
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 266
|
||||
"__id__": 272
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 280
|
||||
"__id__": 286
|
||||
},
|
||||
"clickEvents": [],
|
||||
"_interactable": true,
|
||||
@@ -6700,7 +6862,7 @@
|
||||
"_duration": 0.1,
|
||||
"_zoomScale": 1.2,
|
||||
"_target": {
|
||||
"__id__": 266
|
||||
"__id__": 272
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
@@ -6731,7 +6893,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 283
|
||||
"__id__": 289
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -6759,10 +6921,10 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 285
|
||||
"__id__": 291
|
||||
},
|
||||
"backBtn": {
|
||||
"__id__": 266
|
||||
"__id__": 272
|
||||
},
|
||||
"createdListContent": {
|
||||
"__id__": 54
|
||||
@@ -6770,6 +6932,12 @@
|
||||
"createdListItemTemplate": {
|
||||
"__id__": 63
|
||||
},
|
||||
"participatedListContent": {
|
||||
"__id__": 196
|
||||
},
|
||||
"participatedListItemTemplate": {
|
||||
"__id__": 205
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { _decorator, Node, Button, instantiate, Label, ScrollView, UITransform, Sprite, SpriteFrame, Texture2D, ImageAsset, assetManager } from 'cc';
|
||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||
import { CreatedShareItem, ShareParticipantRankSummary } from 'db://assets/scripts/types/ApiTypes';
|
||||
import { CreatedShareItem, ParticipatedShareItem, ShareParticipantRankSummary } from 'db://assets/scripts/types/ApiTypes';
|
||||
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
||||
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
||||
import { AudioManager } from 'db://assets/scripts/utils/AudioManager';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('PagePKData')
|
||||
@@ -11,6 +12,9 @@ export class PagePKData extends BaseView {
|
||||
private static readonly CREATED_ITEM_TOP_PADDING = 20;
|
||||
private static readonly CREATED_ITEM_BOTTOM_PADDING = 20;
|
||||
private static readonly CREATED_ITEM_SPACING = 20;
|
||||
private static readonly PARTICIPATED_ITEM_TOP_PADDING = 20;
|
||||
private static readonly PARTICIPATED_ITEM_BOTTOM_PADDING = 20;
|
||||
private static readonly PARTICIPATED_ITEM_SPACING = 20;
|
||||
|
||||
@property({ type: Node, tooltip: '返回按钮' })
|
||||
backBtn: Node | null = null;
|
||||
@@ -21,8 +25,16 @@ export class PagePKData extends BaseView {
|
||||
@property({ type: Node, tooltip: '我创建的挑战列表条目模板 FriendsPKRankListItem' })
|
||||
createdListItemTemplate: Node | null = null;
|
||||
|
||||
@property({ type: Node, tooltip: '我参与的挑战列表 content 节点' })
|
||||
participatedListContent: Node | null = null;
|
||||
|
||||
@property({ type: Node, tooltip: '我参与的挑战列表条目模板 MyPKListItem' })
|
||||
participatedListItemTemplate: Node | null = null;
|
||||
|
||||
private _createdShares: CreatedShareItem[] = [];
|
||||
private _participatedShares: ParticipatedShareItem[] = [];
|
||||
private _createdItemNodes: Node[] = [];
|
||||
private _participatedItemNodes: Node[] = [];
|
||||
private _createdButtonBindings: Array<{ node: Node; handler: () => void }> = [];
|
||||
private _isLoading: boolean = false;
|
||||
private _renderVersion: number = 0;
|
||||
@@ -33,36 +45,45 @@ export class PagePKData extends BaseView {
|
||||
this.backBtn.on(Button.EventType.CLICK, this._onBackClick, this);
|
||||
}
|
||||
this._hideCreatedItemTemplate();
|
||||
this._hideParticipatedItemTemplate();
|
||||
}
|
||||
|
||||
onViewShow(): void {
|
||||
this._resolveNodes();
|
||||
void this._loadCreatedShares();
|
||||
void this._loadShareLists();
|
||||
}
|
||||
|
||||
onViewHide(): void {
|
||||
this._renderVersion++;
|
||||
}
|
||||
|
||||
private _onBackClick(): void {
|
||||
AudioManager.instance.playButtonClick();
|
||||
ViewManager.instance.back();
|
||||
}
|
||||
|
||||
private async _loadCreatedShares(): Promise<void> {
|
||||
private async _loadShareLists(): Promise<void> {
|
||||
if (this._isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isLoading = true;
|
||||
try {
|
||||
const items = await ShareManager.instance.fetchCreatedShares();
|
||||
if (!items) {
|
||||
const [createdItems, participatedItems] = await Promise.all([
|
||||
ShareManager.instance.fetchCreatedShares(),
|
||||
ShareManager.instance.fetchParticipatedShares(),
|
||||
]);
|
||||
|
||||
if (!createdItems || !participatedItems) {
|
||||
ToastManager.instance.show('获取挑战列表失败,请稍后重试');
|
||||
return;
|
||||
}
|
||||
|
||||
this._createdShares = items;
|
||||
this._createdShares = createdItems ?? [];
|
||||
this._participatedShares = participatedItems ?? [];
|
||||
console.log('[PagePKData] 我创建的挑战列表:', this._createdShares);
|
||||
console.log('[PagePKData] 我参与的挑战列表:', this._participatedShares);
|
||||
this._renderCreatedShares();
|
||||
this._renderParticipatedShares();
|
||||
} finally {
|
||||
this._isLoading = false;
|
||||
}
|
||||
@@ -73,6 +94,7 @@ export class PagePKData extends BaseView {
|
||||
this.backBtn.off(Button.EventType.CLICK, this._onBackClick, this);
|
||||
}
|
||||
this._clearCreatedItems();
|
||||
this._clearParticipatedItems();
|
||||
}
|
||||
|
||||
private _resolveNodes(): void {
|
||||
@@ -87,12 +109,25 @@ export class PagePKData extends BaseView {
|
||||
?? this.createdListContent?.getChildByName('FriendsPKRankListItem')
|
||||
?? null;
|
||||
|
||||
const participatedList = this.node.getChildByName('MyPKList');
|
||||
const participatedView = participatedList?.getChildByName('view');
|
||||
this.participatedListContent = this.participatedListContent ?? participatedView?.getChildByName('content') ?? null;
|
||||
this.participatedListItemTemplate = this.participatedListItemTemplate
|
||||
?? this.participatedListContent?.getChildByName('MyPKListItem')
|
||||
?? null;
|
||||
|
||||
if (!this.createdListContent) {
|
||||
console.warn('[PagePKData] 未找到 FriendsPKRankList/content 节点');
|
||||
}
|
||||
if (!this.createdListItemTemplate) {
|
||||
console.warn('[PagePKData] 未找到 FriendsPKRankListItem 模板节点');
|
||||
}
|
||||
if (!this.participatedListContent) {
|
||||
console.warn('[PagePKData] 未找到 MyPKList/content 节点');
|
||||
}
|
||||
if (!this.participatedListItemTemplate) {
|
||||
console.warn('[PagePKData] 未找到 MyPKListItem 模板节点');
|
||||
}
|
||||
}
|
||||
|
||||
private _renderCreatedShares(): void {
|
||||
@@ -119,6 +154,29 @@ export class PagePKData extends BaseView {
|
||||
this._scrollCreatedListToTop();
|
||||
}
|
||||
|
||||
private _renderParticipatedShares(): void {
|
||||
this._clearParticipatedItems();
|
||||
|
||||
if (!this.participatedListContent || !this.participatedListItemTemplate) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._layoutParticipatedList(this._participatedShares.length);
|
||||
this._hideParticipatedItemTemplate();
|
||||
|
||||
this._participatedShares.forEach((share, index) => {
|
||||
const item = instantiate(this.participatedListItemTemplate!);
|
||||
item.name = `MyPKListItem_${index + 1}`;
|
||||
item.active = true;
|
||||
this.participatedListContent!.addChild(item);
|
||||
this._participatedItemNodes.push(item);
|
||||
this._positionParticipatedItem(item, index);
|
||||
this._applyParticipatedShare(item, share);
|
||||
});
|
||||
|
||||
this._scrollParticipatedListToTop();
|
||||
}
|
||||
|
||||
private _applyCreatedShare(item: Node, share: CreatedShareItem, version: number): void {
|
||||
this._setLabel(this._findLabelIn(item, 'Name'), share.title || '未命名挑战');
|
||||
this._setLabel(this._findLabelIn(item, 'ParticipateLabel'), `共${share.participantCount ?? 0}人参与`);
|
||||
@@ -131,14 +189,51 @@ export class PagePKData extends BaseView {
|
||||
this._setLabel(this._findLabelIn(item, 'RankNumberLabel'), firstParticipant ? `第 ${rankNumber} 名` : '暂无排名');
|
||||
this._loadAvatar(firstParticipant?.avatarUrl ?? '', this._findAvatarSprite(item), version);
|
||||
|
||||
const viewButton = this._findChild(item, 'ViewButton');
|
||||
if (viewButton) {
|
||||
const handler = () => {
|
||||
AudioManager.instance.playButtonClick();
|
||||
this._openShareDetail(share);
|
||||
};
|
||||
viewButton.on(Button.EventType.CLICK, handler, this);
|
||||
this._createdButtonBindings.push({ node: viewButton, handler });
|
||||
}
|
||||
|
||||
const shareButton = this._findChild(item, 'ShareButton');
|
||||
if (shareButton) {
|
||||
const handler = () => ShareManager.instance.triggerWxShare(share.title, share.shareCode);
|
||||
const handler = () => {
|
||||
AudioManager.instance.playButtonClick();
|
||||
ShareManager.instance.triggerWxShare(share.title, share.shareCode);
|
||||
};
|
||||
shareButton.on(Button.EventType.CLICK, handler, this);
|
||||
this._createdButtonBindings.push({ node: shareButton, handler });
|
||||
}
|
||||
}
|
||||
|
||||
private _applyParticipatedShare(item: Node, share: ParticipatedShareItem): void {
|
||||
this._setLabel(this._findLabelIn(item, 'ChallangeName'), share.title || '未命名挑战');
|
||||
this._setLabel(this._findLabelIn(item, 'ParticipateLabel'), `共${share.participantCount ?? 0}人参与`);
|
||||
this._applyParticipatedRank(item, share.userRank);
|
||||
}
|
||||
|
||||
private _openShareDetail(share: CreatedShareItem): void {
|
||||
if (!share.shareCode) {
|
||||
ToastManager.instance.show('挑战数据异常,请稍后重试');
|
||||
return;
|
||||
}
|
||||
|
||||
ViewManager.instance.open('PagePKDetail', {
|
||||
params: {
|
||||
share,
|
||||
shareCode: share.shareCode,
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error('[PagePKData] 打开挑战详情失败:', err);
|
||||
ToastManager.instance.show('打开挑战详情失败,请稍后重试');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _getFirstParticipant(share: CreatedShareItem): ShareParticipantRankSummary | null {
|
||||
return share.firstPlaceUser ?? share.topParticipant ?? share.firstParticipant ?? share.champion ?? null;
|
||||
}
|
||||
@@ -175,6 +270,34 @@ export class PagePKData extends BaseView {
|
||||
);
|
||||
}
|
||||
|
||||
private _layoutParticipatedList(itemCount: number): void {
|
||||
if (!this.participatedListContent || !this.participatedListItemTemplate) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentTransform = this.participatedListContent.getComponent(UITransform);
|
||||
const viewTransform = this.participatedListContent.parent?.getComponent(UITransform) ?? null;
|
||||
const itemTransform = this.participatedListItemTemplate.getComponent(UITransform);
|
||||
if (!contentTransform || !viewTransform || !itemTransform) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentHeight = Math.max(
|
||||
viewTransform.height,
|
||||
PagePKData.PARTICIPATED_ITEM_TOP_PADDING
|
||||
+ PagePKData.PARTICIPATED_ITEM_BOTTOM_PADDING
|
||||
+ itemCount * itemTransform.height
|
||||
+ Math.max(0, itemCount - 1) * PagePKData.PARTICIPATED_ITEM_SPACING,
|
||||
);
|
||||
|
||||
contentTransform.setContentSize(contentTransform.width, contentHeight);
|
||||
this.participatedListContent.setPosition(
|
||||
this.participatedListContent.position.x,
|
||||
viewTransform.height / 2,
|
||||
this.participatedListContent.position.z,
|
||||
);
|
||||
}
|
||||
|
||||
private _positionCreatedItem(item: Node, index: number): void {
|
||||
const itemTransform = item.getComponent(UITransform);
|
||||
if (!itemTransform) {
|
||||
@@ -187,11 +310,55 @@ export class PagePKData extends BaseView {
|
||||
item.setPosition(0, y, item.position.z);
|
||||
}
|
||||
|
||||
private _positionParticipatedItem(item: Node, index: number): void {
|
||||
const itemTransform = item.getComponent(UITransform);
|
||||
if (!itemTransform) {
|
||||
return;
|
||||
}
|
||||
|
||||
const y = -PagePKData.PARTICIPATED_ITEM_TOP_PADDING
|
||||
- itemTransform.height / 2
|
||||
- index * (itemTransform.height + PagePKData.PARTICIPATED_ITEM_SPACING);
|
||||
item.setPosition(0, y, item.position.z);
|
||||
}
|
||||
|
||||
private _scrollCreatedListToTop(): void {
|
||||
const scrollView = this.node.getChildByName('FriendsPKRankList')?.getComponent(ScrollView);
|
||||
scrollView?.scrollToTop(0);
|
||||
}
|
||||
|
||||
private _scrollParticipatedListToTop(): void {
|
||||
const scrollView = this.node.getChildByName('MyPKList')?.getComponent(ScrollView);
|
||||
scrollView?.scrollToTop(0);
|
||||
}
|
||||
|
||||
private _applyParticipatedRank(item: Node, rank: number | null): void {
|
||||
const rankRoot = this._findChild(item, 'Rank');
|
||||
if (!rankRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rank1Badge = this._findChild(rankRoot, 'rank1badge');
|
||||
const rank2Badge = this._findChild(rankRoot, 'rank2badge');
|
||||
const rank3Badge = this._findChild(rankRoot, 'rank3badge');
|
||||
const rankNumberNode = this._findChild(rankRoot, 'RankNumber');
|
||||
const normalizedRank = rank && rank > 0 ? rank : null;
|
||||
|
||||
if (rank1Badge) {
|
||||
rank1Badge.active = normalizedRank === 1;
|
||||
}
|
||||
if (rank2Badge) {
|
||||
rank2Badge.active = normalizedRank === 2;
|
||||
}
|
||||
if (rank3Badge) {
|
||||
rank3Badge.active = normalizedRank === 3;
|
||||
}
|
||||
if (rankNumberNode) {
|
||||
rankNumberNode.active = normalizedRank !== 1 && normalizedRank !== 2 && normalizedRank !== 3;
|
||||
this._setLabel(rankNumberNode.getComponent(Label), normalizedRank ? `${normalizedRank}` : '-');
|
||||
}
|
||||
}
|
||||
|
||||
private _findAvatarSprite(item: Node): Sprite | null {
|
||||
const headNode = this._findChild(item, 'Head');
|
||||
return headNode?.children[0]?.getComponent(Sprite) ?? headNode?.getComponent(Sprite) ?? null;
|
||||
@@ -231,6 +398,18 @@ export class PagePKData extends BaseView {
|
||||
this._hideCreatedItemTemplate();
|
||||
}
|
||||
|
||||
private _clearParticipatedItems(): void {
|
||||
for (const item of this._participatedItemNodes) {
|
||||
if (item.isValid) {
|
||||
item.removeFromParent();
|
||||
item.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
this._participatedItemNodes = [];
|
||||
this._hideParticipatedItemTemplate();
|
||||
}
|
||||
|
||||
private _unbindCreatedButtons(): void {
|
||||
for (const binding of this._createdButtonBindings) {
|
||||
if (binding.node.isValid) {
|
||||
@@ -246,6 +425,12 @@ export class PagePKData extends BaseView {
|
||||
}
|
||||
}
|
||||
|
||||
private _hideParticipatedItemTemplate(): void {
|
||||
if (this.participatedListItemTemplate?.isValid) {
|
||||
this.participatedListItemTemplate.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
private _setLabel(label: Label | null, text: string): void {
|
||||
if (label) {
|
||||
label.string = text;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,411 @@
|
||||
import { _decorator, Component, Node } from 'cc';
|
||||
import { _decorator, assetManager, Button, ImageAsset, instantiate, Label, Node, ScrollView, Sprite, SpriteFrame, Texture2D, UITransform } from 'cc';
|
||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||
import { CreatedShareItem, ShareDetailData, ShareParticipantRankSummary } from 'db://assets/scripts/types/ApiTypes';
|
||||
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
||||
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
interface PagePKDetailParams {
|
||||
share?: CreatedShareItem | null;
|
||||
shareCode?: string | null;
|
||||
detail?: ShareDetailData | null;
|
||||
}
|
||||
|
||||
@ccclass('PagePKDetail')
|
||||
export class PagePKDetail extends Component {
|
||||
start() {
|
||||
export class PagePKDetail extends BaseView {
|
||||
private static readonly RANK_ITEM_TOP_PADDING = 16;
|
||||
private static readonly RANK_ITEM_BOTTOM_PADDING = 16;
|
||||
private static readonly RANK_ITEM_SPACING = 16;
|
||||
|
||||
@property({ type: Label, tooltip: '参与人数文案,例如:66 人参与' })
|
||||
participateLabel: Label | null = null;
|
||||
|
||||
private _backButton: Node | null = null;
|
||||
private _titleLabel: Label | null = null;
|
||||
private _championPanel: Node | null = null;
|
||||
private _rankListContent: Node | null = null;
|
||||
private _rankListItemTemplate: Node | null = null;
|
||||
private _rankItemNodes: Node[] = [];
|
||||
private _renderVersion: number = 0;
|
||||
|
||||
onViewLoad(): void {
|
||||
this._resolveNodes();
|
||||
this._bindEvents();
|
||||
this._hideRankItemTemplate();
|
||||
}
|
||||
|
||||
update(deltaTime: number) {
|
||||
onViewShow(): void {
|
||||
this._resolveNodes();
|
||||
void this._loadAndRenderDetail();
|
||||
}
|
||||
|
||||
onViewHide(): void {
|
||||
this._renderVersion++;
|
||||
}
|
||||
|
||||
onViewDestroy(): void {
|
||||
this._unbindEvents();
|
||||
this._clearRankItems();
|
||||
}
|
||||
|
||||
private _resolveNodes(): void {
|
||||
if (!this._backButton || !this._backButton.isValid) {
|
||||
this._backButton = this.node.getChildByName('ButtonBack');
|
||||
}
|
||||
|
||||
this._titleLabel = this._titleLabel
|
||||
?? this.node.getChildByName('Title')?.getChildByName('Label')?.getComponent(Label)
|
||||
?? null;
|
||||
this.participateLabel = this.participateLabel ?? this._findLabelIn(this.node, 'ParticipateLabel');
|
||||
this._championPanel = this._championPanel ?? this.node.getChildByName('ChampionPanel');
|
||||
|
||||
const rankList = this.node.getChildByName('RankList');
|
||||
const view = rankList?.getChildByName('view');
|
||||
this._rankListContent = this._rankListContent ?? view?.getChildByName('content') ?? null;
|
||||
this._rankListItemTemplate = this._rankListItemTemplate
|
||||
?? this._rankListContent?.getChildByName('RankListItem')
|
||||
?? null;
|
||||
|
||||
if (!this._backButton) {
|
||||
console.warn('[PagePKDetail] 未找到 ButtonBack 节点');
|
||||
}
|
||||
if (!this._rankListContent) {
|
||||
console.warn('[PagePKDetail] 未找到 RankList/content 节点');
|
||||
}
|
||||
if (!this._rankListItemTemplate) {
|
||||
console.warn('[PagePKDetail] 未找到 RankListItem 模板节点');
|
||||
}
|
||||
if (!this.participateLabel) {
|
||||
console.warn('[PagePKDetail] 未找到 ParticipateLabel 节点');
|
||||
}
|
||||
}
|
||||
|
||||
private _bindEvents(): void {
|
||||
if (this._backButton) {
|
||||
this._backButton.on(Button.EventType.CLICK, this._onBackClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
private _unbindEvents(): void {
|
||||
if (this._backButton?.isValid) {
|
||||
this._backButton.off(Button.EventType.CLICK, this._onBackClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
private _onBackClick(): void {
|
||||
ViewManager.instance.back();
|
||||
}
|
||||
|
||||
private async _loadAndRenderDetail(): Promise<void> {
|
||||
const params = this.getParams() as PagePKDetailParams | null;
|
||||
const share = this._resolveShare(params);
|
||||
const passedDetail = params?.detail ?? null;
|
||||
const shareCode = passedDetail?.shareCode ?? params?.shareCode ?? share?.shareCode ?? null;
|
||||
const version = ++this._renderVersion;
|
||||
|
||||
if (passedDetail) {
|
||||
this._renderShareDetail(passedDetail, version);
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderShareSummary(share, version);
|
||||
if (!shareCode) {
|
||||
ToastManager.instance.show('挑战数据异常,请稍后重试');
|
||||
return;
|
||||
}
|
||||
|
||||
const detail = await ShareManager.instance.fetchShareDetail(shareCode);
|
||||
if (version !== this._renderVersion || !this.isShowing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!detail) {
|
||||
ToastManager.instance.show('获取挑战详情失败,请稍后重试');
|
||||
this._renderShareSummary(share, version);
|
||||
return;
|
||||
}
|
||||
|
||||
this._renderShareDetail(detail, version);
|
||||
}
|
||||
|
||||
private _resolveShare(params: PagePKDetailParams | null): CreatedShareItem | null {
|
||||
if (params?.share) {
|
||||
return params.share;
|
||||
}
|
||||
|
||||
const shareCode = params?.shareCode ?? params?.detail?.shareCode;
|
||||
if (!shareCode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ShareManager.instance.createdShares.find((share) => share.shareCode === shareCode) ?? null;
|
||||
}
|
||||
|
||||
private _renderShareSummary(share: CreatedShareItem | null, version: number): void {
|
||||
this._clearRankItems();
|
||||
this._setLabel(this._titleLabel, share?.title || '挑战详情');
|
||||
this._renderParticipateCount(share);
|
||||
this._renderChampion(share ? this._getFirstParticipant(share) : null, share, version);
|
||||
this._layoutRankContent(0);
|
||||
this._scrollRankListToTop();
|
||||
}
|
||||
|
||||
private _renderShareDetail(detail: ShareDetailData, version: number): void {
|
||||
this._clearRankItems();
|
||||
|
||||
const rankings = this._normalizeRankings(detail.rankings ?? []);
|
||||
const champion = rankings.find((participant) => participant.rank === 1) ?? rankings[0] ?? null;
|
||||
const restRankings = rankings.filter((participant) => participant !== champion);
|
||||
|
||||
this._setLabel(this._titleLabel, detail.title || '挑战详情');
|
||||
this._renderParticipateCount(detail);
|
||||
this._renderChampion(champion, detail, version);
|
||||
this._renderRankList(restRankings, version);
|
||||
}
|
||||
|
||||
private _renderParticipateCount(shareInfo: CreatedShareItem | ShareDetailData | null): void {
|
||||
const participantCount = Math.max(0, shareInfo?.participantCount ?? 0);
|
||||
this._setLabel(this.participateLabel, `${participantCount} 人参与`);
|
||||
}
|
||||
|
||||
private _normalizeRankings(rankings: ShareParticipantRankSummary[]): ShareParticipantRankSummary[] {
|
||||
return rankings
|
||||
.map((participant, index) => ({
|
||||
...participant,
|
||||
rank: participant.rank ?? index + 1,
|
||||
}))
|
||||
.sort((a, b) => (a.rank ?? 0) - (b.rank ?? 0));
|
||||
}
|
||||
|
||||
private _getFirstParticipant(share: CreatedShareItem): ShareParticipantRankSummary | null {
|
||||
return share.firstPlaceUser ?? share.topParticipant ?? share.firstParticipant ?? share.champion ?? null;
|
||||
}
|
||||
|
||||
private _renderChampion(
|
||||
champion: ShareParticipantRankSummary | null,
|
||||
shareInfo: CreatedShareItem | ShareDetailData | null,
|
||||
version: number,
|
||||
): void {
|
||||
const panel = this._championPanel;
|
||||
if (!panel) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._setLabel(this._findLabelIn(panel, 'UserName'), this._getParticipantDisplayName(champion, '暂无参与'));
|
||||
this._setLabel(this._findLabelIn(panel, 'RightInfo'), this._formatCorrectText(champion, shareInfo));
|
||||
this._setLabel(this._findLabelIn(panel, 'UsedTime'), this._formatTimeText(champion, shareInfo));
|
||||
this._loadAvatar(champion?.avatarUrl ?? '', this._findAvatarSprite(panel), version);
|
||||
}
|
||||
|
||||
private _renderRankList(participants: ShareParticipantRankSummary[], version: number): void {
|
||||
if (!this._rankListContent || !this._rankListItemTemplate) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._hideRankItemTemplate();
|
||||
this._layoutRankContent(participants.length);
|
||||
|
||||
participants.forEach((participant, index) => {
|
||||
const item = instantiate(this._rankListItemTemplate!);
|
||||
item.name = `RankListItem_${index + 1}`;
|
||||
item.active = true;
|
||||
this._rankListContent!.addChild(item);
|
||||
this._rankItemNodes.push(item);
|
||||
this._positionRankItem(item, index);
|
||||
this._applyRankItem(item, participant, version);
|
||||
});
|
||||
|
||||
this._scrollRankListToTop();
|
||||
}
|
||||
|
||||
private _applyRankItem(item: Node, participant: ShareParticipantRankSummary, version: number): void {
|
||||
const rank = participant.rank ?? 0;
|
||||
const rank2Badge = this._findChild(item, 'rank2badge');
|
||||
const rank3Badge = this._findChild(item, 'rank3badge');
|
||||
const rankNumberNode = this._findChild(item, 'RankNumber');
|
||||
|
||||
if (rank2Badge) {
|
||||
rank2Badge.active = rank === 2;
|
||||
}
|
||||
if (rank3Badge) {
|
||||
rank3Badge.active = rank === 3;
|
||||
}
|
||||
if (rankNumberNode) {
|
||||
rankNumberNode.active = rank !== 2 && rank !== 3;
|
||||
this._setLabel(rankNumberNode.getComponent(Label), rank > 0 ? `${rank}` : '-');
|
||||
}
|
||||
|
||||
this._setLabel(this._findLabelIn(item, 'UserName'), this._getParticipantDisplayName(participant, '微信用户'));
|
||||
this._setLabel(this._findLabelIn(item, 'RightInfo'), this._formatCorrectText(participant, null));
|
||||
this._setLabel(this._findLabelIn(item, 'UsedTime'), this._formatTimeText(participant));
|
||||
this._loadAvatar(participant.avatarUrl ?? '', this._findAvatarSprite(item), version);
|
||||
}
|
||||
|
||||
private _layoutRankContent(itemCount: number): void {
|
||||
if (!this._rankListContent || !this._rankListItemTemplate) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentTransform = this._rankListContent.getComponent(UITransform);
|
||||
const viewTransform = this._rankListContent.parent?.getComponent(UITransform) ?? null;
|
||||
const itemTransform = this._rankListItemTemplate.getComponent(UITransform);
|
||||
if (!contentTransform || !viewTransform || !itemTransform) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentHeight = Math.max(
|
||||
viewTransform.height,
|
||||
PagePKDetail.RANK_ITEM_TOP_PADDING
|
||||
+ PagePKDetail.RANK_ITEM_BOTTOM_PADDING
|
||||
+ itemCount * itemTransform.height
|
||||
+ Math.max(0, itemCount - 1) * PagePKDetail.RANK_ITEM_SPACING,
|
||||
);
|
||||
|
||||
contentTransform.setContentSize(contentTransform.width, contentHeight);
|
||||
this._rankListContent.setPosition(
|
||||
this._rankListContent.position.x,
|
||||
viewTransform.height / 2,
|
||||
this._rankListContent.position.z,
|
||||
);
|
||||
}
|
||||
|
||||
private _positionRankItem(item: Node, index: number): void {
|
||||
const itemTransform = item.getComponent(UITransform);
|
||||
if (!itemTransform) {
|
||||
return;
|
||||
}
|
||||
|
||||
const y = -PagePKDetail.RANK_ITEM_TOP_PADDING
|
||||
- itemTransform.height / 2
|
||||
- index * (itemTransform.height + PagePKDetail.RANK_ITEM_SPACING);
|
||||
item.setPosition(0, y, item.position.z);
|
||||
}
|
||||
|
||||
private _scrollRankListToTop(): void {
|
||||
this.node.getChildByName('RankList')?.getComponent(ScrollView)?.scrollToTop(0);
|
||||
}
|
||||
|
||||
private _formatCorrectText(
|
||||
participant: ShareParticipantRankSummary | null,
|
||||
shareInfo: CreatedShareItem | ShareDetailData | null,
|
||||
): string {
|
||||
if (participant?.correctCount !== undefined && participant.correctCount !== null) {
|
||||
return `答对${participant.correctCount}道`;
|
||||
}
|
||||
|
||||
if (shareInfo && (shareInfo.participantCount ?? 0) <= 0) {
|
||||
return '答对0道';
|
||||
}
|
||||
|
||||
if (shareInfo) {
|
||||
return `共${shareInfo.participantCount ?? 0}人参与`;
|
||||
}
|
||||
|
||||
return '暂无成绩';
|
||||
}
|
||||
|
||||
private _formatTimeText(
|
||||
participant: ShareParticipantRankSummary | null,
|
||||
shareInfo: CreatedShareItem | ShareDetailData | null = null,
|
||||
): string {
|
||||
if (participant?.totalTimeSpent === undefined || participant.totalTimeSpent === null) {
|
||||
if (shareInfo && (shareInfo.participantCount ?? 0) <= 0) {
|
||||
return '用时0秒';
|
||||
}
|
||||
return '暂无用时';
|
||||
}
|
||||
|
||||
const totalSeconds = Math.max(0, Math.round(participant.totalTimeSpent));
|
||||
const minutes = Math.floor(totalSeconds / 60);
|
||||
const seconds = totalSeconds % 60;
|
||||
return `用时${minutes}:${seconds.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
private _getParticipantName(participant: ShareParticipantRankSummary | null): string {
|
||||
return participant?.nickname || participant?.nickName || '';
|
||||
}
|
||||
|
||||
private _getParticipantDisplayName(
|
||||
participant: ShareParticipantRankSummary | null,
|
||||
emptyParticipantFallback: string,
|
||||
): string {
|
||||
if (!participant) {
|
||||
return emptyParticipantFallback;
|
||||
}
|
||||
|
||||
return this._getParticipantName(participant) || '微信用户';
|
||||
}
|
||||
|
||||
private _loadAvatar(url: string, sprite: Sprite | null, version: number): void {
|
||||
if (!sprite) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
assetManager.loadRemote<ImageAsset>(url, (err, imageAsset) => {
|
||||
if (err || !imageAsset || version !== this._renderVersion || !sprite.node.isValid) {
|
||||
if (err) {
|
||||
console.error('[PagePKDetail] 加载头像失败:', url, err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const texture = new Texture2D();
|
||||
texture.image = imageAsset;
|
||||
const spriteFrame = new SpriteFrame();
|
||||
spriteFrame.texture = texture;
|
||||
sprite.spriteFrame = spriteFrame;
|
||||
});
|
||||
}
|
||||
|
||||
private _findAvatarSprite(root: Node): Sprite | null {
|
||||
const avatarNode = this._findChild(root, 'Avatar');
|
||||
return avatarNode?.getComponent(Sprite) ?? null;
|
||||
}
|
||||
|
||||
private _clearRankItems(): void {
|
||||
for (const item of this._rankItemNodes) {
|
||||
if (item.isValid) {
|
||||
item.removeFromParent();
|
||||
item.destroy();
|
||||
}
|
||||
}
|
||||
this._rankItemNodes = [];
|
||||
this._hideRankItemTemplate();
|
||||
}
|
||||
|
||||
private _hideRankItemTemplate(): void {
|
||||
if (this._rankListItemTemplate?.isValid) {
|
||||
this._rankListItemTemplate.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
private _setLabel(label: Label | null, text: string): void {
|
||||
if (label) {
|
||||
label.string = text;
|
||||
}
|
||||
}
|
||||
|
||||
private _findLabelIn(root: Node, nodeName: string): Label | null {
|
||||
return this._findChild(root, nodeName)?.getComponent(Label) ?? null;
|
||||
}
|
||||
|
||||
private _findChild(root: Node, nodeName: string): Node | null {
|
||||
if (root.name === nodeName) {
|
||||
return root;
|
||||
}
|
||||
|
||||
for (const child of root.children) {
|
||||
const found = this._findChild(child, nodeName);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 11
|
||||
@@ -426,7 +426,7 @@
|
||||
"__id__": 25
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 71
|
||||
@@ -2106,8 +2106,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -172.179,
|
||||
"y": -613.418,
|
||||
"x": -142.654,
|
||||
"y": 760.825,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2147,7 +2147,7 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 495,
|
||||
"width": 660,
|
||||
"height": 75.6
|
||||
},
|
||||
"_anchorPoint": {
|
||||
@@ -2186,8 +2186,8 @@
|
||||
"_string": "揭晓以下谐音梗的答案吧",
|
||||
"_horizontalAlign": 1,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 45,
|
||||
"_fontSize": 45,
|
||||
"_actualFontSize": 60,
|
||||
"_fontSize": 60,
|
||||
"_fontFamily": "Arial",
|
||||
"_lineHeight": 60,
|
||||
"_overflow": 0,
|
||||
@@ -2256,9 +2256,6 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 93
|
||||
},
|
||||
{
|
||||
"__id__": 147
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
@@ -2276,7 +2273,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -8.201,
|
||||
"y": -852.319,
|
||||
"y": -183.147,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2313,27 +2310,30 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 94
|
||||
},
|
||||
{
|
||||
"__id__": 140
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 140
|
||||
"__id__": 148
|
||||
},
|
||||
{
|
||||
"__id__": 142
|
||||
"__id__": 150
|
||||
},
|
||||
{
|
||||
"__id__": 144
|
||||
"__id__": 152
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 146
|
||||
"__id__": 154
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"y": 46.995,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2345,9 +2345,9 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
"x": 1.363,
|
||||
"y": 1.363,
|
||||
"z": 1.363
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
@@ -2384,7 +2384,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -10,
|
||||
"y": 125,
|
||||
"y": 540,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -2494,7 +2494,7 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -248.28,
|
||||
"x": -202.789,
|
||||
"y": -12.833,
|
||||
"z": 0
|
||||
},
|
||||
@@ -2507,9 +2507,9 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.537,
|
||||
"y": 0.537,
|
||||
"z": 0.767
|
||||
"x": 0.678,
|
||||
"y": 0.678,
|
||||
"z": 0.968
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
@@ -2789,9 +2789,9 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.488,
|
||||
"y": 0.488,
|
||||
"z": 0.488
|
||||
"x": 0.422,
|
||||
"y": 0.422,
|
||||
"z": 0.422
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
@@ -3461,7 +3461,7 @@
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 780,
|
||||
"height": 400
|
||||
"height": 1080
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -3487,6 +3487,181 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "ScrolViewMask",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 93
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 141
|
||||
},
|
||||
{
|
||||
"__id__": 143
|
||||
},
|
||||
{
|
||||
"__id__": 145
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 147
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 9.242999999999938,
|
||||
"y": -517.9897285399853,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 1,
|
||||
"w": 6.123233995736766e-17
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.7336757153338225,
|
||||
"y": 0.7336757153338225,
|
||||
"z": 0.7336757153338225
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 180,
|
||||
"y": 180,
|
||||
"z": 7.016709298534876e-15
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 140
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 142
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 1444.78,
|
||||
"height": 60
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "57cb61nstNg7YGomw8vXcp"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 140
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 144
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 225,
|
||||
"g": 245,
|
||||
"b": 197,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "faab3d46-e885-4c46-8f19-9f872e7d6973@f9941",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
"_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": "d5kG67QW9Nqplq9kKPqg4X"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Widget",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 140
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 146
|
||||
},
|
||||
"_alignFlags": 44,
|
||||
"_target": null,
|
||||
"_left": -130.757,
|
||||
"_right": -149.243,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
"_isAbsRight": true,
|
||||
"_isAbsTop": true,
|
||||
"_isAbsBottom": true,
|
||||
"_isAbsHorizontalCenter": true,
|
||||
"_isAbsVerticalCenter": true,
|
||||
"_originalWidth": 1080,
|
||||
"_originalHeight": 0,
|
||||
"_alignMode": 2,
|
||||
"_lockFlags": 4,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "60ik9u5ftG4oQNCowOqvJi"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "36lE6eex1I0Jo9+fLrBGoc",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
@@ -3497,12 +3672,12 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 141
|
||||
"__id__": 149
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 780,
|
||||
"height": 400
|
||||
"height": 1080
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -3525,7 +3700,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 143
|
||||
"__id__": 151
|
||||
},
|
||||
"_type": 0,
|
||||
"_inverted": false,
|
||||
@@ -3547,7 +3722,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 145
|
||||
"__id__": 153
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
@@ -3596,181 +3771,6 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "ScrolViewMask",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 92
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 148
|
||||
},
|
||||
{
|
||||
"__id__": 150
|
||||
},
|
||||
{
|
||||
"__id__": 152
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 154
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 9.242999999999938,
|
||||
"y": -173.667,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 1,
|
||||
"w": 6.123233995736766e-17
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 180
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 147
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 149
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 1080,
|
||||
"height": 60
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "57cb61nstNg7YGomw8vXcp"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 147
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 151
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 225,
|
||||
"g": 245,
|
||||
"b": 197,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "faab3d46-e885-4c46-8f19-9f872e7d6973@f9941",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
"_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": "d5kG67QW9Nqplq9kKPqg4X"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Widget",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 147
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 153
|
||||
},
|
||||
"_alignFlags": 40,
|
||||
"_target": null,
|
||||
"_left": -130.757,
|
||||
"_right": -149.243,
|
||||
"_top": 0,
|
||||
"_bottom": 0,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
"_isAbsRight": true,
|
||||
"_isAbsTop": true,
|
||||
"_isAbsBottom": true,
|
||||
"_isAbsHorizontalCenter": true,
|
||||
"_isAbsVerticalCenter": true,
|
||||
"_originalWidth": 1080,
|
||||
"_originalHeight": 0,
|
||||
"_alignMode": 2,
|
||||
"_lockFlags": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "60ik9u5ftG4oQNCowOqvJi"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "36lE6eex1I0Jo9+fLrBGoc",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
@@ -3786,7 +3786,7 @@
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 800,
|
||||
"height": 400
|
||||
"height": 1600
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
|
||||
@@ -3,6 +3,7 @@ import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
||||
import { SubmitShareData, SubmittedShareLevelData } from 'db://assets/scripts/types/ApiTypes';
|
||||
import { AudioManager } from 'db://assets/scripts/utils/AudioManager';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('PagePKEnd')
|
||||
@@ -105,6 +106,7 @@ export class PagePKEnd extends BaseView {
|
||||
}
|
||||
|
||||
private _onHomeClick(): void {
|
||||
AudioManager.instance.playButtonClick();
|
||||
ShareManager.instance.clearShareMode();
|
||||
ViewManager.instance.replace('PageHome');
|
||||
}
|
||||
@@ -226,6 +228,7 @@ export class PagePKEnd extends BaseView {
|
||||
}
|
||||
|
||||
const handler = () => {
|
||||
AudioManager.instance.playButtonClick();
|
||||
if (answerButton?.isValid) {
|
||||
answerButton.active = false;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { _decorator, Node, Button, Label, ScrollView, instantiate, UITransform }
|
||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||
import { CompletedLevelsManager } from 'db://assets/scripts/utils/CompletedLevelsManager';
|
||||
import { AudioManager } from 'db://assets/scripts/utils/AudioManager';
|
||||
import { PreviewLevelItem } from './PreviewLevelItem';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@@ -215,6 +216,7 @@ export class PagePreviewLevels extends BaseView {
|
||||
// ─── 事件处理 ───────────────────────────────────────
|
||||
|
||||
private _onBackClick(): void {
|
||||
AudioManager.instance.playButtonClick();
|
||||
console.log('[PagePreviewLevels] 返回');
|
||||
ViewManager.instance.back();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
import { _decorator, Node, Button, Sprite, Label, Toggle, ScrollView, EditBox, instantiate, UITransform, Vec2, EventTouch, EffectAsset, AudioClip, AudioSource } from 'cc';
|
||||
import { _decorator, Node, Button, Sprite, Label, Toggle, ScrollView, EditBox, instantiate, UITransform, Vec2, EventTouch, EffectAsset, Prefab } from 'cc';
|
||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||
import { CommonModal } from 'db://assets/prefabs/CommonModal';
|
||||
import { CompletedLevelsManager } from 'db://assets/scripts/utils/CompletedLevelsManager';
|
||||
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
||||
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
||||
@@ -11,11 +12,12 @@ import { API_ENDPOINTS, API_TIMEOUT } from 'db://assets/scripts/config/ApiConfig
|
||||
import { HttpUtil } from 'db://assets/scripts/utils/HttpUtil';
|
||||
import { ApiEnvelope, CompletedLevel } from 'db://assets/scripts/types/ApiTypes';
|
||||
import { applyRoundedCorner } from 'db://assets/scripts/utils/roundedMaterial.utils';
|
||||
import { AudioManager } from 'db://assets/scripts/utils/AudioManager';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
* 布局配置
|
||||
* view (ScrollView 的可视窗口) 宽 900,高 1000
|
||||
* view (ScrollView 的可视窗口) 宽 900,高 1100
|
||||
* 关卡 item 固定两列,纵向滚动
|
||||
*
|
||||
* item 的实际显示尺寸从 ListTpl 的 UITransform * scale 派生,
|
||||
@@ -28,7 +30,8 @@ const LAYOUT_CONFIG = {
|
||||
EDGE_PADDING_Y: 32,
|
||||
CENTER_ROWS: 2,
|
||||
VIEW_WIDTH: 900,
|
||||
VIEW_HEIGHT: 1000,
|
||||
VIEW_HEIGHT: 1300,
|
||||
LIST_BOTTOM_GAP_TO_TITLE: 54,
|
||||
};
|
||||
|
||||
/** 必须选择的关卡数量 */
|
||||
@@ -66,17 +69,18 @@ export class PageWriteLevels extends BaseView {
|
||||
@property({ type: EffectAsset, tooltip: '关卡封面圆角材质 EffectAsset' })
|
||||
roundedSpriteEffect: EffectAsset | null = null;
|
||||
|
||||
@property({ type: Prefab, tooltip: '通用弹窗预制体' })
|
||||
commonModalPrefab: Prefab | null = null;
|
||||
|
||||
@property({ tooltip: '关卡封面圆角半径比例(相对于短边,0-0.5)' })
|
||||
coverCornerRadius: number = 0.1;
|
||||
|
||||
@property({ type: AudioClip, tooltip: '关卡项选中/取消选中音效' })
|
||||
itemToggleAudio: AudioClip | null = null;
|
||||
|
||||
private _selectedIndices: Set<number> = new Set();
|
||||
private _levels: CompletedLevel[] = [];
|
||||
private _levelCount: number = 0;
|
||||
private _itemNodes: Node[] = [];
|
||||
private _scrollViewComp: ScrollView | null = null;
|
||||
private _levelListLoadToken: number = 0;
|
||||
|
||||
/** 缓存 view 节点的 UITransform,避免每次 _updateContentSize 重复查找 */
|
||||
private _viewTransform: UITransform | null = null;
|
||||
@@ -88,6 +92,7 @@ export class PageWriteLevels extends BaseView {
|
||||
console.log('[PageWriteLevels] onViewLoad');
|
||||
this._initButtons();
|
||||
this._initScrollView();
|
||||
this._resizeScrollViewport();
|
||||
this._updateSelectionUI();
|
||||
}
|
||||
|
||||
@@ -134,30 +139,60 @@ export class PageWriteLevels extends BaseView {
|
||||
|
||||
onViewShow(): void {
|
||||
console.log('[PageWriteLevels] onViewShow');
|
||||
// 仅首次初始化列表,从预览页返回时保留选中状态
|
||||
if (this._itemNodes.length === 0) {
|
||||
this._resizeScrollViewport();
|
||||
this._updateContentSize();
|
||||
void this._initLevelList();
|
||||
}
|
||||
|
||||
private _resizeScrollViewport(): void {
|
||||
if (!this.scrollView || !this._viewTransform) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollTransform = this.scrollView.getComponent(UITransform);
|
||||
const scrollWidget = this.scrollView.getComponent('cc.Widget') as any;
|
||||
const viewWidget = this._viewTransform.node.getComponent('cc.Widget') as any;
|
||||
|
||||
if (!scrollTransform) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrollWidget?.updateAlignment?.();
|
||||
viewWidget?.updateAlignment?.();
|
||||
|
||||
this._viewTransform.setContentSize(
|
||||
scrollTransform.contentSize.width,
|
||||
scrollTransform.contentSize.height,
|
||||
);
|
||||
}
|
||||
|
||||
private async _initLevelList(): Promise<void> {
|
||||
this._clearList();
|
||||
const loadToken = ++this._levelListLoadToken;
|
||||
const selectedLevelIds = this._getSelectedLevelIdSet();
|
||||
|
||||
// 拉取当前用户所有已通关关卡
|
||||
const levels = await CompletedLevelsManager.instance.fetch();
|
||||
const levels = await CompletedLevelsManager.instance.fetch(true);
|
||||
if (loadToken !== this._levelListLoadToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (levels === null) {
|
||||
console.warn('[PageWriteLevels] 获取已通关关卡失败');
|
||||
ToastManager.instance.show('获取关卡列表失败,请稍后重试');
|
||||
return;
|
||||
}
|
||||
|
||||
this._clearList();
|
||||
this._levels = levels;
|
||||
this._levelCount = this._levels.length;
|
||||
this._restoreSelectedIndices(selectedLevelIds);
|
||||
console.log('[PageWriteLevels] 已通关关卡总数:', this._levelCount);
|
||||
|
||||
if (this._levelCount === 0) {
|
||||
console.warn('[PageWriteLevels] 用户尚未通关任何关卡');
|
||||
ToastManager.instance.show('还没有已通关的关卡,快去玩几关吧');
|
||||
this._updateContentSize();
|
||||
this._updateSelectionUI();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -169,6 +204,29 @@ export class PageWriteLevels extends BaseView {
|
||||
}
|
||||
}
|
||||
|
||||
private _getSelectedLevelIdSet(): Set<string> {
|
||||
const selectedLevelIds = new Set<string>();
|
||||
for (const index of this._selectedIndices) {
|
||||
const level = this._levels[index] ?? null;
|
||||
if (level) {
|
||||
selectedLevelIds.add(level.id);
|
||||
}
|
||||
}
|
||||
return selectedLevelIds;
|
||||
}
|
||||
|
||||
private _restoreSelectedIndices(selectedLevelIds: Set<string>): void {
|
||||
if (selectedLevelIds.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let index = 0; index < this._levels.length; index++) {
|
||||
if (selectedLevelIds.has(this._levels[index].id)) {
|
||||
this._selectedIndices.add(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _clearList(): void {
|
||||
for (const node of this._itemNodes) {
|
||||
if (node && node.isValid) {
|
||||
@@ -429,7 +487,7 @@ export class PageWriteLevels extends BaseView {
|
||||
this._selectedIndices.delete(index);
|
||||
}
|
||||
|
||||
this._playSound(this.itemToggleAudio);
|
||||
AudioManager.instance.playButtonClick();
|
||||
|
||||
console.log('[PageWriteLevels] item切换选中:', index, selected, '当前已选:', this._selectedIndices.size);
|
||||
|
||||
@@ -476,11 +534,11 @@ export class PageWriteLevels extends BaseView {
|
||||
}
|
||||
}
|
||||
|
||||
// 更新 CompleteButton 和 PreviewButton 的可用状态
|
||||
// 预览与分享数量不足时也要允许点击,统一弹出提示弹窗。
|
||||
if (this.completeBtn) {
|
||||
const btn = this.completeBtn.getComponent(Button);
|
||||
if (btn) {
|
||||
btn.interactable = isFull;
|
||||
btn.interactable = true;
|
||||
}
|
||||
}
|
||||
if (this.previewBtn) {
|
||||
@@ -492,37 +550,44 @@ export class PageWriteLevels extends BaseView {
|
||||
}
|
||||
|
||||
private _onBackClick(): void {
|
||||
AudioManager.instance.playButtonClick();
|
||||
console.log('[PageWriteLevels] 返回按钮点击');
|
||||
ViewManager.instance.back();
|
||||
}
|
||||
|
||||
private _onDataClick(): void {
|
||||
AudioManager.instance.playButtonClick();
|
||||
ViewManager.instance.open('PagePKData');
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验是否已选满关卡,未满则 Toast 提示
|
||||
* 校验是否已选满关卡,未满则弹出统一提示弹窗
|
||||
* @returns true 表示校验通过
|
||||
*/
|
||||
private _validateSelection(): boolean {
|
||||
if (this._selectedIndices.size < MAX_SELECTION) {
|
||||
const remaining = MAX_SELECTION - this._selectedIndices.size;
|
||||
ToastManager.instance.show(`还需选择${remaining}个关卡`);
|
||||
this._showSelectionRequiredModal();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private _playSound(clip: AudioClip | null): void {
|
||||
if (!clip) {
|
||||
private _showSelectionRequiredModal(): void {
|
||||
if (!this.commonModalPrefab) {
|
||||
console.warn('[PageWriteLevels] commonModalPrefab 未设置,回退为 Toast 提示');
|
||||
ToastManager.instance.show(`请选择${MAX_SELECTION}个关卡后再预览或分享`);
|
||||
return;
|
||||
}
|
||||
|
||||
const audioSource = this.node.getComponent(AudioSource) ?? this.node.addComponent(AudioSource);
|
||||
audioSource?.playOneShot(clip);
|
||||
CommonModal.show(this.commonModalPrefab, {
|
||||
title: '提示',
|
||||
content: `要选择${MAX_SELECTION}个关卡才能分享和预览`,
|
||||
buttonConfirm: '知道了',
|
||||
});
|
||||
}
|
||||
|
||||
private _onPreviewClick(): void {
|
||||
AudioManager.instance.playButtonClick();
|
||||
if (!this._validateSelection()) return;
|
||||
const shareTitle = this.shareTitleEditBox?.getComponent(EditBox)?.string?.trim() || '';
|
||||
ViewManager.instance.open('PagePreviewLevels', {
|
||||
@@ -534,6 +599,7 @@ export class PageWriteLevels extends BaseView {
|
||||
}
|
||||
|
||||
private async _onCompleteClick(): Promise<void> {
|
||||
AudioManager.instance.playButtonClick();
|
||||
if (!this._validateSelection()) return;
|
||||
|
||||
const shareTitle = this.shareTitleEditBox?.getComponent(EditBox)?.string?.trim() || '';
|
||||
|
||||
@@ -652,7 +652,7 @@
|
||||
"__id__": 86
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 98
|
||||
@@ -1632,7 +1632,7 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 442.03125,
|
||||
"width": 461.40625,
|
||||
"height": 75.6
|
||||
},
|
||||
"_anchorPoint": {
|
||||
@@ -1668,7 +1668,7 @@
|
||||
"b": 0,
|
||||
"a": 255
|
||||
},
|
||||
"_string": "还差3题获得冷场小白2级",
|
||||
"_string": "还差3题,解锁新成就等级",
|
||||
"_horizontalAlign": 1,
|
||||
"_verticalAlign": 1,
|
||||
"_actualFontSize": 40,
|
||||
@@ -4019,6 +4019,9 @@
|
||||
"nextLevelButton": {
|
||||
"__id__": 107
|
||||
},
|
||||
"settingButton": {
|
||||
"__id__": 154
|
||||
},
|
||||
"shareButton": {
|
||||
"__id__": 127
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { _decorator, Node, Label, AudioClip, AudioSource, view, UITransform, Size, ProgressBar, tween, Tween } from 'cc';
|
||||
import { BaseModal } from 'db://assets/scripts/core/BaseModal';
|
||||
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
|
||||
import { AudioManager } from 'db://assets/scripts/utils/AudioManager';
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/**
|
||||
@@ -11,6 +12,8 @@ export interface PassModalCallbacks {
|
||||
onNextLevel?: () => void;
|
||||
/** 点击分享回调 */
|
||||
onShare?: () => void;
|
||||
/** 点击返回主页回调 */
|
||||
onHome?: () => void;
|
||||
}
|
||||
|
||||
export interface PassModalTitleInfo {
|
||||
@@ -45,6 +48,10 @@ export class PassModal extends BaseModal {
|
||||
@property(Node)
|
||||
nextLevelButton: Node | null = null;
|
||||
|
||||
/** 返回主页按钮 */
|
||||
@property(Node)
|
||||
settingButton: Node | null = null;
|
||||
|
||||
/** 分享按钮 */
|
||||
@property(Node)
|
||||
shareButton: Node | null = null;
|
||||
@@ -86,7 +93,7 @@ export class PassModal extends BaseModal {
|
||||
private _titleInfo: PassModalTitleInfo = {
|
||||
titleText: '冷场小白1级',
|
||||
nextTitleProgress: 0,
|
||||
progressText: '还差3题获得冷场小白2级'
|
||||
progressText: '还差3题,解锁新成就等级'
|
||||
};
|
||||
|
||||
/** 动画起点。为 null 表示不做进度动画,直接展示终态 */
|
||||
@@ -98,7 +105,7 @@ export class PassModal extends BaseModal {
|
||||
/** 下一步按钮文案,为 null 时保留 prefab 默认值 */
|
||||
private _nextButtonText: string | null = null;
|
||||
|
||||
/** 进度游标 0% 时的本地 X 坐标,使用 prefab 当前摆放位置作为起点 */
|
||||
/** 进度游标 0% 时的本地 X 坐标,根据 ProgressBar Bar 子节点的左端推导出来 */
|
||||
private _progressAnchorStartX: number | null = null;
|
||||
|
||||
setParams(params: PassModalParams): void {
|
||||
@@ -142,6 +149,7 @@ export class PassModal extends BaseModal {
|
||||
*/
|
||||
onViewLoad(): void {
|
||||
console.log('[PassModal] onViewLoad');
|
||||
this._resolveNodes();
|
||||
this._resolveProgressAnchor();
|
||||
this._cacheProgressAnchorStartX();
|
||||
this._bindButtonEvents();
|
||||
@@ -198,6 +206,9 @@ export class PassModal extends BaseModal {
|
||||
if (this.nextLevelButton) {
|
||||
this.nextLevelButton.on(Node.EventType.TOUCH_END, this._onNextLevelClick, this);
|
||||
}
|
||||
if (this.settingButton) {
|
||||
this.settingButton.on(Node.EventType.TOUCH_END, this._onHomeClick, this);
|
||||
}
|
||||
if (this.shareButton) {
|
||||
this.shareButton.on(Node.EventType.TOUCH_END, this._onShareClick, this);
|
||||
}
|
||||
@@ -211,11 +222,20 @@ export class PassModal extends BaseModal {
|
||||
if (this.nextLevelButton && this.nextLevelButton.isValid) {
|
||||
this.nextLevelButton.off(Node.EventType.TOUCH_END, this._onNextLevelClick, this);
|
||||
}
|
||||
if (this.settingButton && this.settingButton.isValid) {
|
||||
this.settingButton.off(Node.EventType.TOUCH_END, this._onHomeClick, this);
|
||||
}
|
||||
if (this.shareButton && this.shareButton.isValid) {
|
||||
this.shareButton.off(Node.EventType.TOUCH_END, this._onShareClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
private _resolveNodes(): void {
|
||||
this.nextLevelButton = this.nextLevelButton ?? this.node.getChildByName('Button') ?? null;
|
||||
this.settingButton = this.settingButton ?? this.node.getChildByName('SettingButton') ?? null;
|
||||
this.shareButton = this.shareButton ?? this.node.getChildByName('Share') ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放通关音效
|
||||
*/
|
||||
@@ -380,11 +400,24 @@ export class PassModal extends BaseModal {
|
||||
}
|
||||
|
||||
private _cacheProgressAnchorStartX(): void {
|
||||
if (this._progressAnchorStartX !== null || !this.progressAnchor) {
|
||||
if (this._progressAnchorStartX !== null || !this.titleProgressBar) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._progressAnchorStartX = this.progressAnchor.position.x;
|
||||
const barSprite = this.titleProgressBar.barSprite;
|
||||
if (!barSprite) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bar 节点 anchor 为 (0, 0.5),其本地 position.x 即为进度条可视左端。
|
||||
// ProgressBar 与 ProgressAnchor 共享同一父节点(TitleLevel),
|
||||
// 因此把 Bar 的本地 X 按 ProgressBar 自身的位移与缩放映射到父节点空间,
|
||||
// 才是真正的「0% 起点」。直接拿 progressAnchor.position.x 当起点会导致
|
||||
// 气泡始终被 prefab 摆放偏移量带跑(实测偏右 ~24px)。
|
||||
// -40 为视觉微调,与 PageHome 保持一致。
|
||||
const progressBarNode = this.titleProgressBar.node;
|
||||
const barLocalX = barSprite.node.position.x;
|
||||
this._progressAnchorStartX = progressBarNode.position.x + barLocalX * progressBarNode.scale.x - 30;
|
||||
}
|
||||
|
||||
private _resolveProgressAnchor(): void {
|
||||
@@ -481,4 +514,13 @@ export class PassModal extends BaseModal {
|
||||
|
||||
this._callbacks.onShare?.();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回主页按钮点击
|
||||
*/
|
||||
private _onHomeClick(): void {
|
||||
console.log('[PassModal] 点击返回主页');
|
||||
AudioManager.instance.playButtonClick();
|
||||
this._callbacks.onHome?.();
|
||||
}
|
||||
}
|
||||
|
||||
BIN
assets/resources/.DS_Store
vendored
Normal file
BIN
assets/resources/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
assets/resources/audios/good.mp3
Normal file
BIN
assets/resources/audios/good.mp3
Normal file
Binary file not shown.
14
assets/resources/audios/good.mp3.meta
Normal file
14
assets/resources/audios/good.mp3.meta
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"importer": "audio-clip",
|
||||
"imported": true,
|
||||
"uuid": "f1b26185-7493-4c10-b45a-e35ecc86c507",
|
||||
"files": [
|
||||
".json",
|
||||
".mp3"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"downloadMode": 0
|
||||
}
|
||||
}
|
||||
9
assets/resources/spine.meta
Normal file
9
assets/resources/spine.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "56ca3b87-0258-46ac-a7fe-6fa57bd4fdcd",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
BIN
assets/resources/spine/.DS_Store
vendored
Normal file
BIN
assets/resources/spine/.DS_Store
vendored
Normal file
Binary file not shown.
9
assets/resources/spine/passPose.meta
Normal file
9
assets/resources/spine/passPose.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "62bb3395-0a86-43c7-8c4e-30dc272c9383",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
62
assets/resources/spine/passPose/skeleton.atlas
Normal file
62
assets/resources/spine/passPose/skeleton.atlas
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
skeleton.png
|
||||
size: 281,409
|
||||
format: RGBA8888
|
||||
filter: Linear,Linear
|
||||
repeat: none
|
||||
good
|
||||
rotate: false
|
||||
xy: 2, 2
|
||||
size: 260, 93
|
||||
orig: 260, 93
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
亮点1 (1)
|
||||
rotate: false
|
||||
xy: 23, 385
|
||||
size: 23, 22
|
||||
orig: 26, 25
|
||||
offset: 1, 2
|
||||
index: -1
|
||||
亮点1 (2)
|
||||
rotate: false
|
||||
xy: 2, 389
|
||||
size: 19, 18
|
||||
orig: 21, 21
|
||||
offset: 1, 2
|
||||
index: -1
|
||||
亮点1 (3)
|
||||
rotate: false
|
||||
xy: 48, 375
|
||||
size: 32, 32
|
||||
orig: 43, 43
|
||||
offset: 5, 6
|
||||
index: -1
|
||||
亮点大
|
||||
rotate: false
|
||||
xy: 147, 283
|
||||
size: 125, 124
|
||||
orig: 140, 140
|
||||
offset: 7, 8
|
||||
index: -1
|
||||
图层 13 2
|
||||
rotate: false
|
||||
xy: 2, 97
|
||||
size: 277, 92
|
||||
orig: 277, 93
|
||||
offset: 0, 1
|
||||
index: -1
|
||||
星星
|
||||
rotate: true
|
||||
xy: 82, 363
|
||||
size: 44, 63
|
||||
orig: 46, 65
|
||||
offset: 1, 1
|
||||
index: -1
|
||||
组 1 2
|
||||
rotate: false
|
||||
xy: 2, 191
|
||||
size: 267, 90
|
||||
orig: 267, 90
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
12
assets/resources/spine/passPose/skeleton.atlas.meta
Normal file
12
assets/resources/spine/passPose/skeleton.atlas.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"importer": "*",
|
||||
"imported": true,
|
||||
"uuid": "87210cc5-bbb1-4b08-8723-ca58e073aa69",
|
||||
"files": [
|
||||
".atlas",
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
806
assets/resources/spine/passPose/skeleton.json
Normal file
806
assets/resources/spine/passPose/skeleton.json
Normal file
@@ -0,0 +1,806 @@
|
||||
{
|
||||
"skeleton": {
|
||||
"hash": "5g+pbV3em/XRMMTUCFs+FCta7b0=",
|
||||
"spine": "3.8.75",
|
||||
"x": -152.01,
|
||||
"y": -87.03,
|
||||
"width": 308.06,
|
||||
"height": 170.6,
|
||||
"images": "C:/Users/jihuiwang/Downloads/亮点",
|
||||
"audio": ""
|
||||
},
|
||||
"bones": [
|
||||
{ "name": "root" },
|
||||
{ "name": "good", "parent": "root" },
|
||||
{ "name": "亮点1 (1)", "parent": "root", "x": -47.75, "y": 51.34 },
|
||||
{ "name": "亮点1 (2)", "parent": "root", "x": -101.75, "y": 46.85 },
|
||||
{ "name": "亮点1 (3)", "parent": "root", "x": 53.8, "y": 51.61 },
|
||||
{ "name": "亮点大", "parent": "root", "x": 11.71 },
|
||||
{ "name": "星星", "parent": "root", "x": -53.44, "y": -54.53 },
|
||||
{ "name": "星星2", "parent": "root", "x": 46.48, "y": -44.29, "scaleX": 0.7758, "scaleY": 0.7758 },
|
||||
{ "name": "星星3", "parent": "root", "x": 81.98, "y": -69.17, "scaleX": 0.3525, "scaleY": 0.3525 },
|
||||
{ "name": "星星4", "parent": "root", "x": -137.62, "y": 12.08, "scaleX": 0.6258, "scaleY": 0.6258 },
|
||||
{ "name": "星星5", "parent": "root", "x": 141.64, "y": -19.76, "scaleX": 0.5363, "scaleY": 0.5363 },
|
||||
{ "name": "亮点1 (2)2", "parent": "root", "x": 94.96, "y": 42.33 },
|
||||
{ "name": "亮点1 (3)2", "parent": "root", "x": 134.55, "y": 10.91 },
|
||||
{ "name": "bone2", "parent": "root" },
|
||||
{ "name": "bone3", "parent": "root" }
|
||||
],
|
||||
"slots": [
|
||||
{ "name": "good", "bone": "good", "attachment": "good" },
|
||||
{ "name": "亮点1 (1)", "bone": "亮点1 (1)", "attachment": "亮点1 (1)", "blend": "screen" },
|
||||
{ "name": "亮点1 (2)", "bone": "亮点1 (2)", "attachment": "亮点1 (2)", "blend": "screen" },
|
||||
{ "name": "亮点1 (2)2", "bone": "亮点1 (2)2", "attachment": "亮点1 (2)", "blend": "screen" },
|
||||
{ "name": "亮点1 (3)", "bone": "亮点1 (3)", "attachment": "亮点1 (3)", "blend": "screen" },
|
||||
{ "name": "亮点1 (3)2", "bone": "亮点1 (3)2", "attachment": "亮点1 (3)", "blend": "screen" },
|
||||
{ "name": "亮点大", "bone": "亮点大", "attachment": "亮点大", "blend": "additive" },
|
||||
{ "name": "星星", "bone": "星星", "attachment": "星星", "blend": "screen" },
|
||||
{ "name": "星星5", "bone": "星星5", "attachment": "星星", "blend": "screen" },
|
||||
{ "name": "星星4", "bone": "星星4", "color": "ffffffc9", "attachment": "星星", "blend": "screen" },
|
||||
{ "name": "星星3", "bone": "星星3", "attachment": "星星", "blend": "screen" },
|
||||
{ "name": "星星2", "bone": "星星2", "color": "ffffffb2", "attachment": "星星", "blend": "screen" },
|
||||
{ "name": "图层 13 2", "bone": "bone3", "attachment": "图层 13 2" },
|
||||
{ "name": "组 1 2", "bone": "bone2", "attachment": "组 1 2" }
|
||||
],
|
||||
"skins": [
|
||||
{
|
||||
"name": "default",
|
||||
"attachments": {
|
||||
"亮点1 (2)": {
|
||||
"亮点1 (2)": { "width": 21, "height": 21 }
|
||||
},
|
||||
"亮点1 (2)2": {
|
||||
"亮点1 (2)": { "width": 21, "height": 21 }
|
||||
},
|
||||
"亮点1 (3)2": {
|
||||
"亮点1 (3)": { "width": 43, "height": 43 }
|
||||
},
|
||||
"图层 13 2": {
|
||||
"图层 13 2": { "width": 277, "height": 93 }
|
||||
},
|
||||
"星星2": {
|
||||
"星星": { "width": 46, "height": 65 }
|
||||
},
|
||||
"星星3": {
|
||||
"星星": { "width": 46, "height": 65 }
|
||||
},
|
||||
"星星4": {
|
||||
"星星": { "width": 46, "height": 65 }
|
||||
},
|
||||
"星星5": {
|
||||
"星星": { "width": 46, "height": 65 }
|
||||
},
|
||||
"星星": {
|
||||
"星星": { "width": 46, "height": 65 }
|
||||
},
|
||||
"亮点1 (3)": {
|
||||
"亮点1 (3)": { "width": 43, "height": 43 }
|
||||
},
|
||||
"亮点1 (1)": {
|
||||
"亮点1 (1)": { "width": 26, "height": 25 }
|
||||
},
|
||||
"组 1 2": {
|
||||
"组 1 2": { "width": 267, "height": 90 }
|
||||
},
|
||||
"亮点大": {
|
||||
"亮点大": { "scaleX": 1.1937, "scaleY": 1.1937, "width": 140, "height": 140 }
|
||||
},
|
||||
"good": {
|
||||
"good": { "width": 260, "height": 93 }
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"animations": {
|
||||
"1": {
|
||||
"slots": {
|
||||
"亮点1 (3)2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"图层 13 2": {
|
||||
"attachment": [
|
||||
{ "name": null }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1667, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"good": {
|
||||
"color": [
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8667, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星3": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffffb2", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"组 1 2": {
|
||||
"attachment": [
|
||||
{ "name": null }
|
||||
]
|
||||
},
|
||||
"星星5": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (1)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1667, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": "stepped" },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点大": {
|
||||
"color": [
|
||||
{ "time": 0.1667, "color": "ffffffff", "curve": 0.442, "c2": 0.42, "c3": 0.819, "c4": 0.82 },
|
||||
{ "time": 0.3333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (3)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星4": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1333, "color": "ffffffc9", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffffc9", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5667, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6667, "color": "ffffff00" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"bones": {
|
||||
"亮点1 (1)": {
|
||||
"translate": [
|
||||
{ "time": 0.3, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 110.68 }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)": {
|
||||
"translate": [
|
||||
{ "time": 0.1667, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 89.43 }
|
||||
]
|
||||
},
|
||||
"亮点1 (3)": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "x": 2.2, "y": 49.11 }
|
||||
]
|
||||
},
|
||||
"亮点大": {
|
||||
"translate": [
|
||||
{ "time": 0.5, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 87.86 }
|
||||
],
|
||||
"scale": [
|
||||
{ "x": 0.5, "y": 0.5 },
|
||||
{ "time": 0.3333 },
|
||||
{ "time": 0.3667, "x": 0.01, "y": 0.01 }
|
||||
]
|
||||
},
|
||||
"星星": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "y": 15.39 }
|
||||
],
|
||||
"scale": [
|
||||
{ "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "x": 0.8, "y": 0.8 }
|
||||
]
|
||||
},
|
||||
"星星2": {
|
||||
"translate": [
|
||||
{ "time": 0.1, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "y": 13.19 }
|
||||
]
|
||||
},
|
||||
"星星3": {
|
||||
"translate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "y": 35.88 }
|
||||
]
|
||||
},
|
||||
"星星4": {
|
||||
"translate": [
|
||||
{ "time": 0.2333, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 43.25 }
|
||||
]
|
||||
},
|
||||
"星星5": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 19.06 }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)2": {
|
||||
"translate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 57.91 }
|
||||
]
|
||||
},
|
||||
"good": {
|
||||
"rotate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "angle": -18.23, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "angle": 12.17, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "angle": -14.28, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "angle": 11.65, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "angle": -6.34, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6 }
|
||||
],
|
||||
"translate": [
|
||||
{ "time": 0.5, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8667, "y": 87.86 }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"slots": {
|
||||
"亮点1 (3)2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"图层 13 2": {
|
||||
"color": [
|
||||
{ "time": 0.5, "color": "ffffffff" },
|
||||
{ "time": 0.8667, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"good": {
|
||||
"color": [
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8667, "color": "ffffff00" }
|
||||
],
|
||||
"attachment": [
|
||||
{ "name": null }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1667, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星3": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffffb2", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"组 1 2": {
|
||||
"attachment": [
|
||||
{ "name": null }
|
||||
]
|
||||
},
|
||||
"星星5": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (1)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1667, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": "stepped" },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点大": {
|
||||
"color": [
|
||||
{ "time": 0.1667, "color": "ffffffff", "curve": 0.442, "c2": 0.42, "c3": 0.819, "c4": 0.82 },
|
||||
{ "time": 0.3333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (3)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星4": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1333, "color": "ffffffc9", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffffc9", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5667, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6667, "color": "ffffff00" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"bones": {
|
||||
"亮点大": {
|
||||
"rotate": [
|
||||
{ "angle": -0.41 }
|
||||
],
|
||||
"translate": [
|
||||
{ "time": 0.5, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 87.86 }
|
||||
],
|
||||
"scale": [
|
||||
{ "x": 0.5, "y": 0.5 },
|
||||
{ "time": 0.3333 },
|
||||
{ "time": 0.3667, "x": 0.01, "y": 0.01 }
|
||||
]
|
||||
},
|
||||
"bone3": {
|
||||
"rotate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "angle": -18.23, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "angle": 12.17, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "angle": -14.28, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "angle": 11.65, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "angle": -6.34, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6 }
|
||||
],
|
||||
"translate": [
|
||||
{ "time": 0.5, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8667, "y": 87.86 }
|
||||
]
|
||||
},
|
||||
"good": {
|
||||
"rotate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "angle": -18.23, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "angle": 12.17, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "angle": -14.28, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "angle": 11.65, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "angle": -6.34, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6 }
|
||||
],
|
||||
"translate": [
|
||||
{ "time": 0.5, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8667, "y": 87.86 }
|
||||
]
|
||||
},
|
||||
"星星3": {
|
||||
"translate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "y": 35.88 }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)2": {
|
||||
"translate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 57.91 }
|
||||
]
|
||||
},
|
||||
"星星": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "y": 15.39 }
|
||||
],
|
||||
"scale": [
|
||||
{ "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "x": 0.8, "y": 0.8 }
|
||||
]
|
||||
},
|
||||
"亮点1 (3)": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "x": 2.2, "y": 49.11 }
|
||||
]
|
||||
},
|
||||
"星星2": {
|
||||
"translate": [
|
||||
{ "time": 0.1, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "y": 13.19 }
|
||||
]
|
||||
},
|
||||
"亮点1 (1)": {
|
||||
"translate": [
|
||||
{ "time": 0.3, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 110.68 }
|
||||
]
|
||||
},
|
||||
"星星4": {
|
||||
"translate": [
|
||||
{ "time": 0.2333, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 43.25 }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)": {
|
||||
"translate": [
|
||||
{ "time": 0.1667, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 89.43 }
|
||||
]
|
||||
},
|
||||
"星星5": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 19.06 }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"3": {
|
||||
"slots": {
|
||||
"亮点1 (3)2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"图层 13 2": {
|
||||
"attachment": [
|
||||
{ "name": null }
|
||||
]
|
||||
},
|
||||
"good": {
|
||||
"color": [
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8667, "color": "ffffff00" }
|
||||
],
|
||||
"attachment": [
|
||||
{ "name": null }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1667, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星3": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffffb2", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"组 1 2": {
|
||||
"color": [
|
||||
{ "time": 0.5, "color": "ffffffff" },
|
||||
{ "time": 0.8667, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星5": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (1)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1667, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": "stepped" },
|
||||
{ "time": 0.5, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)2": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点大": {
|
||||
"color": [
|
||||
{ "time": 0.1667, "color": "ffffffff", "curve": 0.442, "c2": 0.42, "c3": 0.819, "c4": 0.82 },
|
||||
{ "time": 0.3333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"亮点1 (3)": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": "stepped" },
|
||||
{ "time": 0.1, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "color": "ffffff00" }
|
||||
]
|
||||
},
|
||||
"星星4": {
|
||||
"color": [
|
||||
{ "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1333, "color": "ffffffc9", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3333, "color": "ffffffc9", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "color": "ffffff00", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5667, "color": "ffffffff", "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6667, "color": "ffffff00" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"bones": {
|
||||
"good": {
|
||||
"rotate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "angle": -18.23, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "angle": 12.17, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "angle": -14.28, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "angle": 11.65, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "angle": -6.34, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6 }
|
||||
],
|
||||
"translate": [
|
||||
{ "time": 0.5, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8667, "y": 87.86 }
|
||||
]
|
||||
},
|
||||
"星星3": {
|
||||
"translate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.7333, "y": 35.88 }
|
||||
]
|
||||
},
|
||||
"星星": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "y": 15.39 }
|
||||
],
|
||||
"scale": [
|
||||
{ "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4333, "x": 0.8, "y": 0.8, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "x": 1.313, "y": 1.313, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "x": 0.8, "y": 0.8 }
|
||||
]
|
||||
},
|
||||
"星星5": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 19.06 }
|
||||
]
|
||||
},
|
||||
"亮点大": {
|
||||
"translate": [
|
||||
{ "time": 0.5, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 87.86 }
|
||||
],
|
||||
"scale": [
|
||||
{ "x": 0.5, "y": 0.5 },
|
||||
{ "time": 0.3333 },
|
||||
{ "time": 0.3667, "x": 0.01, "y": 0.01 }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)": {
|
||||
"translate": [
|
||||
{ "time": 0.1667, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 89.43 }
|
||||
]
|
||||
},
|
||||
"星星2": {
|
||||
"translate": [
|
||||
{ "time": 0.1, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5333, "y": 13.19 }
|
||||
]
|
||||
},
|
||||
"亮点1 (1)": {
|
||||
"translate": [
|
||||
{ "time": 0.3, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "y": 110.68 }
|
||||
]
|
||||
},
|
||||
"亮点1 (3)": {
|
||||
"translate": [
|
||||
{ "time": 0.2, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8333, "x": 2.2, "y": 49.11 }
|
||||
]
|
||||
},
|
||||
"星星4": {
|
||||
"translate": [
|
||||
{ "time": 0.2333, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 43.25 }
|
||||
]
|
||||
},
|
||||
"亮点1 (2)2": {
|
||||
"translate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6333, "y": 57.91 }
|
||||
]
|
||||
},
|
||||
"bone2": {
|
||||
"rotate": [
|
||||
{ "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.1, "angle": -18.23, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.2, "angle": 12.17, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.3, "angle": -14.28, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.4, "angle": 11.65, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.5, "angle": -6.34, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.6 }
|
||||
],
|
||||
"translate": [
|
||||
{ "time": 0.5, "curve": 0.25, "c3": 0.846, "c4": 0.81 },
|
||||
{ "time": 0.8667, "y": 87.86 }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
assets/resources/spine/passPose/skeleton.json.meta
Normal file
13
assets/resources/spine/passPose/skeleton.json.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.2.7",
|
||||
"importer": "spine-data",
|
||||
"imported": true,
|
||||
"uuid": "443e4aca-50d0-4d49-9c21-c1daeb44116d",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"atlasUuid": "87210cc5-bbb1-4b08-8723-ca58e073aa69"
|
||||
}
|
||||
}
|
||||
BIN
assets/resources/spine/passPose/skeleton.png
Normal file
BIN
assets/resources/spine/passPose/skeleton.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
134
assets/resources/spine/passPose/skeleton.png.meta
Normal file
134
assets/resources/spine/passPose/skeleton.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "051410b7-cb90-4a14-98be-109bd75eabcd",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "051410b7-cb90-4a14-98be-109bd75eabcd@6c48a",
|
||||
"displayName": "skeleton",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "051410b7-cb90-4a14-98be-109bd75eabcd",
|
||||
"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": "051410b7-cb90-4a14-98be-109bd75eabcd@f9941",
|
||||
"displayName": "skeleton",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 2,
|
||||
"trimY": 2,
|
||||
"width": 277,
|
||||
"height": 405,
|
||||
"rawWidth": 281,
|
||||
"rawHeight": 409,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-138.5,
|
||||
-202.5,
|
||||
0,
|
||||
138.5,
|
||||
-202.5,
|
||||
0,
|
||||
-138.5,
|
||||
202.5,
|
||||
0,
|
||||
138.5,
|
||||
202.5,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
2,
|
||||
407,
|
||||
279,
|
||||
407,
|
||||
2,
|
||||
2,
|
||||
279,
|
||||
2
|
||||
],
|
||||
"nuv": [
|
||||
0.0071174377224199285,
|
||||
0.004889975550122249,
|
||||
0.9928825622775801,
|
||||
0.004889975550122249,
|
||||
0.0071174377224199285,
|
||||
0.9951100244498777,
|
||||
0.9928825622775801,
|
||||
0.9951100244498777
|
||||
],
|
||||
"minPos": [
|
||||
-138.5,
|
||||
-202.5,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
138.5,
|
||||
202.5,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "051410b7-cb90-4a14-98be-109bd75eabcd@6c48a",
|
||||
"atlasUuid": "",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"fixAlphaTransparencyArtifacts": false,
|
||||
"hasAlpha": true,
|
||||
"redirect": "051410b7-cb90-4a14-98be-109bd75eabcd@6c48a"
|
||||
}
|
||||
}
|
||||
125
assets/resources/spine/prize_fx.atlas
Normal file
125
assets/resources/spine/prize_fx.atlas
Normal file
@@ -0,0 +1,125 @@
|
||||
|
||||
prize_fx.png
|
||||
size: 668,525
|
||||
format: RGBA8888
|
||||
filter: Linear,Linear
|
||||
repeat: none
|
||||
caidai01
|
||||
rotate: true
|
||||
xy: 313, 234
|
||||
size: 42, 33
|
||||
orig: 42, 33
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
caidai02
|
||||
rotate: true
|
||||
xy: 638, 265
|
||||
size: 25, 28
|
||||
orig: 25, 28
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
cd1
|
||||
rotate: true
|
||||
xy: 238, 2
|
||||
size: 26, 150
|
||||
orig: 37, 160
|
||||
offset: 6, 0
|
||||
index: -1
|
||||
cd2
|
||||
rotate: false
|
||||
xy: 289, 235
|
||||
size: 22, 145
|
||||
orig: 37, 160
|
||||
offset: 12, 4
|
||||
index: -1
|
||||
cd3
|
||||
rotate: true
|
||||
xy: 390, 2
|
||||
size: 26, 150
|
||||
orig: 37, 160
|
||||
offset: 6, 0
|
||||
index: -1
|
||||
cd4
|
||||
rotate: true
|
||||
xy: 391, 247
|
||||
size: 29, 66
|
||||
orig: 46, 80
|
||||
offset: 10, 7
|
||||
index: -1
|
||||
gh_0
|
||||
rotate: false
|
||||
xy: 238, 30
|
||||
size: 193, 195
|
||||
orig: 200, 200
|
||||
offset: 3, 2
|
||||
index: -1
|
||||
guang
|
||||
rotate: false
|
||||
xy: 348, 235
|
||||
size: 41, 41
|
||||
orig: 66, 69
|
||||
offset: 17, 16
|
||||
index: -1
|
||||
guang1
|
||||
rotate: false
|
||||
xy: 433, 50
|
||||
size: 65, 66
|
||||
orig: 66, 69
|
||||
offset: 0, 1
|
||||
index: -1
|
||||
ks
|
||||
rotate: false
|
||||
xy: 289, 382
|
||||
size: 141, 141
|
||||
orig: 155, 155
|
||||
offset: 7, 7
|
||||
index: -1
|
||||
light_glow
|
||||
rotate: false
|
||||
xy: 433, 292
|
||||
size: 233, 231
|
||||
orig: 279, 278
|
||||
offset: 23, 24
|
||||
index: -1
|
||||
light_line1
|
||||
rotate: true
|
||||
xy: 2, 5
|
||||
size: 220, 234
|
||||
orig: 285, 263
|
||||
offset: 43, 23
|
||||
index: -1
|
||||
light_line2
|
||||
rotate: true
|
||||
xy: 2, 227
|
||||
size: 296, 285
|
||||
orig: 309, 298
|
||||
offset: 9, 12
|
||||
index: -1
|
||||
star1
|
||||
rotate: false
|
||||
xy: 433, 200
|
||||
size: 20, 19
|
||||
orig: 26, 26
|
||||
offset: 3, 3
|
||||
index: -1
|
||||
xx02
|
||||
rotate: false
|
||||
xy: 433, 221
|
||||
size: 24, 24
|
||||
orig: 32, 32
|
||||
offset: 4, 4
|
||||
index: -1
|
||||
yd_c1_light
|
||||
rotate: true
|
||||
xy: 459, 118
|
||||
size: 172, 177
|
||||
orig: 200, 200
|
||||
offset: 17, 12
|
||||
index: -1
|
||||
yd_light
|
||||
rotate: false
|
||||
xy: 313, 278
|
||||
size: 102, 102
|
||||
orig: 112, 112
|
||||
offset: 5, 5
|
||||
index: -1
|
||||
12
assets/resources/spine/prize_fx.atlas.meta
Normal file
12
assets/resources/spine/prize_fx.atlas.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ver": "1.0.0",
|
||||
"importer": "*",
|
||||
"imported": true,
|
||||
"uuid": "4b5c9209-f28d-4e6a-9eae-905c0e9dbbb7",
|
||||
"files": [
|
||||
".atlas",
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
3408
assets/resources/spine/prize_fx.json
Normal file
3408
assets/resources/spine/prize_fx.json
Normal file
File diff suppressed because it is too large
Load Diff
13
assets/resources/spine/prize_fx.json.meta
Normal file
13
assets/resources/spine/prize_fx.json.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.2.7",
|
||||
"importer": "spine-data",
|
||||
"imported": true,
|
||||
"uuid": "fff92c24-e843-4fca-b0aa-6e4e4f2caef5",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"atlasUuid": "4b5c9209-f28d-4e6a-9eae-905c0e9dbbb7"
|
||||
}
|
||||
}
|
||||
BIN
assets/resources/spine/prize_fx.png
Normal file
BIN
assets/resources/spine/prize_fx.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 290 KiB |
134
assets/resources/spine/prize_fx.png.meta
Normal file
134
assets/resources/spine/prize_fx.png.meta
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"ver": "1.0.27",
|
||||
"importer": "image",
|
||||
"imported": true,
|
||||
"uuid": "4d9aae14-3f9b-44b6-96a9-3535d097fed4",
|
||||
"files": [
|
||||
".json",
|
||||
".png"
|
||||
],
|
||||
"subMetas": {
|
||||
"6c48a": {
|
||||
"importer": "texture",
|
||||
"uuid": "4d9aae14-3f9b-44b6-96a9-3535d097fed4@6c48a",
|
||||
"displayName": "prize_fx",
|
||||
"id": "6c48a",
|
||||
"name": "texture",
|
||||
"userData": {
|
||||
"wrapModeS": "clamp-to-edge",
|
||||
"wrapModeT": "clamp-to-edge",
|
||||
"imageUuidOrDatabaseUri": "4d9aae14-3f9b-44b6-96a9-3535d097fed4",
|
||||
"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": "4d9aae14-3f9b-44b6-96a9-3535d097fed4@f9941",
|
||||
"displayName": "prize_fx",
|
||||
"id": "f9941",
|
||||
"name": "spriteFrame",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 2,
|
||||
"trimY": 2,
|
||||
"width": 664,
|
||||
"height": 521,
|
||||
"rawWidth": 668,
|
||||
"rawHeight": 525,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [
|
||||
-332,
|
||||
-260.5,
|
||||
0,
|
||||
332,
|
||||
-260.5,
|
||||
0,
|
||||
-332,
|
||||
260.5,
|
||||
0,
|
||||
332,
|
||||
260.5,
|
||||
0
|
||||
],
|
||||
"indexes": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
3
|
||||
],
|
||||
"uv": [
|
||||
2,
|
||||
523,
|
||||
666,
|
||||
523,
|
||||
2,
|
||||
2,
|
||||
666,
|
||||
2
|
||||
],
|
||||
"nuv": [
|
||||
0.0029940119760479044,
|
||||
0.0038095238095238095,
|
||||
0.9970059880239521,
|
||||
0.0038095238095238095,
|
||||
0.0029940119760479044,
|
||||
0.9961904761904762,
|
||||
0.9970059880239521,
|
||||
0.9961904761904762
|
||||
],
|
||||
"minPos": [
|
||||
-332,
|
||||
-260.5,
|
||||
0
|
||||
],
|
||||
"maxPos": [
|
||||
332,
|
||||
260.5,
|
||||
0
|
||||
]
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "4d9aae14-3f9b-44b6-96a9-3535d097fed4@6c48a",
|
||||
"atlasUuid": "",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
"type": "sprite-frame",
|
||||
"fixAlphaTransparencyArtifacts": false,
|
||||
"hasAlpha": true,
|
||||
"redirect": "4d9aae14-3f9b-44b6-96a9-3535d097fed4@6c48a"
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ export const API_ENDPOINTS = {
|
||||
/** 分享相关 */
|
||||
SHARE_CREATE: `${API_BASE}/share`,
|
||||
SHARE_CREATED: `${API_BASE}/share/created`,
|
||||
SHARE_PARTICIPATED: `${API_BASE}/share/participated`,
|
||||
/** 用户信息 */
|
||||
USER_INFO: `${API_BASE}/user/info`,
|
||||
/** 用户所有已通关的关卡(成就墙 / 关卡回看) */
|
||||
@@ -37,6 +38,10 @@ export function getShareJoinUrl(code: string): string {
|
||||
return `${API_BASE}/share/${code}/join`;
|
||||
}
|
||||
|
||||
export function getShareDetailUrl(code: string): string {
|
||||
return `${API_BASE}/share/${code}`;
|
||||
}
|
||||
|
||||
export function getShareSubmitUrl(code: string): string {
|
||||
return `${API_BASE}/share/${code}/submit`;
|
||||
}
|
||||
|
||||
@@ -165,6 +165,7 @@ export interface SubmitShareData {
|
||||
/** 分享挑战参与者排行摘要 */
|
||||
export interface ShareParticipantRankSummary {
|
||||
userId?: string | null;
|
||||
participantId?: string | null;
|
||||
nickname?: string | null;
|
||||
nickName?: string | null;
|
||||
avatarUrl?: string | null;
|
||||
@@ -193,6 +194,30 @@ export interface CreatedShareListData {
|
||||
items: CreatedShareItem[];
|
||||
}
|
||||
|
||||
/** 我参与的分享挑战条目 */
|
||||
export interface ParticipatedShareItem {
|
||||
title: string;
|
||||
participantCount: number;
|
||||
userRank: number | null;
|
||||
}
|
||||
|
||||
/** 我参与的分享挑战列表响应 */
|
||||
export interface ParticipatedShareListData {
|
||||
items: ParticipatedShareItem[];
|
||||
}
|
||||
|
||||
/** 分享挑战详情响应 */
|
||||
export interface ShareDetailData {
|
||||
id: string;
|
||||
shareCode: string;
|
||||
title: string;
|
||||
levelCount: number;
|
||||
participantCount: number;
|
||||
userRank: number | null;
|
||||
createdAt: string;
|
||||
rankings: ShareParticipantRankSummary[];
|
||||
}
|
||||
|
||||
/** 已通关关卡数据(成就墙 / 关卡回看场景) */
|
||||
export interface CompletedLevel {
|
||||
/** 关卡 ID */
|
||||
|
||||
252
assets/scripts/utils/AchievementTitleAnimator.ts
Normal file
252
assets/scripts/utils/AchievementTitleAnimator.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
import { Label, Node, ProgressBar, tween, Tween } from 'cc';
|
||||
|
||||
/**
|
||||
* 称号进度展示数据
|
||||
* 字段对应 AchievementTitleManager.getTitleInfo 的产物,但所有字段都是可选的,
|
||||
* 调用方可以只更新需要的部分(例如分享模式只想清空文字)。
|
||||
*/
|
||||
export interface TitleProgressData {
|
||||
/** 当前称号文案(如「冷场小白1级」) */
|
||||
titleText?: string;
|
||||
/** 进度提示文案(如「还差3题,解锁新成就等级」) */
|
||||
progressText?: string;
|
||||
/** 当前称号到下一称号的进度,0-1 */
|
||||
nextTitleProgress?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 进度条 / 称号视图所需的节点引用集合
|
||||
*/
|
||||
export interface TitleAnimatorBindings {
|
||||
/** 称号文案 Label(如「冷场小白1级」),可空 */
|
||||
titleLabel?: Label | null;
|
||||
/** 进度提示 Label(如「还差3题,解锁新成就等级」),可空 */
|
||||
progressLabel?: Label | null;
|
||||
/** 进度条组件 */
|
||||
progressBar?: ProgressBar | null;
|
||||
/** 进度条上跟随移动的 anchor 节点(若其下有 Label 子节点会自动写百分比) */
|
||||
progressAnchor?: Node | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 进度条动画起始前的等待时长(秒)。让弹窗 / 弹起动画稳定后再开播
|
||||
*/
|
||||
const PROGRESS_ANIM_START_DELAY = 0.4;
|
||||
/** 单段进度条填充动画时长(秒) */
|
||||
const PROGRESS_ANIM_SEGMENT_DURATION = 0.6;
|
||||
/** 跨称号切换时的等级信息刷新停顿(秒),让玩家看清称号变更 */
|
||||
const PROGRESS_ANIM_LEVELUP_PAUSE = 0.12;
|
||||
|
||||
/**
|
||||
* 九宫格 Bar Left+Right border = 240px、totalLength = 925px。
|
||||
* width < 240px 时圆角会畸变,因此 progress > 0 时强制最小值。
|
||||
*/
|
||||
const MIN_PROGRESS_RATIO = 240 / 925;
|
||||
|
||||
/** anchor 起点的视觉微调(与 PageHome 等其他页面保持一致) */
|
||||
const PROGRESS_ANCHOR_VISUAL_OFFSET = -30;
|
||||
|
||||
/**
|
||||
* 把称号文字、进度条、跟随气泡这三件事打包成一个可复用的动画/展示工具。
|
||||
* 没有引擎组件依赖(不是 cc.Component),可以被任何持有节点引用的对象 new 一个出来用。
|
||||
*
|
||||
* 起源:原本只在 PassModal 内部实现。PassNode 替换 PassModal 后,
|
||||
* PageLevel 也需要同一套行为,所以抽出来共用。
|
||||
*/
|
||||
export class AchievementTitleAnimator {
|
||||
private _bindings: TitleAnimatorBindings = {};
|
||||
/** anchor 起点 X(在 progressBar 父节点空间下),首次解析后缓存 */
|
||||
private _progressAnchorStartX: number | null = null;
|
||||
/** Tween 共享的目标对象,方便 stopAllByTarget */
|
||||
private readonly _tweenTarget: { progress: number } = { progress: 0 };
|
||||
|
||||
/** 绑定 / 重新绑定节点引用。任何重新绑定都会清掉缓存的 anchor 起点 */
|
||||
bind(bindings: TitleAnimatorBindings): void {
|
||||
this._bindings = bindings;
|
||||
this._progressAnchorStartX = null;
|
||||
}
|
||||
|
||||
/** 直接展示终态,无动画 */
|
||||
setTarget(data: TitleProgressData): void {
|
||||
this.stop();
|
||||
this._applyTitleText(data.titleText);
|
||||
this._applyProgressText(data.progressText);
|
||||
this._applyProgressValue(data.nextTitleProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 prev → current 播过渡动画
|
||||
* - prev 为空:直接展示 current 终态
|
||||
* - 同称号:单段 tween
|
||||
* - 跨称号:先填满旧称号,再切到新称号 + 进度从 0 涨到 current
|
||||
*/
|
||||
playTransition(prev: TitleProgressData | null | undefined, current: TitleProgressData): void {
|
||||
if (!prev) {
|
||||
this.setTarget(current);
|
||||
return;
|
||||
}
|
||||
|
||||
const startProgress = prev.nextTitleProgress;
|
||||
const endProgress = current.nextTitleProgress;
|
||||
if (startProgress === undefined || endProgress === undefined) {
|
||||
this.setTarget(current);
|
||||
return;
|
||||
}
|
||||
|
||||
const isSameTitle = prev.titleText === undefined
|
||||
|| current.titleText === undefined
|
||||
|| prev.titleText === current.titleText;
|
||||
|
||||
// 同称号且起止相同,没必要播动画
|
||||
if (isSameTitle && Math.abs(startProgress - endProgress) < 1e-4) {
|
||||
this.setTarget(current);
|
||||
return;
|
||||
}
|
||||
|
||||
this.stop();
|
||||
|
||||
if (isSameTitle) {
|
||||
// 先展示文字 + 起点进度,再 tween 到终点
|
||||
this._applyTitleText(current.titleText);
|
||||
this._applyProgressText(current.progressText);
|
||||
this._applyProgressValue(startProgress);
|
||||
this._runSegmentTween(startProgress, endProgress, PROGRESS_ANIM_START_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
// 跨称号:先展示旧称号 + 起点进度
|
||||
this._applyTitleText(prev.titleText);
|
||||
this._applyProgressText(prev.progressText);
|
||||
this._applyProgressValue(startProgress);
|
||||
|
||||
const target = this._tweenTarget;
|
||||
target.progress = this._clamp(startProgress);
|
||||
const onUpdate = () => this._applyAnimatedProgress(target.progress);
|
||||
|
||||
tween(target)
|
||||
.delay(PROGRESS_ANIM_START_DELAY)
|
||||
.to(PROGRESS_ANIM_SEGMENT_DURATION, { progress: 1 }, { easing: 'sineOut', onUpdate })
|
||||
.call(() => {
|
||||
this._applyTitleText(current.titleText);
|
||||
this._applyProgressText(current.progressText);
|
||||
target.progress = 0;
|
||||
this._applyAnimatedProgress(0);
|
||||
})
|
||||
.delay(PROGRESS_ANIM_LEVELUP_PAUSE)
|
||||
.to(
|
||||
PROGRESS_ANIM_SEGMENT_DURATION,
|
||||
{ progress: this._clamp(endProgress) },
|
||||
{ easing: 'sineOut', onUpdate },
|
||||
)
|
||||
.start();
|
||||
}
|
||||
|
||||
/** 停止当前动画(不影响已展示的进度值) */
|
||||
stop(): void {
|
||||
Tween.stopAllByTarget(this._tweenTarget);
|
||||
}
|
||||
|
||||
private _runSegmentTween(from: number, to: number, delay: number): void {
|
||||
const target = this._tweenTarget;
|
||||
target.progress = this._clamp(from);
|
||||
this._applyAnimatedProgress(from);
|
||||
|
||||
const chain = tween(target);
|
||||
if (delay > 0) {
|
||||
chain.delay(delay);
|
||||
}
|
||||
|
||||
chain.to(
|
||||
PROGRESS_ANIM_SEGMENT_DURATION,
|
||||
{ progress: this._clamp(to) },
|
||||
{
|
||||
easing: 'sineOut',
|
||||
onUpdate: () => this._applyAnimatedProgress(target.progress),
|
||||
},
|
||||
).start();
|
||||
}
|
||||
|
||||
private _applyTitleText(text: string | undefined): void {
|
||||
if (text === undefined) return;
|
||||
const label = this._bindings.titleLabel;
|
||||
if (label?.isValid) {
|
||||
label.string = text;
|
||||
}
|
||||
}
|
||||
|
||||
private _applyProgressText(text: string | undefined): void {
|
||||
if (text === undefined) return;
|
||||
const label = this._bindings.progressLabel;
|
||||
if (label?.isValid) {
|
||||
label.string = text;
|
||||
}
|
||||
}
|
||||
|
||||
private _applyProgressValue(progress: number | undefined): void {
|
||||
if (progress === undefined) return;
|
||||
this._applyAnimatedProgress(progress);
|
||||
}
|
||||
|
||||
private _applyAnimatedProgress(progress: number): void {
|
||||
const clamped = this._clamp(progress);
|
||||
const bar = this._bindings.progressBar;
|
||||
if (bar?.isValid) {
|
||||
bar.progress = this._normalize(clamped);
|
||||
}
|
||||
this._updateProgressAnchor(clamped);
|
||||
}
|
||||
|
||||
private _updateProgressAnchor(progress: number): void {
|
||||
const anchor = this._bindings.progressAnchor;
|
||||
if (!anchor?.isValid) return;
|
||||
|
||||
this._cacheProgressAnchorStartX();
|
||||
|
||||
const startX = this._progressAnchorStartX ?? anchor.position.x;
|
||||
const travelWidth = this._getProgressAnchorTravelWidth();
|
||||
anchor.setPosition(
|
||||
startX + travelWidth * progress,
|
||||
anchor.position.y,
|
||||
anchor.position.z,
|
||||
);
|
||||
|
||||
const percentLabel = anchor.getChildByName('Label')?.getComponent(Label);
|
||||
if (percentLabel) {
|
||||
percentLabel.string = `${Math.round(progress * 100)}%`;
|
||||
}
|
||||
}
|
||||
|
||||
private _getProgressAnchorTravelWidth(): number {
|
||||
const bar = this._bindings.progressBar;
|
||||
if (!bar) return 0;
|
||||
return Math.abs(bar.totalLength * bar.node.scale.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bar 节点 anchor 为 (0, 0.5),其本地 position.x 即进度条可视左端。
|
||||
* ProgressBar 与 ProgressAnchor 共享同一父节点,因此把 Bar 的本地 X
|
||||
* 按 ProgressBar 自身的位移与缩放映射到父节点空间,才是真正的「0% 起点」。
|
||||
* 直接拿 anchor.position.x 当起点会被 prefab 摆放偏移量带跑。
|
||||
*/
|
||||
private _cacheProgressAnchorStartX(): void {
|
||||
if (this._progressAnchorStartX !== null) return;
|
||||
const bar = this._bindings.progressBar;
|
||||
const barSprite = bar?.barSprite;
|
||||
if (!bar || !barSprite) return;
|
||||
|
||||
const barLocalX = barSprite.node.position.x;
|
||||
this._progressAnchorStartX = bar.node.position.x
|
||||
+ barLocalX * bar.node.scale.x
|
||||
+ PROGRESS_ANCHOR_VISUAL_OFFSET;
|
||||
}
|
||||
|
||||
private _normalize(progress: number): number {
|
||||
if (!Number.isFinite(progress) || progress <= 0) return 0;
|
||||
return Math.max(MIN_PROGRESS_RATIO, Math.min(1, progress));
|
||||
}
|
||||
|
||||
private _clamp(progress: number): number {
|
||||
if (!Number.isFinite(progress) || progress <= 0) return 0;
|
||||
return Math.min(1, progress);
|
||||
}
|
||||
}
|
||||
9
assets/scripts/utils/AchievementTitleAnimator.ts.meta
Normal file
9
assets/scripts/utils/AchievementTitleAnimator.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "54354f70-d976-4008-b1a9-40473c99e872",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ export class AchievementTitleManager {
|
||||
titleText: currentStage.titleText,
|
||||
nextTitleText: nextStage.titleText,
|
||||
nextTitleProgress,
|
||||
progressText: `还差${remainingToNextTitle}题获得${nextStage.titleText}`,
|
||||
progressText: `还差${remainingToNextTitle}题,解锁新成就等级`,
|
||||
completedLevelCount,
|
||||
currentTitleStartCount: currentStage.startCount,
|
||||
nextTitleRequiredCount: nextStage.startCount,
|
||||
|
||||
55
assets/scripts/utils/AudioManager.ts
Normal file
55
assets/scripts/utils/AudioManager.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { AudioClip, AudioSource, Node } from 'cc';
|
||||
|
||||
/**
|
||||
* 音效管理器
|
||||
* 统一管理全局按钮点击等通用音效,避免页面各自维护 AudioSource。
|
||||
*/
|
||||
export class AudioManager {
|
||||
private static _instance: AudioManager | null = null;
|
||||
|
||||
private _clickAudio: AudioClip | null = null;
|
||||
private _hostNode: Node | null = null;
|
||||
private _audioSource: AudioSource | null = null;
|
||||
|
||||
static get instance(): AudioManager {
|
||||
if (!this._instance) {
|
||||
this._instance = new AudioManager();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
private constructor() {}
|
||||
|
||||
init(clickAudio: AudioClip | null, hostNode: Node | null): void {
|
||||
this._clickAudio = clickAudio;
|
||||
this._hostNode = hostNode;
|
||||
this._audioSource = null;
|
||||
}
|
||||
|
||||
playButtonClick(): void {
|
||||
this._playOneShot(this._clickAudio);
|
||||
}
|
||||
|
||||
private _playOneShot(clip: AudioClip | null): void {
|
||||
if (!clip) {
|
||||
return;
|
||||
}
|
||||
|
||||
const audioSource = this._ensureAudioSource();
|
||||
audioSource?.playOneShot(clip);
|
||||
}
|
||||
|
||||
private _ensureAudioSource(): AudioSource | null {
|
||||
if (this._audioSource?.isValid) {
|
||||
return this._audioSource;
|
||||
}
|
||||
|
||||
if (!this._hostNode?.isValid) {
|
||||
console.warn('[AudioManager] 未初始化宿主节点,无法播放音效');
|
||||
return null;
|
||||
}
|
||||
|
||||
this._audioSource = this._hostNode.getComponent(AudioSource) ?? this._hostNode.addComponent(AudioSource);
|
||||
return this._audioSource;
|
||||
}
|
||||
}
|
||||
9
assets/scripts/utils/AudioManager.ts.meta
Normal file
9
assets/scripts/utils/AudioManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "2dc839e1-6bb2-4d35-a2c4-bf90f85f40e8",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
147
assets/scripts/utils/ShareLaunchHandler.ts
Normal file
147
assets/scripts/utils/ShareLaunchHandler.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { WxSDK } from './WxSDK';
|
||||
import { ShareManager } from './ShareManager';
|
||||
import { AuthManager } from './AuthManager';
|
||||
import { ViewManager } from '../core/ViewManager';
|
||||
|
||||
/**
|
||||
* 分享启动监听器
|
||||
*
|
||||
* 微信小游戏未被杀掉、只是退到后台时,再次通过好友分享卡片打开小游戏,
|
||||
* 不会重新走启动链路(PageLoading 不会再跑),因此 `wx.getLaunchOptionsSync()`
|
||||
* 取到的 query 可能是上一次启动的旧值。这个 handler 通过 `wx.onShow`
|
||||
* 拿到最新的 query,检测 shareCode 变化后:
|
||||
* 1. 清掉旧的分享态
|
||||
* 2. 调用 `ShareManager.joinShare(code)` 拉取新的题单
|
||||
* 3. 直接打开 `PageLevel` 进入分享挑战
|
||||
*
|
||||
* 对应在 PageLevel 那侧通过 `onViewShow` 检测到 ShareManager.shareCode
|
||||
* 变化,重新走 `_reinitLevelSession`。
|
||||
*/
|
||||
export class ShareLaunchHandler {
|
||||
private static _instance: ShareLaunchHandler | null = null;
|
||||
|
||||
static get instance(): ShareLaunchHandler {
|
||||
if (!this._instance) {
|
||||
this._instance = new ShareLaunchHandler();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/** 已经处理过的 shareCode,相同则不再重复 join */
|
||||
private _activeShareCode: string | null = null;
|
||||
|
||||
/** 是否正在处理一次 onShow 触发的 join 流程,避免并发 */
|
||||
private _isHandlingShow: boolean = false;
|
||||
|
||||
/** 是否已经初始化 */
|
||||
private _initialized: boolean = false;
|
||||
|
||||
private _showHandler = (res: { query?: Record<string, any> } | undefined) => {
|
||||
const code = WxSDK.extractShareCodeFromQuery(res?.query);
|
||||
if (!code) {
|
||||
return;
|
||||
}
|
||||
// 同一个 shareCode 且当前已经处于该分享态,无需重复处理
|
||||
if (code === this._activeShareCode && ShareManager.instance.isShareMode) {
|
||||
return;
|
||||
}
|
||||
// 即使不是新的 code,但如果 ShareManager 已经丢失了分享态(例如挑战完成被 clear),
|
||||
// 用户重新点同一个分享卡片仍然应当重新加入。
|
||||
void this._handleShareCode(code);
|
||||
};
|
||||
|
||||
private _hideHandler = () => {
|
||||
// 目前不在 onHide 时做任何破坏性操作;保留监听只为方便后续扩展
|
||||
// (比如:暂停倒计时、上报埋点)。
|
||||
console.log('[ShareLaunchHandler] 小游戏切到后台');
|
||||
};
|
||||
|
||||
/**
|
||||
* 在 main.onLoad 中调用,注册 wx.onShow / wx.onHide。
|
||||
* 同时把当前启动参数中的 shareCode 作为种子,避免初次冷启动时
|
||||
* 因 wx.onShow 也会被调用一次而重复触发分享流程。
|
||||
*/
|
||||
init(): void {
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._initialized = true;
|
||||
|
||||
if (!WxSDK.isWechat()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 冷启动时先把当前 launch 中的 shareCode 标记成已处理,
|
||||
// 避免 wx.onShow 在初始展示时拿到同一个 code 又走一遍 join。
|
||||
this._activeShareCode = WxSDK.getShareCodeFromLaunch();
|
||||
|
||||
WxSDK.onAppShow(this._showHandler);
|
||||
WxSDK.onAppHide(this._hideHandler);
|
||||
|
||||
console.log('[ShareLaunchHandler] 已注册 onShow/onHide 监听');
|
||||
}
|
||||
|
||||
/**
|
||||
* 由 PageLoading 在初始 join 之后调用,把已处理的 shareCode 显式同步过来,
|
||||
* 让 onShow 收到相同 code 时不会重复 join。
|
||||
*/
|
||||
markActiveShareCode(code: string | null): void {
|
||||
this._activeShareCode = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主动取消监听(一般无需调用,留作扩展)
|
||||
*/
|
||||
dispose(): void {
|
||||
if (!this._initialized) return;
|
||||
this._initialized = false;
|
||||
WxSDK.offAppShow(this._showHandler);
|
||||
WxSDK.offAppHide(this._hideHandler);
|
||||
}
|
||||
|
||||
private async _handleShareCode(code: string): Promise<void> {
|
||||
if (this._isHandlingShow) {
|
||||
console.log('[ShareLaunchHandler] 已有 onShow 分享流程在执行,跳过', code);
|
||||
return;
|
||||
}
|
||||
this._isHandlingShow = true;
|
||||
|
||||
try {
|
||||
console.log('[ShareLaunchHandler] 检测到新的 shareCode,准备切换:', code);
|
||||
|
||||
// 确保已登录(initialize 内部对已有 token 做了校验,幂等可重复调用)
|
||||
const loginOk = await AuthManager.instance.initialize();
|
||||
if (!loginOk) {
|
||||
console.warn('[ShareLaunchHandler] 登录失败,放弃 onShow 分享切换');
|
||||
return;
|
||||
}
|
||||
|
||||
// 切到新的分享前清掉旧分享态,避免 ShareManager 内残留旧题单导致 PageLevel 错位
|
||||
if (ShareManager.instance.isShareMode) {
|
||||
ShareManager.instance.clearShareMode();
|
||||
}
|
||||
|
||||
const joinOk = await ShareManager.instance.joinShare(code);
|
||||
if (!joinOk) {
|
||||
console.warn('[ShareLaunchHandler] 加入分享失败:', code);
|
||||
return;
|
||||
}
|
||||
|
||||
// 标记当前激活的分享码
|
||||
this._activeShareCode = code;
|
||||
|
||||
// 跳过中间页,直接打开 PageLevel 进入分享挑战。
|
||||
// PageLevel 会在 onViewShow 中根据 ShareManager.shareCode 与本地缓存比对,
|
||||
// 决定是否需要 `_reinitLevelSession`。
|
||||
ViewManager.instance.open('PageLevel', {
|
||||
params: { shareMode: true },
|
||||
});
|
||||
|
||||
console.log('[ShareLaunchHandler] 已切换到分享挑战:', code);
|
||||
} catch (err) {
|
||||
console.error('[ShareLaunchHandler] 处理 shareCode 异常:', err);
|
||||
} finally {
|
||||
this._isHandlingShow = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/scripts/utils/ShareLaunchHandler.ts.meta
Normal file
9
assets/scripts/utils/ShareLaunchHandler.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0709f849-66c8-4e4c-aec5-044c3c414c3e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SpriteFrame, Texture2D, ImageAsset, assetManager } from 'cc';
|
||||
import { HttpUtil } from './HttpUtil';
|
||||
import { WxSDK } from './WxSDK';
|
||||
import { API_ENDPOINTS, getShareJoinUrl, getShareSubmitUrl, API_TIMEOUT } from '../config/ApiConfig';
|
||||
import { API_ENDPOINTS, getShareDetailUrl, getShareJoinUrl, getShareSubmitUrl, API_TIMEOUT } from '../config/ApiConfig';
|
||||
import {
|
||||
ApiEnvelope,
|
||||
CreateShareData,
|
||||
@@ -9,6 +9,9 @@ import {
|
||||
ShareLevelData,
|
||||
CreatedShareItem,
|
||||
CreatedShareListData,
|
||||
ParticipatedShareItem,
|
||||
ParticipatedShareListData,
|
||||
ShareDetailData,
|
||||
SubmitShareData,
|
||||
SubmitShareLevel,
|
||||
} from '../types/ApiTypes';
|
||||
@@ -30,6 +33,7 @@ export class ShareManager {
|
||||
private _shareTitle: string = '';
|
||||
private _shareCode: string | null = null;
|
||||
private _createdShares: CreatedShareItem[] = [];
|
||||
private _participatedShares: ParticipatedShareItem[] = [];
|
||||
|
||||
/** 图片缓存:URL -> SpriteFrame */
|
||||
private _imageCache: Map<string, SpriteFrame> = new Map();
|
||||
@@ -51,6 +55,10 @@ export class ShareManager {
|
||||
return [...this._createdShares];
|
||||
}
|
||||
|
||||
get participatedShares(): ParticipatedShareItem[] {
|
||||
return [...this._participatedShares];
|
||||
}
|
||||
|
||||
get shareCode(): string | null {
|
||||
return this._shareCode;
|
||||
}
|
||||
@@ -157,6 +165,47 @@ export class ShareManager {
|
||||
}
|
||||
}
|
||||
|
||||
async fetchParticipatedShares(): Promise<ParticipatedShareItem[] | null> {
|
||||
try {
|
||||
const response = await HttpUtil.get<ApiEnvelope<ParticipatedShareListData>>(
|
||||
API_ENDPOINTS.SHARE_PARTICIPATED,
|
||||
API_TIMEOUT.DEFAULT,
|
||||
);
|
||||
|
||||
if (!response.success || !response.data) {
|
||||
console.error('[ShareManager] 获取我参与的挑战列表失败:', response.message);
|
||||
return null;
|
||||
}
|
||||
|
||||
this._participatedShares = response.data.items ?? [];
|
||||
console.log(`[ShareManager] 获取我参与的挑战列表成功: ${this._participatedShares.length} 条`);
|
||||
return this.participatedShares;
|
||||
} catch (err) {
|
||||
console.error('[ShareManager] 获取我参与的挑战列表异常:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async fetchShareDetail(code: string): Promise<ShareDetailData | null> {
|
||||
try {
|
||||
const response = await HttpUtil.get<ApiEnvelope<ShareDetailData>>(
|
||||
getShareDetailUrl(code),
|
||||
API_TIMEOUT.DEFAULT,
|
||||
);
|
||||
|
||||
if (!response.success || !response.data) {
|
||||
console.error('[ShareManager] 获取分享挑战详情失败:', response.message);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`[ShareManager] 获取分享挑战详情成功: ${response.data.title}, ${response.data.rankings?.length ?? 0} 条排行`);
|
||||
return response.data;
|
||||
} catch (err) {
|
||||
console.error('[ShareManager] 获取分享挑战详情异常:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async ensureShareLevelReady(index: number): Promise<RuntimeLevelConfig | null> {
|
||||
if (!this._shareLevels || index < 0 || index >= this._shareLevels.length) {
|
||||
return null;
|
||||
|
||||
@@ -398,15 +398,82 @@ export class WxSDK {
|
||||
|
||||
try {
|
||||
const options = wxApi.getLaunchOptionsSync();
|
||||
if (options?.query?.shareCode) {
|
||||
console.log('[WxSDK] 检测到分享码:', options.query.shareCode);
|
||||
return options.query.shareCode;
|
||||
const code = WxSDK.extractShareCodeFromQuery(options?.query);
|
||||
if (code) {
|
||||
console.log('[WxSDK] 检测到分享码:', code);
|
||||
return code;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[WxSDK] 获取启动参数失败:', err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从查询对象(来自 launch options 或 onShow 回调)中提取 shareCode
|
||||
*/
|
||||
static extractShareCodeFromQuery(query: Record<string, any> | null | undefined): string | null {
|
||||
const code = query?.shareCode;
|
||||
return typeof code === 'string' && code.length > 0 ? code : null;
|
||||
}
|
||||
|
||||
// ==================== 前后台生命周期 ====================
|
||||
|
||||
/**
|
||||
* 监听小游戏切到前台事件。
|
||||
* 同一个回调可重复注册多次:内部用 wx.onShow,请确保业务层做幂等处理或在卸载时调用 offAppShow。
|
||||
* @param callback 切前台时触发,包含本次显示对应的 query / scene 等参数
|
||||
*/
|
||||
static onAppShow(callback: (res: { query?: Record<string, any>; scene?: number; path?: string } | undefined) => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.onShow !== 'function') {
|
||||
console.warn('[WxSDK] 当前微信版本不支持 onShow');
|
||||
return;
|
||||
}
|
||||
|
||||
wxApi.onShow(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消监听小游戏切到前台事件
|
||||
*/
|
||||
static offAppShow(callback: (res: any) => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.offShow === 'function') {
|
||||
wxApi.offShow(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听小游戏切到后台事件
|
||||
*/
|
||||
static onAppHide(callback: () => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.onHide !== 'function') {
|
||||
console.warn('[WxSDK] 当前微信版本不支持 onHide');
|
||||
return;
|
||||
}
|
||||
|
||||
wxApi.onHide(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消监听小游戏切到后台事件
|
||||
*/
|
||||
static offAppHide(callback: () => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.offHide === 'function') {
|
||||
wxApi.offHide(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 隐私授权相关 ====================
|
||||
|
||||
BIN
extensions/.DS_Store
vendored
Normal file
BIN
extensions/.DS_Store
vendored
Normal file
Binary file not shown.
1
extensions/cocos-mcp-server
Submodule
1
extensions/cocos-mcp-server
Submodule
Submodule extensions/cocos-mcp-server added at 754adecdb8
6
settings/mcp-server.json
Normal file
6
settings/mcp-server.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"port": 3008,
|
||||
"autoStart": false,
|
||||
"debugLog": false,
|
||||
"maxConnections": 10
|
||||
}
|
||||
957
settings/tool-manager.json
Normal file
957
settings/tool-manager.json
Normal file
@@ -0,0 +1,957 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"id": "4e401ac4-fa11-4f3b-9531-bb09687de4df",
|
||||
"name": "默认配置",
|
||||
"description": "自动创建的默认工具配置",
|
||||
"tools": [
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "get_current_scene",
|
||||
"enabled": true,
|
||||
"description": "Get current scene information"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "get_scene_list",
|
||||
"enabled": true,
|
||||
"description": "Get all scenes in the project"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "open_scene",
|
||||
"enabled": true,
|
||||
"description": "Open a scene by path"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "save_scene",
|
||||
"enabled": true,
|
||||
"description": "Save current scene"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "create_scene",
|
||||
"enabled": true,
|
||||
"description": "Create a new scene asset"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "save_scene_as",
|
||||
"enabled": true,
|
||||
"description": "Save scene as new file"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "close_scene",
|
||||
"enabled": true,
|
||||
"description": "Close current scene"
|
||||
},
|
||||
{
|
||||
"category": "scene",
|
||||
"name": "get_scene_hierarchy",
|
||||
"enabled": true,
|
||||
"description": "Get the complete hierarchy of current scene"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "create_node",
|
||||
"enabled": true,
|
||||
"description": "Create a new node in the scene. Supports creating empty nodes, nodes with components, or instantiating from assets (prefabs, etc.). IMPORTANT: You should always provide parentUuid to specify where to create the node."
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "get_node_info",
|
||||
"enabled": true,
|
||||
"description": "Get node information by UUID"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "find_nodes",
|
||||
"enabled": true,
|
||||
"description": "Find nodes by name pattern"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "find_node_by_name",
|
||||
"enabled": true,
|
||||
"description": "Find first node by exact name"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "get_all_nodes",
|
||||
"enabled": true,
|
||||
"description": "Get all nodes in the scene with their UUIDs"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "set_node_property",
|
||||
"enabled": true,
|
||||
"description": "Set node property value (prefer using set_node_transform for active/layer/mobility/position/rotation/scale)"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "set_node_transform",
|
||||
"enabled": true,
|
||||
"description": "Set node transform properties (position, rotation, scale) with unified interface. Automatically handles 2D/3D node differences."
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "delete_node",
|
||||
"enabled": true,
|
||||
"description": "Delete a node from scene"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "move_node",
|
||||
"enabled": true,
|
||||
"description": "Move node to new parent"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "duplicate_node",
|
||||
"enabled": true,
|
||||
"description": "Duplicate a node"
|
||||
},
|
||||
{
|
||||
"category": "node",
|
||||
"name": "detect_node_type",
|
||||
"enabled": true,
|
||||
"description": "Detect if a node is 2D or 3D based on its components and properties"
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "add_component",
|
||||
"enabled": true,
|
||||
"description": "Add a component to a specific node. IMPORTANT: You must provide the nodeUuid parameter to specify which node to add the component to."
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "remove_component",
|
||||
"enabled": true,
|
||||
"description": "Remove a component from a node. componentType must be the component's classId (cid, i.e. the type field from getComponents), not the script name or class name. Use getComponents to get the correct cid."
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "get_components",
|
||||
"enabled": true,
|
||||
"description": "Get all components of a node"
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "get_component_info",
|
||||
"enabled": true,
|
||||
"description": "Get specific component information"
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "set_component_property",
|
||||
"enabled": true,
|
||||
"description": "Set component property values for UI components or custom script components. Supports setting properties of built-in UI components (e.g., cc.Label, cc.Sprite) and custom script components. Note: For node basic properties (name, active, layer, etc.), use set_node_property. For node transform properties (position, rotation, scale, etc.), use set_node_transform."
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "attach_script",
|
||||
"enabled": true,
|
||||
"description": "Attach a script component to a node"
|
||||
},
|
||||
{
|
||||
"category": "component",
|
||||
"name": "get_available_components",
|
||||
"enabled": true,
|
||||
"description": "Get list of available component types"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "get_prefab_list",
|
||||
"enabled": true,
|
||||
"description": "Get all prefabs in the project"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "load_prefab",
|
||||
"enabled": true,
|
||||
"description": "Load a prefab by path"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "instantiate_prefab",
|
||||
"enabled": true,
|
||||
"description": "Instantiate a prefab in the scene"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "create_prefab",
|
||||
"enabled": true,
|
||||
"description": "Create a prefab from a node with all children and components"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "update_prefab",
|
||||
"enabled": true,
|
||||
"description": "Update an existing prefab"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "revert_prefab",
|
||||
"enabled": true,
|
||||
"description": "Revert prefab instance to original"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "get_prefab_info",
|
||||
"enabled": true,
|
||||
"description": "Get detailed prefab information"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "validate_prefab",
|
||||
"enabled": true,
|
||||
"description": "Validate a prefab file format"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "duplicate_prefab",
|
||||
"enabled": true,
|
||||
"description": "Duplicate an existing prefab"
|
||||
},
|
||||
{
|
||||
"category": "prefab",
|
||||
"name": "restore_prefab_node",
|
||||
"enabled": true,
|
||||
"description": "Restore prefab node using prefab asset (built-in undo record)"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "run_project",
|
||||
"enabled": true,
|
||||
"description": "Run the project in preview mode"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "build_project",
|
||||
"enabled": true,
|
||||
"description": "Build the project"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_project_info",
|
||||
"enabled": true,
|
||||
"description": "Get project information"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_project_settings",
|
||||
"enabled": true,
|
||||
"description": "Get project settings"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "refresh_assets",
|
||||
"enabled": true,
|
||||
"description": "Refresh asset database"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "import_asset",
|
||||
"enabled": true,
|
||||
"description": "Import an asset file"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_asset_info",
|
||||
"enabled": true,
|
||||
"description": "Get asset information"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_assets",
|
||||
"enabled": true,
|
||||
"description": "Get assets by type"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_build_settings",
|
||||
"enabled": true,
|
||||
"description": "Get build settings - shows current limitations"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "open_build_panel",
|
||||
"enabled": true,
|
||||
"description": "Open the build panel in the editor"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "check_builder_status",
|
||||
"enabled": true,
|
||||
"description": "Check if builder worker is ready"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "start_preview_server",
|
||||
"enabled": true,
|
||||
"description": "Start preview server"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "stop_preview_server",
|
||||
"enabled": true,
|
||||
"description": "Stop preview server"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "create_asset",
|
||||
"enabled": true,
|
||||
"description": "Create a new asset file or folder"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "copy_asset",
|
||||
"enabled": true,
|
||||
"description": "Copy an asset to another location"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "move_asset",
|
||||
"enabled": true,
|
||||
"description": "Move an asset to another location"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "delete_asset",
|
||||
"enabled": true,
|
||||
"description": "Delete an asset"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "save_asset",
|
||||
"enabled": true,
|
||||
"description": "Save asset content"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "reimport_asset",
|
||||
"enabled": true,
|
||||
"description": "Reimport an asset"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "query_asset_path",
|
||||
"enabled": true,
|
||||
"description": "Get asset disk path"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "query_asset_uuid",
|
||||
"enabled": true,
|
||||
"description": "Get asset UUID from URL"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "query_asset_url",
|
||||
"enabled": true,
|
||||
"description": "Get asset URL from UUID"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "find_asset_by_name",
|
||||
"enabled": true,
|
||||
"description": "Find assets by name (supports partial matching and multiple results)"
|
||||
},
|
||||
{
|
||||
"category": "project",
|
||||
"name": "get_asset_details",
|
||||
"enabled": true,
|
||||
"description": "Get detailed asset information including spriteFrame sub-assets"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_console_logs",
|
||||
"enabled": true,
|
||||
"description": "Get editor console logs"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "clear_console",
|
||||
"enabled": true,
|
||||
"description": "Clear editor console"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "execute_script",
|
||||
"enabled": true,
|
||||
"description": "Execute JavaScript in scene context"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_node_tree",
|
||||
"enabled": true,
|
||||
"description": "Get detailed node tree for debugging"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_performance_stats",
|
||||
"enabled": true,
|
||||
"description": "Get performance statistics"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "validate_scene",
|
||||
"enabled": true,
|
||||
"description": "Validate current scene for issues"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_editor_info",
|
||||
"enabled": true,
|
||||
"description": "Get editor and environment information"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_project_logs",
|
||||
"enabled": true,
|
||||
"description": "Get project logs from temp/logs/project.log file"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "get_log_file_info",
|
||||
"enabled": true,
|
||||
"description": "Get information about the project log file"
|
||||
},
|
||||
{
|
||||
"category": "debug",
|
||||
"name": "search_project_logs",
|
||||
"enabled": true,
|
||||
"description": "Search for specific patterns or errors in project logs"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "open_preferences_settings",
|
||||
"enabled": true,
|
||||
"description": "Open preferences settings panel"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "query_preferences_config",
|
||||
"enabled": true,
|
||||
"description": "Query preferences configuration"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "set_preferences_config",
|
||||
"enabled": true,
|
||||
"description": "Set preferences configuration"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "get_all_preferences",
|
||||
"enabled": true,
|
||||
"description": "Get all available preferences categories"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "reset_preferences",
|
||||
"enabled": true,
|
||||
"description": "Reset preferences to default values"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "export_preferences",
|
||||
"enabled": true,
|
||||
"description": "Export current preferences configuration"
|
||||
},
|
||||
{
|
||||
"category": "preferences",
|
||||
"name": "import_preferences",
|
||||
"enabled": true,
|
||||
"description": "Import preferences configuration from file"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "query_server_ip_list",
|
||||
"enabled": true,
|
||||
"description": "Query server IP list"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "query_sorted_server_ip_list",
|
||||
"enabled": true,
|
||||
"description": "Get sorted server IP list"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "query_server_port",
|
||||
"enabled": true,
|
||||
"description": "Query editor server current port"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "get_server_status",
|
||||
"enabled": true,
|
||||
"description": "Get comprehensive server status information"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "check_server_connectivity",
|
||||
"enabled": true,
|
||||
"description": "Check server connectivity and network status"
|
||||
},
|
||||
{
|
||||
"category": "server",
|
||||
"name": "get_network_interfaces",
|
||||
"enabled": true,
|
||||
"description": "Get available network interfaces"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "get_broadcast_log",
|
||||
"enabled": true,
|
||||
"description": "Get recent broadcast messages log"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "listen_broadcast",
|
||||
"enabled": true,
|
||||
"description": "Start listening for specific broadcast messages"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "stop_listening",
|
||||
"enabled": true,
|
||||
"description": "Stop listening for specific broadcast messages"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "clear_broadcast_log",
|
||||
"enabled": true,
|
||||
"description": "Clear the broadcast messages log"
|
||||
},
|
||||
{
|
||||
"category": "broadcast",
|
||||
"name": "get_active_listeners",
|
||||
"enabled": true,
|
||||
"description": "Get list of active broadcast listeners"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "reset_node_property",
|
||||
"enabled": true,
|
||||
"description": "Reset node property to default value"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "move_array_element",
|
||||
"enabled": true,
|
||||
"description": "Move array element position"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "remove_array_element",
|
||||
"enabled": true,
|
||||
"description": "Remove array element at specific index"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "copy_node",
|
||||
"enabled": true,
|
||||
"description": "Copy node for later paste operation"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "paste_node",
|
||||
"enabled": true,
|
||||
"description": "Paste previously copied nodes"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "cut_node",
|
||||
"enabled": true,
|
||||
"description": "Cut node (copy + mark for move)"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "reset_node_transform",
|
||||
"enabled": true,
|
||||
"description": "Reset node position, rotation and scale"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "reset_component",
|
||||
"enabled": true,
|
||||
"description": "Reset component to default values"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "restore_prefab",
|
||||
"enabled": true,
|
||||
"description": "Restore prefab instance from asset"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "execute_component_method",
|
||||
"enabled": true,
|
||||
"description": "Execute method on component"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "execute_scene_script",
|
||||
"enabled": true,
|
||||
"description": "Execute scene script method"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "scene_snapshot",
|
||||
"enabled": true,
|
||||
"description": "Create scene state snapshot"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "scene_snapshot_abort",
|
||||
"enabled": true,
|
||||
"description": "Abort scene snapshot creation"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "begin_undo_recording",
|
||||
"enabled": true,
|
||||
"description": "Begin recording undo data"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "end_undo_recording",
|
||||
"enabled": true,
|
||||
"description": "End recording undo data"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "cancel_undo_recording",
|
||||
"enabled": true,
|
||||
"description": "Cancel undo recording"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "soft_reload_scene",
|
||||
"enabled": true,
|
||||
"description": "Soft reload current scene"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_scene_ready",
|
||||
"enabled": true,
|
||||
"description": "Check if scene is ready"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_scene_dirty",
|
||||
"enabled": true,
|
||||
"description": "Check if scene has unsaved changes"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_scene_classes",
|
||||
"enabled": true,
|
||||
"description": "Query all registered classes"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_scene_components",
|
||||
"enabled": true,
|
||||
"description": "Query available scene components"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_component_has_script",
|
||||
"enabled": true,
|
||||
"description": "Check if component has script"
|
||||
},
|
||||
{
|
||||
"category": "sceneAdvanced",
|
||||
"name": "query_nodes_by_asset_uuid",
|
||||
"enabled": true,
|
||||
"description": "Find nodes that use specific asset UUID"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "change_gizmo_tool",
|
||||
"enabled": true,
|
||||
"description": "Change Gizmo tool"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_gizmo_tool_name",
|
||||
"enabled": true,
|
||||
"description": "Get current Gizmo tool name"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "change_gizmo_pivot",
|
||||
"enabled": true,
|
||||
"description": "Change transform pivot point"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_gizmo_pivot",
|
||||
"enabled": true,
|
||||
"description": "Get current Gizmo pivot point"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_gizmo_view_mode",
|
||||
"enabled": true,
|
||||
"description": "Query view mode (view/select)"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "change_gizmo_coordinate",
|
||||
"enabled": true,
|
||||
"description": "Change coordinate system"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_gizmo_coordinate",
|
||||
"enabled": true,
|
||||
"description": "Get current coordinate system"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "change_view_mode_2d_3d",
|
||||
"enabled": true,
|
||||
"description": "Change 2D/3D view mode"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_view_mode_2d_3d",
|
||||
"enabled": true,
|
||||
"description": "Get current view mode"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "set_grid_visible",
|
||||
"enabled": true,
|
||||
"description": "Show/hide grid"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_grid_visible",
|
||||
"enabled": true,
|
||||
"description": "Query grid visibility status"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "set_icon_gizmo_3d",
|
||||
"enabled": true,
|
||||
"description": "Set IconGizmo to 3D or 2D mode"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_icon_gizmo_3d",
|
||||
"enabled": true,
|
||||
"description": "Query IconGizmo mode"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "set_icon_gizmo_size",
|
||||
"enabled": true,
|
||||
"description": "Set IconGizmo size"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "query_icon_gizmo_size",
|
||||
"enabled": true,
|
||||
"description": "Query IconGizmo size"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "focus_camera_on_nodes",
|
||||
"enabled": true,
|
||||
"description": "Focus scene camera on nodes"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "align_camera_with_view",
|
||||
"enabled": true,
|
||||
"description": "Apply scene camera position and angle to selected node"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "align_view_with_node",
|
||||
"enabled": true,
|
||||
"description": "Apply selected node position and angle to current view"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "get_scene_view_status",
|
||||
"enabled": true,
|
||||
"description": "Get comprehensive scene view status"
|
||||
},
|
||||
{
|
||||
"category": "sceneView",
|
||||
"name": "reset_scene_view",
|
||||
"enabled": true,
|
||||
"description": "Reset scene view to default settings"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "add_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Add reference image(s) to scene"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "remove_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Remove reference image(s)"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "switch_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Switch to specific reference image"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "set_reference_image_data",
|
||||
"enabled": true,
|
||||
"description": "Set reference image transform and display properties"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "query_reference_image_config",
|
||||
"enabled": true,
|
||||
"description": "Query reference image configuration"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "query_current_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Query current reference image data"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "refresh_reference_image",
|
||||
"enabled": true,
|
||||
"description": "Refresh reference image display"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "set_reference_image_position",
|
||||
"enabled": true,
|
||||
"description": "Set reference image position"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "set_reference_image_scale",
|
||||
"enabled": true,
|
||||
"description": "Set reference image scale"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "set_reference_image_opacity",
|
||||
"enabled": true,
|
||||
"description": "Set reference image opacity"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "list_reference_images",
|
||||
"enabled": true,
|
||||
"description": "List all available reference images"
|
||||
},
|
||||
{
|
||||
"category": "referenceImage",
|
||||
"name": "clear_all_reference_images",
|
||||
"enabled": true,
|
||||
"description": "Clear all reference images"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "save_asset_meta",
|
||||
"enabled": true,
|
||||
"description": "Save asset meta information"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "generate_available_url",
|
||||
"enabled": true,
|
||||
"description": "Generate an available URL based on input URL"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "query_asset_db_ready",
|
||||
"enabled": true,
|
||||
"description": "Check if asset database is ready"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "open_asset_external",
|
||||
"enabled": true,
|
||||
"description": "Open asset with external program"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "batch_import_assets",
|
||||
"enabled": true,
|
||||
"description": "Import multiple assets in batch"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "batch_delete_assets",
|
||||
"enabled": true,
|
||||
"description": "Delete multiple assets in batch"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "validate_asset_references",
|
||||
"enabled": true,
|
||||
"description": "Validate asset references and find broken links"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "get_asset_dependencies",
|
||||
"enabled": true,
|
||||
"description": "Get asset dependency tree"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "get_unused_assets",
|
||||
"enabled": true,
|
||||
"description": "Find unused assets in project"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "compress_textures",
|
||||
"enabled": true,
|
||||
"description": "Batch compress texture assets"
|
||||
},
|
||||
{
|
||||
"category": "assetAdvanced",
|
||||
"name": "export_asset_manifest",
|
||||
"enabled": true,
|
||||
"description": "Export asset manifest/inventory"
|
||||
},
|
||||
{
|
||||
"category": "validation",
|
||||
"name": "validate_json_params",
|
||||
"enabled": true,
|
||||
"description": "Validate and fix JSON parameters before sending to other tools"
|
||||
},
|
||||
{
|
||||
"category": "validation",
|
||||
"name": "safe_string_value",
|
||||
"enabled": true,
|
||||
"description": "Create a safe string value that won't cause JSON parsing issues"
|
||||
},
|
||||
{
|
||||
"category": "validation",
|
||||
"name": "format_mcp_request",
|
||||
"enabled": true,
|
||||
"description": "Format a complete MCP request with proper JSON escaping"
|
||||
}
|
||||
],
|
||||
"createdAt": "2026-05-19T14:37:17.528Z",
|
||||
"updatedAt": "2026-05-19T14:37:17.528Z"
|
||||
}
|
||||
],
|
||||
"currentConfigId": "4e401ac4-fa11-4f3b-9531-bb09687de4df",
|
||||
"maxConfigSlots": 5
|
||||
}
|
||||
Reference in New Issue
Block a user