Compare commits
23 Commits
fe823df01e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d246de24c | ||
|
|
f8198e0463 | ||
|
|
dd883f14b0 | ||
|
|
16efb1bb25 | ||
|
|
fbea31b9ea | ||
|
|
950572ad74 | ||
|
|
9d60fa601d | ||
|
|
1e5017e28e | ||
|
|
5074706115 | ||
|
|
f5732b46a5 | ||
|
|
ecc82ae9a7 | ||
|
|
4f93725779 | ||
|
|
8d54ffdbf8 | ||
|
|
4d699c127f | ||
|
|
457dd07d80 | ||
|
|
5eef9d8528 | ||
|
|
34e06480ce | ||
|
|
5d472e1c30 | ||
|
|
ddf51919b0 | ||
|
|
2f74f260b7 | ||
|
|
9cf499a5e1 | ||
|
|
69c0986996 | ||
|
|
447e7a944a |
102
AGENTS.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Repository Guidelines
|
||||||
|
|
||||||
|
## 项目结构与模块组织
|
||||||
|
本仓库是 `Cocos Creator 3.8.8` 小游戏项目。主入口在 `assets/main.ts`,主场景是 `assets/main.scene`。页面与弹窗组件集中在 `assets/prefabs/`,命名通常为 `PageXxx.ts`、`PassModal.ts`。公共逻辑位于 `assets/scripts/`:`core/` 放页面基类与视图管理,`utils/` 放 SDK、鉴权、存储、网络等工具,`config/` 放接口配置,`types/` 放类型定义。静态资源在 `assets/resources/`,编辑器配置在 `settings/v2/packages/`,设计说明在 `docs/` 与根目录分析文档中。
|
||||||
|
|
||||||
|
## 构建、调试与开发命令
|
||||||
|
先运行 `npm install`,同步 `minigame-api-typings` 依赖。日常开发主要通过 Cocos Creator 编辑器完成:使用 3.8.8 打开仓库,点击 `Play` 预览,使用 `Project > Build` 或 `Cmd+B` 构建小游戏包。若编辑器已生成 `temp/tsconfig.cocos.json`,可执行 `npx tsc --noEmit` 做一次 TypeScript 静态检查。
|
||||||
|
|
||||||
|
## 代码风格与命名约定
|
||||||
|
项目使用 TypeScript,当前代码统一为 4 空格缩进。组件类、页面类、管理器类使用 `PascalCase`,实例属性与私有方法使用 `camelCase` / `_camelCase`,管理器统一使用 `XxxManager` 后缀。新增页面、预制体、脚本请保持同名,例如 `PageLevel.prefab` 对应 `PageLevel.ts`。优先把复用逻辑放入 `assets/scripts/utils/` 或 `assets/scripts/core/`,不要把业务代码散落到场景脚本中。Cocos 资源的 `.meta` 文件必须一并提交。
|
||||||
|
|
||||||
|
## 测试与验证
|
||||||
|
仓库当前未配置 Jest、Vitest 一类自动化测试。提交前至少完成三项验证:1. 编辑器预览主流程可进入页面;2. 目标平台构建成功;3. 涉及微信能力时,在真机或开发者工具验证登录、分享、隐私授权等流程。若修改接口或体力/关卡逻辑,补充手动验证步骤到 PR 描述。
|
||||||
|
|
||||||
|
## 提交与 Pull Request 规范
|
||||||
|
Git 历史采用 Conventional Commits,且摘要多为中文,例如 `feat: 支持分享关卡通关上报`、`fix: 修复关卡排序`、`docs: 添加设计文档`。请继续使用 `feat:`、`fix:`、`perf:`、`docs:` 前缀,首行聚焦单一变更。PR 需说明改动范围、影响页面或模块、验证方式;涉及 UI 请附截图或录屏,涉及微信环境差异请写明复现条件与平台。
|
||||||
|
|
||||||
|
|
||||||
|
<claude-mem-context>
|
||||||
|
# Memory Context
|
||||||
|
|
||||||
|
# [mp-xieyingeng] recent context, 2026-04-29 6:32pm GMT+8
|
||||||
|
|
||||||
|
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: 50 obs (9,755t read) | 1,857,754t work | 99% savings
|
||||||
|
|
||||||
|
### Apr 26, 2026
|
||||||
|
1330 4:45p 🔄 API Protocol Upgrade - NextLevel-Driven Architecture
|
||||||
|
1331 " ✅ ApiTypes.ts type definitions updated
|
||||||
|
1332 " ✅ Task 4 completed: ApiTypes.ts type definitions updated
|
||||||
|
1333 4:46p ✅ Tasks 4 and 5 completed: type definitions migrated
|
||||||
|
1334 5:10p 🔵 进度条小百分比时圆角畸形问题
|
||||||
|
1335 " 🔵 进度条圆角畸形问题调查中
|
||||||
|
1336 " 🔵 通关弹窗进度条使用 Cocos ProgressBar 组件
|
||||||
|
1337 5:11p 🔵 进度条圆角畸形调查中 - Prefab 结构检查
|
||||||
|
1338 " 🔵 ProgressBar 系统架构已定位
|
||||||
|
1340 " 🔵 找到进度条圆角畸形根本原因
|
||||||
|
1341 5:12p 🔵 进度条小百分比时圆角变形问题定位
|
||||||
|
1339 " 🔵 发现 RoundedRectMask 工具组件
|
||||||
|
S1309 移除 PageLevel.ts 进入关卡时弹出体力扣减 toast (Apr 26 at 5:16 PM)
|
||||||
|
1342 5:16p 🔵 PassModal 进度值规范化逻辑
|
||||||
|
1343 5:17p 🔴 进度条圆角畸形问题已修复
|
||||||
|
1344 " ⚖️ 探索使用 Mask 裁剪替代最小进度值方案
|
||||||
|
1345 " ⚖️ 否决 Mask 方案,确认最小进度值方案最优
|
||||||
|
### Apr 27, 2026
|
||||||
|
1346 9:21a 🔴 移除进入游戏后的体力扣减 toast 提示
|
||||||
|
1347 " 🔴 移除进入游戏后的体力扣减 toast 提示
|
||||||
|
1348 " 🟣 首页添加体力值显示功能
|
||||||
|
S1308 移除进入游戏关卡时弹出体力扣减的 toast 提示 (Apr 27 at 9:21 AM)
|
||||||
|
S1310 移除进入游戏体力扣减 toast 并在首页添加体力显示 (Apr 27 at 9:22 AM)
|
||||||
|
S1311 移除体力扣减 toast 并完善首页体验 (Apr 27 at 9:23 AM)
|
||||||
|
1349 9:25a ✅ PageHome.ts 添加 ToastManager 导入
|
||||||
|
1350 " ✅ PK按钮点击改为提示"功能开发中"
|
||||||
|
S1313 Implement object-fit: cover image scaling in Cocos Creator to prevent downloaded images from being distorted (Apr 27 at 9:26 AM)
|
||||||
|
1351 9:32a 🟣 Stamina animation system for level entry
|
||||||
|
1352 " 🔵 Cocos Creator game project structure discovered
|
||||||
|
1354 " 🟣 StarGame 按钮点击动画需求
|
||||||
|
1356 " 🔵 体力系统架构发现
|
||||||
|
1353 9:33a 🔵 StaminaManager API confirmed for stamina operations
|
||||||
|
1355 9:37a 🔵 项目结构和现有代码发现
|
||||||
|
1357 9:38a 🔵 EnterLevelData 结构分析
|
||||||
|
1359 9:39a 🟣 Stamina animation system implemented for game entry flow
|
||||||
|
1358 9:41a ⚖️ 体力值飞行动画实现计划制定完成
|
||||||
|
1362 9:45a 🟣 Image Cover Mode Scaling in Cocos Creator
|
||||||
|
S1312 Fix image distortion in PageLevel.ts by implementing object-fit: cover behavior for downloaded images (Apr 27 at 9:45 AM)
|
||||||
|
1360 " ✅ Cocos Creator animation imports added to PageHome.ts
|
||||||
|
1361 " ✅ Animation constants added to PageHome class
|
||||||
|
1363 " ✅ Start game button integrated with stamina check and animation flow
|
||||||
|
1364 " 🟣 Stamina consumption animation fully implemented in PageHome
|
||||||
|
S1314 Implement stamina consumption animation in Cocos Creator game - when clicking StarGame button, IconLive node flies to button with floating "-1" text, then navigates to level (Apr 27 at 9:45 AM)
|
||||||
|
1365 9:46a 🔴 Animation completes but navigation to PageLevel fails
|
||||||
|
S1315 为 PageLevel.ts 的 mainImage 和 mainImage2 节点实现 CSS cover 模式图片缩放 (Apr 27 at 9:46 AM)
|
||||||
|
1366 9:50a 🔴 Cocos Creator tween chain broken by premature node destroy
|
||||||
|
1367 9:55a 🔴 Navigation still failing after first tween chain fix - further debugging needed
|
||||||
|
1368 " 🔴 Decoupled fly animation from float text timing using setTimeout
|
||||||
|
1369 9:56a 🔴 Cocos Creator tween chain broken by any node state change mid-animation
|
||||||
|
1370 9:59a 🟣 CSS cover-style image scaling for PageLevel images
|
||||||
|
1371 10:01a ✅ PageLevel.ts imports extended for cover-style image scaling
|
||||||
|
1372 " 🟣 CSS cover-mode image scaling implemented for PageLevel images
|
||||||
|
S1316 Debug cover mode image overflow in PageLevel.ts - image exceeds container bounds despite Mask applied (Apr 27 at 10:02 AM)
|
||||||
|
1373 10:02a 🔴 Cover mode image overflows container bounds
|
||||||
|
1374 10:06a 🔵 GRAPHICS_RECT vs GRAPHICS_STENCIL for Mask in Cocos Creator
|
||||||
|
1375 10:08a 🔴 Mask.Type.RECT does not exist in Cocos Creator API
|
||||||
|
1376 " 🔵 MaskType enum found in Cocos Creator 3.8 engine declarations
|
||||||
|
1378 " 🔵 MaskType enum values confirmed - GRAPHICS_RECT exists
|
||||||
|
1377 10:09a 🔵 MaskType enum definition found at line 46015
|
||||||
|
1379 10:10a 🔴 Reverted Mask.Type to GRAPHICS_RECT
|
||||||
|
S1317 Implement CSS cover-mode image scaling for PageLevel.ts mainImage nodes (Apr 27 at 10:10 AM)
|
||||||
|
**Investigated**: Cover mode implementation in _applyCoverSprite() using Mask + scaled child node approach; Cocos Creator 3.8 MaskType enum investigation; root cause analysis of image overflow
|
||||||
|
|
||||||
|
**Learned**: Cocos Creator Mask only clips child nodes, NOT the container's own Sprite component; GRAPHICS_RECT = 0 is valid enum value in Cocos 3.8; container Sprite renders outside Mask bounds; solution: disable containerSprite and use child node for image display
|
||||||
|
|
||||||
|
**Completed**: _applyCoverSprite() method implemented with: Mask(GRAPHICS_RECT) on container, child node '_coverImg' with Sprite.SizeMode.RAW, cover scale calculation, containerSprite.enabled = false to prevent overflow
|
||||||
|
|
||||||
|
**Next Steps**: User to test in Cocos Creator editor to verify image clipping now works correctly
|
||||||
|
|
||||||
|
|
||||||
|
Access 1858k tokens of past work via get_observations([IDs]) or mem-search skill.
|
||||||
|
</claude-mem-context>
|
||||||
496
ARCHITECTURE.md
@@ -1,496 +0,0 @@
|
|||||||
# Architecture Overview
|
|
||||||
|
|
||||||
## System Architecture Diagram
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ COCOS CREATOR GAME │
|
|
||||||
│ WeChat Mini-Game Version 3.8.8 │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ PRESENTATION LAYER (UI) │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ PageLoading.ts ──────┐ │
|
|
||||||
│ (Loading Screen) │ │
|
|
||||||
│ │ │
|
|
||||||
│ ┌──────────┐ │ ┌──────────┐ ┌──────────┐ │
|
|
||||||
│ │PageHome │─────────┴──────│PageLevel │──────│PassModal │ │
|
|
||||||
│ │(Menu) │ │ (Play) │ │(Victory) │ │
|
|
||||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
|
||||||
│ ▲ ▲ │ │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ └────────────────┬───────────┘ │ │
|
|
||||||
│ │ (Back button) │ │
|
|
||||||
│ └─────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ Toast.ts ────────────────────────────────────────────────────────────│
|
|
||||||
│ (Notifications) │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ CORE LOGIC LAYER │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
|
||||||
│ │ PageLevel.ts │ │ PassModal.ts │ │
|
|
||||||
│ ├──────────────────────┤ ├──────────────────────┤ │
|
|
||||||
│ │ • Answer validation │ │ • Next level │ │
|
|
||||||
│ │ • Hint unlock (-life)│ │ • Share button │ │
|
|
||||||
│ │ • Countdown (60s) │ │ • Callbacks │ │
|
|
||||||
│ │ • Sound/Vibration │ │ │ │
|
|
||||||
│ │ • Life display │ │ │ │
|
|
||||||
│ └──────────────────────┘ └──────────────────────┘ │
|
|
||||||
│ ▲ ▲ │
|
|
||||||
│ │ │ │
|
|
||||||
│ └────────────────┬───────────────┘ │
|
|
||||||
│ │ │
|
|
||||||
│ ┌──────────────────────────┴──────────────────────────────────┐ │
|
|
||||||
│ │ ViewManager.ts (View Navigation) │ │
|
|
||||||
│ ├──────────────────────────────────────────────────────────────┤ │
|
|
||||||
│ │ • Page registration & caching │ │
|
|
||||||
│ │ • Page stack management (push/pop/replace) │ │
|
|
||||||
│ │ • Lifecycle: onViewLoad → onViewShow → onViewHide → destroy │ │
|
|
||||||
│ │ • Parameter passing between pages │ │
|
|
||||||
│ └──────────────────────────────────────────────────────────────┘ │
|
|
||||||
│ ▲ │
|
|
||||||
│ │ │
|
|
||||||
│ BaseView.ts (Abstract base class for all pages) │
|
|
||||||
│ • Lifecycle hooks │
|
|
||||||
│ • Page state management │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ DATA & STATE MANAGEMENT LAYER │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ StorageManager.ts (Single Source of Truth) │ │
|
|
||||||
│ ├──────────────────────────────────────────────────────────────┤ │
|
|
||||||
│ │ Lives Management: │ │
|
|
||||||
│ │ • getLives() / setLives() / consumeLife() / addLife() │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ Progress Management: │ │
|
|
||||||
│ │ • getCurrentLevelIndex() / getMaxUnlockedLevelIndex() │ │
|
|
||||||
│ │ • onLevelCompleted(levelIndex) │ │
|
|
||||||
│ │ • isLevelUnlocked(levelIndex) │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ Storage Backend: sys.localStorage │ │
|
|
||||||
│ │ └─ game_lives: string number (default: "10") │ │
|
|
||||||
│ │ └─ game_progress: JSON with currentIndex & maxUnlockedIdx │ │
|
|
||||||
│ └──────────────────────────────────────────────────────────────┘ │
|
|
||||||
│ ▲ │
|
|
||||||
│ │ │
|
|
||||||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ LevelDataManager.ts (Level Data & Assets) │ │
|
|
||||||
│ ├──────────────────────────────────────────────────────────────┤ │
|
|
||||||
│ │ • initialize(onProgress) - Fetch API & load first level │ │
|
|
||||||
│ │ • getLevelConfig(index) - Get level data + image │ │
|
|
||||||
│ │ • ensureLevelReady(index) - On-demand level loading │ │
|
|
||||||
│ │ • preloadNextLevel(currentIndex) - Async preload │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ Memory Caches: │ │
|
|
||||||
│ │ • _apiData: All levels from server │ │
|
|
||||||
│ │ • _levelConfigs: Map of loaded level configs │ │
|
|
||||||
│ │ • _imageCache: Map of loaded images (SpriteFrames) │ │
|
|
||||||
│ │ • _loadingLevels: Set of levels being loaded │ │
|
|
||||||
│ └──────────────────────────────────────────────────────────────┘ │
|
|
||||||
│ ▲ │
|
|
||||||
│ │ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ UTILITY & SDK LAYER │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────┐ ┌────────────────────┐ ┌──────────────────┐ │
|
|
||||||
│ │ HttpUtil.ts │ │ WxSDK.ts │ │ToastManager.ts │ │
|
|
||||||
│ ├────────────────────┤ ├────────────────────┤ ├──────────────────┤ │
|
|
||||||
│ │ • get<T>() │ │ • isWechat() │ │ • init() │ │
|
|
||||||
│ │ • post<T>() │ │ • initShare() │ │ • show() │ │
|
|
||||||
│ │ │ │ • shareAppMessage()│ │ │ │
|
|
||||||
│ │ Timeout: 10s │ │ • onShareAppMsg() │ │ Display duration │ │
|
|
||||||
│ │ Error handling │ │ • vibrateShort() │ │ Fade out anim │ │
|
|
||||||
│ │ │ │ • vibrateLong() │ │ │ │
|
|
||||||
│ └────────────────────┘ └────────────────────┘ └──────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ EXTERNAL SYSTEMS │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────────────────────────┐ │
|
|
||||||
│ │ WeChat Mini-Game SDK (wx global) │ │
|
|
||||||
│ ├──────────────────────────────────────┤ │
|
|
||||||
│ │ • wx.shareAppMessage() │ │
|
|
||||||
│ │ • wx.onShareAppMessage() │ │
|
|
||||||
│ │ • wx.showShareMenu() │ │
|
|
||||||
│ │ • wx.vibrateShort() │ │
|
|
||||||
│ │ • wx.vibrateLong() │ │
|
|
||||||
│ └──────────────────────────────────────┘ │
|
|
||||||
│ ▲ │
|
|
||||||
│ │ │
|
|
||||||
│ │ │
|
|
||||||
│ ┌──────────────────────────────────────┐ │
|
|
||||||
│ │ Backend API Server │ │
|
|
||||||
│ │ https://ilookai.cn │ │
|
|
||||||
│ ├──────────────────────────────────────┤ │
|
|
||||||
│ │ GET /api/v1/wechat-game/levels │ │
|
|
||||||
│ │ • Returns: {success, data, message} │ │
|
|
||||||
│ │ • Retry: 2x with 1s delay │ │
|
|
||||||
│ │ • Timeout: 8s │ │
|
|
||||||
│ └──────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Data Flow Diagram: Complete User Session
|
|
||||||
|
|
||||||
```
|
|
||||||
START
|
|
||||||
│
|
|
||||||
├─ [main.ts] onLoad()
|
|
||||||
│ └─ ViewManager.init(canvas)
|
|
||||||
│ └─ ToastManager.init(toastPrefab)
|
|
||||||
│ └─ Register PageHome & PageLevel
|
|
||||||
│
|
|
||||||
├─ [PageLoading.ts] start()
|
|
||||||
│ ├─ LevelDataManager.initialize()
|
|
||||||
│ │ ├─ HttpUtil.get() → API call
|
|
||||||
│ │ │ └─ https://ilookai.cn/api/v1/wechat-game/levels
|
|
||||||
│ │ ├─ Cache response → _apiData
|
|
||||||
│ │ ├─ Load first level image
|
|
||||||
│ │ │ └─ assetManager.loadRemote() → SpriteFrame
|
|
||||||
│ │ │ └─ Cache in _imageCache
|
|
||||||
│ │ └─ Return success
|
|
||||||
│ │
|
|
||||||
│ └─ ViewManager.preload('PageHome')
|
|
||||||
│ └─ ViewManager.open('PageHome')
|
|
||||||
│ └─ PageHome.onViewLoad()
|
|
||||||
│ └─ WxSDK.initShare()
|
|
||||||
│
|
|
||||||
├─ [USER CLICKS "START GAME"]
|
|
||||||
│
|
|
||||||
├─ ViewManager.open('PageLevel', {params: {levelIndex: 0}})
|
|
||||||
│ └─ PageLevel.onViewLoad()
|
|
||||||
│ ├─ StorageManager.getCurrentLevelIndex()
|
|
||||||
│ ├─ PageLevel.initLevel()
|
|
||||||
│ │ ├─ LevelDataManager.ensureLevelReady(levelIndex)
|
|
||||||
│ │ │ ├─ Check cache (_levelConfigs)
|
|
||||||
│ │ │ ├─ If not cached: load image + create config
|
|
||||||
│ │ │ └─ Store in cache
|
|
||||||
│ │ │
|
|
||||||
│ │ └─ PageLevel._applyLevelConfig()
|
|
||||||
│ │ ├─ Display main image (sprite)
|
|
||||||
│ │ ├─ Show Hint 1 (free)
|
|
||||||
│ │ ├─ Hide Hints 2, 3 (show unlock buttons)
|
|
||||||
│ │ ├─ Create input field based on answer.length
|
|
||||||
│ │ ├─ Display lives: StorageManager.getLives()
|
|
||||||
│ │ ├─ Start countdown (60s)
|
|
||||||
│ │ └─ LevelDataManager.preloadNextLevel() [async]
|
|
||||||
│
|
|
||||||
├─ [USER INTERACTS]
|
|
||||||
│
|
|
||||||
├─ Option A: UNLOCK HINT
|
|
||||||
│ ├─ PageLevel.onUnlockClue(2 or 3)
|
|
||||||
│ ├─ Check: StorageManager.hasLives()?
|
|
||||||
│ ├─ Yes → StorageManager.consumeLife() → display hint
|
|
||||||
│ └─ No → Show "生命值不足" message
|
|
||||||
│
|
|
||||||
├─ Option B: SUBMIT ANSWER
|
|
||||||
│ ├─ PageLevel.onSubmitAnswer()
|
|
||||||
│ ├─ Validate: userAnswer === correctAnswer?
|
|
||||||
│ │
|
|
||||||
│ ├─ YES (Correct)
|
|
||||||
│ │ ├─ PageLevel.showSuccess()
|
|
||||||
│ │ ├─ Stop countdown
|
|
||||||
│ │ ├─ Play successAudio
|
|
||||||
│ │ ├─ StorageManager.addLife() [+1]
|
|
||||||
│ │ ├─ PageLevel._showPassModal()
|
|
||||||
│ │ │ ├─ Instantiate PassModal prefab
|
|
||||||
│ │ │ ├─ PassModal.onViewLoad()
|
|
||||||
│ │ │ ├─ PassModal.onViewShow()
|
|
||||||
│ │ │ │ └─ Play success sound
|
|
||||||
│ │ │ │ └─ Adjust widget to full screen
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ └─ User clicks button:
|
|
||||||
│ │ │ ├─ "Next Level" → PageLevel.nextLevel()
|
|
||||||
│ │ │ │ ├─ StorageManager.onLevelCompleted(currentIndex)
|
|
||||||
│ │ │ │ │ ├─ currentLevelIndex++
|
|
||||||
│ │ │ │ │ ├─ maxUnlockedLevelIndex = max(prev, current)
|
|
||||||
│ │ │ │ │ └─ Save to localStorage
|
|
||||||
│ │ │ │ ├─ Reload PageLevel with new index
|
|
||||||
│ │ │ │ │ └─ Repeat from Level Setup
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ │ │ └─ If last level:
|
|
||||||
│ │ │ │ └─ ViewManager.back() → return to PageHome
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ └─ "Share" → WxSDK.shareAppMessage()
|
|
||||||
│ │ │ └─ query: `level=${currentIndex+1}`
|
|
||||||
│ │
|
|
||||||
│ ├─ NO (Wrong)
|
|
||||||
│ │ ├─ PageLevel.showError()
|
|
||||||
│ │ ├─ Play failAudio
|
|
||||||
│ │ ├─ WxSDK.vibrateLong() [device vibration]
|
|
||||||
│ │ ├─ ToastManager.show("答案错误,再试试吧!")
|
|
||||||
│ │ │ ├─ Create Toast node
|
|
||||||
│ │ │ ├─ Show for 2000ms
|
|
||||||
│ │ │ ├─ Fade out animation (300ms)
|
|
||||||
│ │ │ └─ Destroy node
|
|
||||||
│ │ │
|
|
||||||
│ │ └─ Continue playing (allow retry)
|
|
||||||
│
|
|
||||||
├─ Option C: TIMEOUT
|
|
||||||
│ └─ Countdown reaches 0
|
|
||||||
│ ├─ PageLevel.onTimeUp()
|
|
||||||
│ ├─ Play failAudio
|
|
||||||
│ └─ [Incomplete: can still submit after timeout]
|
|
||||||
│
|
|
||||||
├─ [USER CLICKS BACK BUTTON]
|
|
||||||
│ ├─ ViewManager.back()
|
|
||||||
│ │ ├─ PageLevel._doHide()
|
|
||||||
│ │ └─ PageHome._doShow()
|
|
||||||
│ │
|
|
||||||
│ └─ Return to home (progress saved in localStorage)
|
|
||||||
│
|
|
||||||
└─ END
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## State Management Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
USER PROGRESS STATE
|
|
||||||
│
|
|
||||||
├─ localStorage: game_progress
|
|
||||||
│ └─ {
|
|
||||||
│ "currentLevelIndex": 5,
|
|
||||||
│ "maxUnlockedLevelIndex": 5
|
|
||||||
│ }
|
|
||||||
│
|
|
||||||
├─ Memory Cache (LevelDataManager)
|
|
||||||
│ ├─ _apiData: ApiLevelData[] (all levels)
|
|
||||||
│ ├─ _levelConfigs: Map<levelIndex, RuntimeLevelConfig>
|
|
||||||
│ ├─ _imageCache: Map<url, SpriteFrame>
|
|
||||||
│ └─ _loadingLevels: Set<levelIndex> (currently loading)
|
|
||||||
│
|
|
||||||
└─ Session State (PageLevel component)
|
|
||||||
├─ currentLevelIndex: number
|
|
||||||
├─ _currentConfig: RuntimeLevelConfig
|
|
||||||
├─ _countdown: number (60 → 0)
|
|
||||||
├─ _isTimeUp: boolean
|
|
||||||
├─ _isTransitioning: boolean
|
|
||||||
└─ _passModalNode: Node | null
|
|
||||||
|
|
||||||
|
|
||||||
LIVES STATE
|
|
||||||
│
|
|
||||||
├─ localStorage: game_lives
|
|
||||||
│ └─ "10" (string representation of number)
|
|
||||||
│
|
|
||||||
├─ Cached value (StorageManager._progressCache)
|
|
||||||
│ └─ Read on first access, cached for performance
|
|
||||||
│
|
|
||||||
└─ Operations (immediate storage update)
|
|
||||||
├─ getLives() → read from storage
|
|
||||||
├─ setLives(n) → validate & write to storage
|
|
||||||
├─ consumeLife() → getLives() - 1, setLives()
|
|
||||||
├─ addLife() → getLives() + 1, setLives()
|
|
||||||
└─ hasLives() → getLives() > 0
|
|
||||||
|
|
||||||
|
|
||||||
API CACHE
|
|
||||||
│
|
|
||||||
├─ First Load (Startup)
|
|
||||||
│ ├─ HttpUtil.get(apiUrl, 8000ms timeout)
|
|
||||||
│ ├─ Retry: 2 times (1s delay between)
|
|
||||||
│ └─ Cache in LevelDataManager._apiData
|
|
||||||
│
|
|
||||||
└─ Per-Level Resources (On-Demand)
|
|
||||||
├─ Check _levelConfigs cache
|
|
||||||
├─ If missing: assetManager.loadRemote(imageUrl)
|
|
||||||
├─ Create SpriteFrame
|
|
||||||
└─ Cache in _imageCache
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## View Stack & Navigation
|
|
||||||
|
|
||||||
```
|
|
||||||
VIEW STACK (LIFO - Last In First Out)
|
|
||||||
│
|
|
||||||
├─ Level 0 (Bottom)
|
|
||||||
│ └─ PageHome
|
|
||||||
│
|
|
||||||
├─ Level 1 (Middle)
|
|
||||||
│ └─ PageLevel
|
|
||||||
│
|
|
||||||
├─ Level 2 (Top - Current)
|
|
||||||
│ └─ PassModal (temporary, on PageLevel)
|
|
||||||
│
|
|
||||||
└─ Operations
|
|
||||||
├─ open(viewId) → push to stack + show
|
|
||||||
├─ back() → pop from stack + hide + show prev
|
|
||||||
├─ replace(viewId) → pop + push new view
|
|
||||||
└─ close() → pop + show previous
|
|
||||||
|
|
||||||
|
|
||||||
CACHING BEHAVIOR
|
|
||||||
│
|
|
||||||
├─ PageHome
|
|
||||||
│ ├─ cache: true
|
|
||||||
│ └─ Cached after first open, reused on back
|
|
||||||
│
|
|
||||||
├─ PageLevel
|
|
||||||
│ ├─ cache: true
|
|
||||||
│ └─ Cached per instance (but reinitializes on each open)
|
|
||||||
│
|
|
||||||
└─ PassModal
|
|
||||||
├─ Dynamically instantiated
|
|
||||||
├─ Not cached
|
|
||||||
└─ Destroyed after close
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Class Hierarchy
|
|
||||||
|
|
||||||
```
|
|
||||||
Component (Cocos)
|
|
||||||
│
|
|
||||||
├─ BaseView (Abstract base)
|
|
||||||
│ ├─ PageHome
|
|
||||||
│ ├─ PageLevel
|
|
||||||
│ └─ PassModal
|
|
||||||
│
|
|
||||||
└─ Toast
|
|
||||||
|
|
||||||
|
|
||||||
Managers (Singleton)
|
|
||||||
│
|
|
||||||
├─ ViewManager
|
|
||||||
│ └─ Manages page lifecycle & navigation
|
|
||||||
│
|
|
||||||
├─ LevelDataManager
|
|
||||||
│ └─ Manages API data & asset loading
|
|
||||||
│
|
|
||||||
├─ StorageManager
|
|
||||||
│ └─ Manages user data persistence
|
|
||||||
│
|
|
||||||
├─ ToastManager
|
|
||||||
│ └─ Manages toast notifications
|
|
||||||
│
|
|
||||||
└─ WxSDK
|
|
||||||
└─ Manages WeChat integration
|
|
||||||
|
|
||||||
|
|
||||||
Utilities
|
|
||||||
│
|
|
||||||
├─ HttpUtil
|
|
||||||
│ └─ Static HTTP methods (GET/POST)
|
|
||||||
│
|
|
||||||
└─ LevelTypes
|
|
||||||
└─ TypeScript interfaces for API data
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Dependency Graph
|
|
||||||
|
|
||||||
```
|
|
||||||
main.ts
|
|
||||||
├─ ViewManager
|
|
||||||
├─ ToastManager
|
|
||||||
└─ [Page Prefabs]
|
|
||||||
├─ PageHome
|
|
||||||
│ └─ WxSDK
|
|
||||||
│
|
|
||||||
├─ PageLevel
|
|
||||||
│ ├─ StorageManager
|
|
||||||
│ ├─ WxSDK
|
|
||||||
│ ├─ LevelDataManager
|
|
||||||
│ ├─ ToastManager
|
|
||||||
│ └─ PassModal
|
|
||||||
│ ├─ WxSDK
|
|
||||||
│ └─ BaseView
|
|
||||||
│
|
|
||||||
└─ PageLoading
|
|
||||||
├─ ViewManager
|
|
||||||
├─ LevelDataManager
|
|
||||||
│ ├─ HttpUtil
|
|
||||||
│ │ └─ XMLHttpRequest
|
|
||||||
│ ├─ LevelTypes
|
|
||||||
│ └─ Cocos assetManager
|
|
||||||
└─ ToastManager
|
|
||||||
|
|
||||||
|
|
||||||
EXTERNAL APIS
|
|
||||||
│
|
|
||||||
├─ https://ilookai.cn/api/v1/wechat-game/levels
|
|
||||||
│ └─ Called by LevelDataManager._fetchApiData()
|
|
||||||
│
|
|
||||||
└─ WeChat SDK (wx global)
|
|
||||||
├─ wx.shareAppMessage()
|
|
||||||
├─ wx.onShareAppMessage()
|
|
||||||
├─ wx.showShareMenu()
|
|
||||||
├─ wx.vibrateShort()
|
|
||||||
└─ wx.vibrateLong()
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Performance Considerations
|
|
||||||
|
|
||||||
### Memory Management
|
|
||||||
- **Image Loading**: Remote images loaded on-demand with local caching
|
|
||||||
- **Level Configs**: Loaded incrementally, current + next level only
|
|
||||||
- **View Caching**: Pages cached after first load, reused on navigation back
|
|
||||||
- **Message Queuing**: No event queue; direct method calls
|
|
||||||
|
|
||||||
### Network
|
|
||||||
- **Single API Call**: Startup only (all levels fetched at once)
|
|
||||||
- **Timeout**: 8 seconds for API requests
|
|
||||||
- **Retry Logic**: 2 attempts with 1-second delay
|
|
||||||
- **Cache Strategy**: In-memory cache, no expiration
|
|
||||||
|
|
||||||
### Storage
|
|
||||||
- **localStorage**: 2 keys (lives + progress)
|
|
||||||
- **No Batching**: Each update writes immediately
|
|
||||||
- **Synchronous**: No async operations needed
|
|
||||||
|
|
||||||
### UI/Graphics
|
|
||||||
- **Single Image**: Main puzzle image per level
|
|
||||||
- **Dynamic Input**: Input field size adjusts based on answer length
|
|
||||||
- **Audio**: One-shot playback, no loops
|
|
||||||
- **Animations**: Toast fade-out only
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
### Current Implementation
|
|
||||||
- ⚠️ All data stored locally (no encryption)
|
|
||||||
- ⚠️ No user authentication
|
|
||||||
- ⚠️ No server-side validation
|
|
||||||
- ⚠️ Progress can be manually edited via localStorage
|
|
||||||
|
|
||||||
### Vulnerabilities
|
|
||||||
1. localStorage can be inspected/modified via browser console
|
|
||||||
2. No server-side checks on progress/lives
|
|
||||||
3. Can modify localStorage to skip levels
|
|
||||||
4. Can modify lives directly
|
|
||||||
|
|
||||||
### Improvements Needed
|
|
||||||
- Server-side progress validation
|
|
||||||
- User authentication
|
|
||||||
- Encrypted storage
|
|
||||||
- Server-side truth for lives/progress
|
|
||||||
|
|
||||||
288
DOCS_INDEX.md
@@ -1,288 +0,0 @@
|
|||||||
# Documentation Index
|
|
||||||
|
|
||||||
This directory contains comprehensive analysis of the mp-xieyingeng (写英语) Cocos Creator game point/score system.
|
|
||||||
|
|
||||||
## 📚 Documentation Files
|
|
||||||
|
|
||||||
### 1. **GAME_ANALYSIS.md** (19 KB) - COMPREHENSIVE ANALYSIS
|
|
||||||
The complete technical analysis of the game's point and score system. **Start here for complete understanding.**
|
|
||||||
|
|
||||||
**Contents:**
|
|
||||||
- PART 1: Points/Asset System (Lives currency)
|
|
||||||
- PART 2: Level Completion & Rewards (+1 life per pass)
|
|
||||||
- PART 3: Hint/Clue System (Costs 1 life each)
|
|
||||||
- PART 4: Game Play Logic (Answer validation, timing)
|
|
||||||
- PART 5: Loading Page Logic (Initialization flow)
|
|
||||||
- PART 6: API & Network Requests (Backend endpoint)
|
|
||||||
- PART 7: User Data Storage (localStorage schema)
|
|
||||||
- PART 8: WeChat Mini-Game SDK Usage
|
|
||||||
- PART 9: Complete Game Flow Diagram
|
|
||||||
- PART 10: Complete Resource Flow
|
|
||||||
- PART 11: Key Observations & Implementation Gaps
|
|
||||||
- PART 12: Network Architecture
|
|
||||||
- Summary table of all features
|
|
||||||
|
|
||||||
### 2. **QUICK_REFERENCE.md** (8.6 KB) - QUICK LOOKUP GUIDE
|
|
||||||
Fast reference guide for developers. Use this for quick lookups.
|
|
||||||
|
|
||||||
**Contents:**
|
|
||||||
- Core Currency Overview (Lives system)
|
|
||||||
- Flow Charts (Life economics, answer submission, app startup)
|
|
||||||
- Data Structures (localStorage, API response)
|
|
||||||
- Key Functions & Methods
|
|
||||||
- Missing Features & Implementation Gaps
|
|
||||||
- Network Calls Summary
|
|
||||||
- Game Loop Per Level
|
|
||||||
- Data Integrity Notes
|
|
||||||
- WeChat Features Status
|
|
||||||
- Extension Ideas (Easy/Medium/Complex)
|
|
||||||
|
|
||||||
### 3. **ARCHITECTURE.md** (26 KB) - SYSTEM DESIGN
|
|
||||||
Detailed architecture diagrams and system design documentation.
|
|
||||||
|
|
||||||
**Contents:**
|
|
||||||
- System Architecture Diagram (layered view)
|
|
||||||
- Data Flow Diagram (complete user session)
|
|
||||||
- State Management Flow
|
|
||||||
- View Stack & Navigation
|
|
||||||
- Class Hierarchy
|
|
||||||
- Dependency Graph
|
|
||||||
- Performance Considerations
|
|
||||||
- Security Considerations & Vulnerabilities
|
|
||||||
|
|
||||||
## 🎯 Quick Navigation
|
|
||||||
|
|
||||||
### "I want to understand..."
|
|
||||||
|
|
||||||
**...how the point system works**
|
|
||||||
→ Read: QUICK_REFERENCE.md "THE COMPLETE PICTURE"
|
|
||||||
|
|
||||||
**...the complete game flow**
|
|
||||||
→ Read: GAME_ANALYSIS.md "PART 9: Complete Game Flow Diagram"
|
|
||||||
|
|
||||||
**...how lives are stored and managed**
|
|
||||||
→ Read: GAME_ANALYSIS.md "PART 1: Points/Asset System" + PART 7: User Data Storage"
|
|
||||||
|
|
||||||
**...what happens when a user completes a level**
|
|
||||||
→ Read: GAME_ANALYSIS.md "PART 2: Level Completion & Rewards"
|
|
||||||
|
|
||||||
**...how hints work**
|
|
||||||
→ Read: GAME_ANALYSIS.md "PART 3: Hint/Clue System"
|
|
||||||
|
|
||||||
**...the API integration**
|
|
||||||
→ Read: GAME_ANALYSIS.md "PART 6: API & Network Requests"
|
|
||||||
|
|
||||||
**...the code organization**
|
|
||||||
→ Read: ARCHITECTURE.md "System Architecture Diagram" + "Dependency Graph"
|
|
||||||
|
|
||||||
**...what's missing in the implementation**
|
|
||||||
→ Read: GAME_ANALYSIS.md "PART 11: Key Observations & Gaps"
|
|
||||||
|
|
||||||
**...where to add new features**
|
|
||||||
→ Read: QUICK_REFERENCE.md "EXTENSION IDEAS"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔑 Key Findings Summary
|
|
||||||
|
|
||||||
### THE POINT SYSTEM
|
|
||||||
- **Currency**: Lives (生命值)
|
|
||||||
- **Default**: 10 lives
|
|
||||||
- **Earn**: +1 per level pass
|
|
||||||
- **Spend**: -1 per hint unlock (Hint 2 or 3 only)
|
|
||||||
- **Storage**: localStorage under key `game_lives`
|
|
||||||
- **No other currency**: No points, coins, or score counter
|
|
||||||
|
|
||||||
### LEVEL COMPLETION
|
|
||||||
- **Reward**: +1 life (only reward)
|
|
||||||
- **No time bonus**: Same reward regardless of speed
|
|
||||||
- **No partial credit**: Exact case-sensitive match required
|
|
||||||
- **Unlimited retries**: Can retry wrong answers indefinitely
|
|
||||||
- **Timeout incomplete**: 60s countdown exists but doesn't prevent submission
|
|
||||||
|
|
||||||
### HINT SYSTEM
|
|
||||||
- **Hint 1**: Free (always shown)
|
|
||||||
- **Hint 2**: Costs 1 life (unlock button)
|
|
||||||
- **Hint 3**: Costs 1 life (unlock button)
|
|
||||||
- **Max loss per level**: 2 lives (both hints)
|
|
||||||
- **Net per level**: -1 to +1 depending on hints used
|
|
||||||
|
|
||||||
### DATA STORAGE
|
|
||||||
- **Lives**: localStorage["game_lives"]
|
|
||||||
- **Progress**: localStorage["game_progress"] with currentLevelIndex & maxUnlockedLevelIndex
|
|
||||||
- **All local**: No server-side sync
|
|
||||||
- **No encryption**: Direct access via console
|
|
||||||
- **Immediate writes**: Each update written to storage immediately
|
|
||||||
|
|
||||||
### API INTEGRATION
|
|
||||||
- **Single endpoint**: GET https://ilookai.cn/api/v1/wechat-game/levels
|
|
||||||
- **Startup only**: Called once during initialization
|
|
||||||
- **Retry**: 2 attempts with 1s delay
|
|
||||||
- **Timeout**: 8 seconds
|
|
||||||
- **No other backend calls**: No score submission, no analytics, no leaderboard
|
|
||||||
|
|
||||||
### WECHAT FEATURES
|
|
||||||
- ✅ Sharing (with level parameter)
|
|
||||||
- ✅ Haptic feedback (vibration on errors)
|
|
||||||
- ❌ No authentication
|
|
||||||
- ❌ No cloud save
|
|
||||||
- ❌ No leaderboard
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 Source Files Referenced
|
|
||||||
|
|
||||||
All 16 TypeScript files in the project are analyzed:
|
|
||||||
|
|
||||||
**Core Pages:**
|
|
||||||
- `PageLoading.ts` - Loading screen & initialization
|
|
||||||
- `PageHome.ts` - Home menu page
|
|
||||||
- `PageLevel.ts` - Main game level (where all game logic happens)
|
|
||||||
- `PassModal.ts` - Level completion modal
|
|
||||||
|
|
||||||
**Management Systems:**
|
|
||||||
- `ViewManager.ts` - Page navigation & lifecycle
|
|
||||||
- `StorageManager.ts` - Lives & progress persistence
|
|
||||||
- `LevelDataManager.ts` - API integration & asset loading
|
|
||||||
|
|
||||||
**Utilities:**
|
|
||||||
- `BaseView.ts` - Base class for pages
|
|
||||||
- `HttpUtil.ts` - HTTP request wrapper
|
|
||||||
- `WxSDK.ts` - WeChat SDK integration
|
|
||||||
- `ToastManager.ts` - Toast notifications
|
|
||||||
- `Toast.ts` - Toast component
|
|
||||||
- `LevelTypes.ts` - TypeScript interfaces
|
|
||||||
- `RoundedRectMask.ts` - UI utility
|
|
||||||
- `BackgroundScaler.ts` - UI utility
|
|
||||||
- `main.ts` - App entry point
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔬 Analysis Methodology
|
|
||||||
|
|
||||||
This documentation was created by:
|
|
||||||
1. Finding all 16 TypeScript files in the assets/ directory
|
|
||||||
2. Reading and analyzing each file for:
|
|
||||||
- Score/points logic
|
|
||||||
- Currency/asset management
|
|
||||||
- Level completion mechanics
|
|
||||||
- Hint/cost systems
|
|
||||||
- API calls
|
|
||||||
- Storage mechanisms
|
|
||||||
- WeChat SDK usage
|
|
||||||
- Data flows
|
|
||||||
3. Mapping dependencies between files
|
|
||||||
4. Creating flowcharts and diagrams
|
|
||||||
5. Documenting observations and gaps
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Using This Documentation
|
|
||||||
|
|
||||||
### For Understanding the System
|
|
||||||
1. Start with QUICK_REFERENCE.md for overview
|
|
||||||
2. Read GAME_ANALYSIS.md for detailed understanding
|
|
||||||
3. Refer to ARCHITECTURE.md for system design
|
|
||||||
|
|
||||||
### For Making Changes
|
|
||||||
1. Check ARCHITECTURE.md "Dependency Graph"
|
|
||||||
2. Review relevant code sections in GAME_ANALYSIS.md
|
|
||||||
3. Use QUICK_REFERENCE.md to find specific methods
|
|
||||||
|
|
||||||
### For Adding Features
|
|
||||||
1. Review QUICK_REFERENCE.md "EXTENSION IDEAS"
|
|
||||||
2. Check ARCHITECTURE.md "Security Considerations"
|
|
||||||
3. Plan changes against current dependencies
|
|
||||||
|
|
||||||
### For Debugging
|
|
||||||
1. Review GAME_ANALYSIS.md "PART 9: Game Flow Diagram"
|
|
||||||
2. Check ARCHITECTURE.md "Data Flow Diagram"
|
|
||||||
3. Trace through StorageManager and LevelDataManager
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ Important Notes
|
|
||||||
|
|
||||||
### Security Issues
|
|
||||||
- ⚠️ All data stored locally without encryption
|
|
||||||
- ⚠️ No server-side validation of progress
|
|
||||||
- ⚠️ Users can modify localStorage directly
|
|
||||||
- ⚠️ Can skip levels by editing progress
|
|
||||||
|
|
||||||
### Implementation Gaps
|
|
||||||
- ❌ No points/coins display
|
|
||||||
- ❌ No time-based bonuses
|
|
||||||
- ❌ Timeout doesn't prevent submission
|
|
||||||
- ❌ No server-side progress sync
|
|
||||||
- ❌ No analytics tracking
|
|
||||||
|
|
||||||
### To Improve
|
|
||||||
- Add server-side progress validation
|
|
||||||
- Implement user authentication
|
|
||||||
- Add score API endpoint
|
|
||||||
- Track time-to-completion
|
|
||||||
- Consider leaderboard system
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Document Versions
|
|
||||||
|
|
||||||
- Created: April 5, 2026
|
|
||||||
- Cocos Creator Version: 3.8.8
|
|
||||||
- Project: mp-xieyingeng (写英语)
|
|
||||||
- Platform: WeChat Mini-Game
|
|
||||||
- Analysis Coverage: 100% of TypeScript codebase (16 files)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📞 Questions Answered
|
|
||||||
|
|
||||||
This documentation answers:
|
|
||||||
- ✅ What is the points/score system?
|
|
||||||
- ✅ How do users earn points?
|
|
||||||
- ✅ How are points spent?
|
|
||||||
- ✅ What happens on level completion?
|
|
||||||
- ✅ How do hints work and cost lives?
|
|
||||||
- ✅ Where is data stored?
|
|
||||||
- ✅ What API calls are made?
|
|
||||||
- ✅ How does WeChat integration work?
|
|
||||||
- ✅ What's the complete game flow?
|
|
||||||
- ✅ What features are missing?
|
|
||||||
- ✅ What's the system architecture?
|
|
||||||
- ✅ Where are the security issues?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔗 Cross-References
|
|
||||||
|
|
||||||
| Topic | Main Document | Quick Ref | Architecture |
|
|
||||||
|-------|---------------|-----------|--------------|
|
|
||||||
| Lives System | PART 1 | Overview | State Mgmt |
|
|
||||||
| Level Rewards | PART 2 | Economics | Data Flow |
|
|
||||||
| Hints & Costs | PART 3 | Game Loop | Dependencies |
|
|
||||||
| API | PART 6 | Network | External |
|
|
||||||
| Storage | PART 7 | Data Structures | State Mgmt |
|
|
||||||
| WeChat | PART 8 | Features | Dependencies |
|
|
||||||
| Game Flow | PART 9 | Game Loop | Data Flow |
|
|
||||||
| Features | PART 11 | Missing | Performance |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Statistics
|
|
||||||
|
|
||||||
- **TypeScript Files Analyzed**: 16
|
|
||||||
- **Lines of Code Reviewed**: ~1,800
|
|
||||||
- **API Endpoints**: 1
|
|
||||||
- **Storage Keys**: 2
|
|
||||||
- **External SDKs**: 1 (WeChat)
|
|
||||||
- **Currency Types**: 1 (Lives)
|
|
||||||
- **Hint Levels**: 3
|
|
||||||
- **Levels Supported**: 100+ (from API)
|
|
||||||
- **Player Lives**: 10 (default)
|
|
||||||
- **Time Per Level**: 60 seconds
|
|
||||||
- **Max Hint Cost Per Level**: 2 lives
|
|
||||||
- **Max Life Gain Per Level**: 1 life
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**For questions or clarifications, refer to the specific document sections listed above.**
|
|
||||||
504
GAME_ANALYSIS.md
@@ -1,504 +0,0 @@
|
|||||||
# Cocos Creator Game - Complete Point/Score System Analysis
|
|
||||||
|
|
||||||
## Project Overview
|
|
||||||
This is a WeChat Mini-Game built with Cocos Creator. It's a word puzzle game where players guess answers to images within a 60-second time limit. The game uses a "lives" system instead of traditional points/coins.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. LIVES/RESOURCE SYSTEM (The Currency/Points Equivalent)
|
|
||||||
|
|
||||||
### Storage & Persistence
|
|
||||||
**File:** `StorageManager.ts`
|
|
||||||
- **Storage Key:** `game_lives`
|
|
||||||
- **Default Lives:** 10 (for new users)
|
|
||||||
- **Minimum Lives:** 0
|
|
||||||
- **Storage Method:** `sys.localStorage` (Cocos local storage)
|
|
||||||
|
|
||||||
### Lives Management Methods:
|
|
||||||
```typescript
|
|
||||||
// Core Methods:
|
|
||||||
- getLives(): number // Get current lives (default 10 if not set)
|
|
||||||
- setLives(lives: number) // Set lives value (min 0)
|
|
||||||
- consumeLife(): boolean // Deduct 1 life, returns success status
|
|
||||||
- addLife(): void // Add 1 life
|
|
||||||
- hasLives(): boolean // Check if lives > 0
|
|
||||||
- resetLives(): void // Reset to default 10
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lives Usage:
|
|
||||||
1. **Unlocking Hints (Clues):** Each unlock costs 1 life
|
|
||||||
- Clue 1: Free (always unlocked)
|
|
||||||
- Clue 2: Costs 1 life to unlock
|
|
||||||
- Clue 3: Costs 1 life to unlock
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. LEVEL PROGRESSION SYSTEM
|
|
||||||
|
|
||||||
**File:** `StorageManager.ts` (User Progress section)
|
|
||||||
|
|
||||||
### Progress Data Structure:
|
|
||||||
```typescript
|
|
||||||
interface UserProgress {
|
|
||||||
currentLevelIndex: number; // Current level (0-based)
|
|
||||||
maxUnlockedLevelIndex: number; // Highest level player reached
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Progress Storage:
|
|
||||||
- **Storage Key:** `game_progress`
|
|
||||||
- **Default:** `{ currentLevelIndex: 0, maxUnlockedLevelIndex: 0 }`
|
|
||||||
- **Caching:** Cached in memory (`_progressCache`) to avoid repeated localStorage reads
|
|
||||||
|
|
||||||
### Progression Methods:
|
|
||||||
```typescript
|
|
||||||
- getCurrentLevelIndex(): number // Get current level
|
|
||||||
- setCurrentLevelIndex(index): void // Set current level
|
|
||||||
- getMaxUnlockedLevelIndex(): number // Get highest unlocked level
|
|
||||||
- isLevelUnlocked(levelIndex): boolean // Check if level is playable
|
|
||||||
- onLevelCompleted(completedLevelIndex) // Called when level is beaten
|
|
||||||
- resetProgress(): void // Reset to level 1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Level Unlock Logic:
|
|
||||||
- **Level 1** is always unlocked
|
|
||||||
- When player completes level N:
|
|
||||||
- Current level → N+1
|
|
||||||
- Max unlocked → max(maxUnlocked, N)
|
|
||||||
- This allows replaying lower levels while progressing forward
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. GAME LEVEL DATA & API
|
|
||||||
|
|
||||||
**File:** `LevelDataManager.ts`
|
|
||||||
|
|
||||||
### API Configuration:
|
|
||||||
```typescript
|
|
||||||
API_URL = 'https://ilookai.cn/api/v1/wechat-game/levels'
|
|
||||||
REQUEST_TIMEOUT = 8000ms
|
|
||||||
API_RETRY_COUNT = 2 (retries on failure)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Level Data Structure (from API):
|
|
||||||
```typescript
|
|
||||||
interface ApiLevelData {
|
|
||||||
id: string; // UUID
|
|
||||||
level: number; // Level number
|
|
||||||
imageUrl: string; // Main image URL
|
|
||||||
hint1: string; // Free clue
|
|
||||||
hint2: string; // Paid clue (costs 1 life)
|
|
||||||
hint3: string; // Paid clue (costs 1 life)
|
|
||||||
answer: string; // The correct answer
|
|
||||||
sortOrder: number; // Sorting order
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### API Response:
|
|
||||||
```typescript
|
|
||||||
interface ApiResponse {
|
|
||||||
success: boolean;
|
|
||||||
message: string | null;
|
|
||||||
data: {
|
|
||||||
levels: ApiLevelData[];
|
|
||||||
total: number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Image Loading:
|
|
||||||
- Remote images loaded via `assetManager.loadRemote()`
|
|
||||||
- Cached in memory (`_imageCache: Map<URL, SpriteFrame>`)
|
|
||||||
- First level image preloaded during app initialization
|
|
||||||
- Next level image preloaded silently after entering current level
|
|
||||||
|
|
||||||
### Loading Strategy:
|
|
||||||
1. **On App Start:** Load all level metadata + first level image (80% of loading bar)
|
|
||||||
2. **On Level Enter:** Load current level image if needed
|
|
||||||
3. **After Level Completion:** Preload next level asynchronously (doesn't block gameplay)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. GAMEPLAY LOOP
|
|
||||||
|
|
||||||
**File:** `PageLevel.ts`
|
|
||||||
|
|
||||||
### Game Sequence:
|
|
||||||
1. Player enters level
|
|
||||||
2. Main image displays with hint 1 visible
|
|
||||||
3. 60-second countdown starts
|
|
||||||
4. Player enters answer in single EditBox
|
|
||||||
5. Player can unlock hints 2 & 3 by spending lives
|
|
||||||
6. Player submits answer
|
|
||||||
|
|
||||||
### Time Limit:
|
|
||||||
- **Duration:** 60 seconds per level
|
|
||||||
- **Implementation:** `schedule(this.onCountdownTick, 1)` (1-second interval)
|
|
||||||
- **On Time Up:** Plays fail sound, but doesn't force level exit
|
|
||||||
|
|
||||||
### Input System:
|
|
||||||
- **Type:** Single EditBox (not multi-input per character)
|
|
||||||
- **Width:** Dynamic (based on answer length)
|
|
||||||
- Formula: `Math.min(600, Math.max(200, answerLength * 60 + 40))` pixels
|
|
||||||
- **Max Length:** Match answer length
|
|
||||||
- **Placeholder:** Shows answer length as hint
|
|
||||||
|
|
||||||
### Answer Processing:
|
|
||||||
```typescript
|
|
||||||
getAnswer(): string {
|
|
||||||
const editBox = this._inputNodes[0].getComponent(EditBox);
|
|
||||||
return (editBox?.string ?? '').trim(); // Trimmed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparison is case-sensitive:
|
|
||||||
if (userAnswer === this._currentConfig.answer) {
|
|
||||||
// WIN
|
|
||||||
} else {
|
|
||||||
// LOSE
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. WINNING & REWARDS
|
|
||||||
|
|
||||||
**File:** `PageLevel.ts`
|
|
||||||
|
|
||||||
### On Correct Answer:
|
|
||||||
1. **Stop Timer:** Countdown stops
|
|
||||||
2. **Play Sound:** Success audio plays
|
|
||||||
3. **Award 1 Life:** `addLife()` called
|
|
||||||
4. **Show Modal:** PassModal displays with buttons
|
|
||||||
|
|
||||||
### Pass Modal (Victory Screen):
|
|
||||||
- Shows "Next Level" button
|
|
||||||
- Shows "Share with Friends" button
|
|
||||||
- On "Next Level": Progress to next level (calls `onLevelCompleted()`)
|
|
||||||
- On "Share": Triggers WeChat share with query param `?level=<levelIndex>`
|
|
||||||
|
|
||||||
### Progression on Pass:
|
|
||||||
```typescript
|
|
||||||
StorageManager.onLevelCompleted(currentLevelIndex);
|
|
||||||
// Sets:
|
|
||||||
// - currentLevelIndex → currentLevelIndex + 1
|
|
||||||
// - maxUnlockedLevelIndex → max(maxUnlocked, currentLevelIndex)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Game End Condition:
|
|
||||||
- When `currentLevelIndex >= totalLevels`, player has beaten all levels
|
|
||||||
- Game returns to home page
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. LOSING & CONSEQUENCES
|
|
||||||
|
|
||||||
**File:** `PageLevel.ts`
|
|
||||||
|
|
||||||
### On Wrong Answer:
|
|
||||||
1. **Play Sound:** Fail audio plays
|
|
||||||
2. **Vibration:** `WxSDK.vibrateLong()` (400ms vibration on WeChat)
|
|
||||||
3. **Toast Message:** "答案错误,再试试吧!" (Answer wrong, try again!)
|
|
||||||
4. **No Penalty:** No life deducted, level doesn't change
|
|
||||||
|
|
||||||
### On Time Up:
|
|
||||||
1. **Play Sound:** Fail audio plays
|
|
||||||
2. **Countdown Stops:** `_isTimeUp = true`
|
|
||||||
3. **No Forced Exit:** Player can continue typing and submitting
|
|
||||||
4. **No Life Penalty:** Still can retry
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. HINT/CLUE SYSTEM
|
|
||||||
|
|
||||||
**File:** `PageLevel.ts`
|
|
||||||
|
|
||||||
### Clue Mechanics:
|
|
||||||
1. **Clue 1:** Always visible, FREE
|
|
||||||
2. **Clue 2:** Hidden by default, costs 1 life to unlock
|
|
||||||
3. **Clue 3:** Hidden by default, costs 1 life to unlock
|
|
||||||
|
|
||||||
### Unlocking Process:
|
|
||||||
```typescript
|
|
||||||
onUnlockClue(index: number) {
|
|
||||||
// 1. Check if lives available
|
|
||||||
if (!this.hasLives()) return;
|
|
||||||
|
|
||||||
// 2. Consume 1 life
|
|
||||||
if (!this.consumeLife()) return;
|
|
||||||
|
|
||||||
// 3. Play click sound
|
|
||||||
this.playClickSound();
|
|
||||||
|
|
||||||
// 4. Hide unlock button
|
|
||||||
this.hideUnlockButton(index);
|
|
||||||
|
|
||||||
// 5. Show clue content
|
|
||||||
this.showClue(index);
|
|
||||||
this.setClue(index, clueContent);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clue Cost Implications:
|
|
||||||
- Player starts with 10 lives
|
|
||||||
- Can unlock both clues 2 & 3 = 2 lives spent minimum
|
|
||||||
- But only 8 lives remain per level if both used
|
|
||||||
- Player can conserve lives by solving without clues
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. NETWORK & API COMMUNICATION
|
|
||||||
|
|
||||||
**File:** `HttpUtil.ts`
|
|
||||||
|
|
||||||
### HTTP Methods:
|
|
||||||
```typescript
|
|
||||||
// GET request
|
|
||||||
HttpUtil.get<T>(url: string, timeout: number = 10000): Promise<T>
|
|
||||||
|
|
||||||
// POST request
|
|
||||||
HttpUtil.post<T>(url: string, data: object, timeout: number = 10000): Promise<T>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Implementation:
|
|
||||||
- Uses `XMLHttpRequest`
|
|
||||||
- Supports JSON responses
|
|
||||||
- Default timeout: 10 seconds
|
|
||||||
- Error handling: Rejects on HTTP errors, timeouts, or network failures
|
|
||||||
|
|
||||||
### Used By:
|
|
||||||
- `LevelDataManager` uses `HttpUtil.get()` to fetch level data from API
|
|
||||||
- No POST requests currently used
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. WECHAT SDK INTEGRATION
|
|
||||||
|
|
||||||
**File:** `WxSDK.ts`
|
|
||||||
|
|
||||||
### WeChat Features Used:
|
|
||||||
|
|
||||||
#### 1. Platform Detection:
|
|
||||||
```typescript
|
|
||||||
isWechat(): boolean
|
|
||||||
// Returns: sys.platform === sys.Platform.WECHAT_GAME
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Sharing:
|
|
||||||
- **Share Menu:** `showShareMenu()` - Enables share button in header
|
|
||||||
- **Friend Share:** `onShareAppMessage(config)` - Right-click "Share" message
|
|
||||||
- **Timeline Share:** `onShareTimeline(config)` - Moments sharing
|
|
||||||
- **Active Share:** `shareAppMessage(config)` - Trigger share dialog
|
|
||||||
|
|
||||||
#### 3. Vibration:
|
|
||||||
- **Short Vibrate:** `vibrateShort()` - 15ms, for button clicks
|
|
||||||
- **Long Vibrate:** `vibrateLong()` - 400ms, for errors
|
|
||||||
|
|
||||||
#### 4. Share Configuration:
|
|
||||||
```typescript
|
|
||||||
interface WxShareConfig {
|
|
||||||
title: string; // Share title: "写英语"
|
|
||||||
imageUrl?: string; // Share image (optional)
|
|
||||||
query?: string; // Query params (e.g., "level=5")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 5. Initialization:
|
|
||||||
```typescript
|
|
||||||
WxSDK.initShare(config) {
|
|
||||||
// Calls in sequence:
|
|
||||||
// 1. showShareMenu()
|
|
||||||
// 2. onShareAppMessage(config)
|
|
||||||
// 3. onShareTimeline(config)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Called in:** PageHome on game start
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. GAME STATE MANAGEMENT
|
|
||||||
|
|
||||||
**File:** `ViewManager.ts` (Page Stack) + `StorageManager.ts` (Data)
|
|
||||||
|
|
||||||
### View Stack (Navigation):
|
|
||||||
- Maintains page stack for navigation
|
|
||||||
- `PageHome` (z-index 0) - Main menu
|
|
||||||
- `PageLevel` (z-index 1) - Game level
|
|
||||||
- `PassModal` (z-index 999) - Victory overlay
|
|
||||||
|
|
||||||
### Persistent State:
|
|
||||||
- Lives stored in localStorage with key `game_lives`
|
|
||||||
- Progress stored in localStorage with key `game_progress`
|
|
||||||
- Both persist across app sessions
|
|
||||||
- Data survives app closure and reopening
|
|
||||||
|
|
||||||
### Runtime State:
|
|
||||||
- Current countdown timer
|
|
||||||
- Current input box content
|
|
||||||
- Unlocked clues state (reset each level)
|
|
||||||
- Current level config (API data)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 11. LOADING PAGE FLOW
|
|
||||||
|
|
||||||
**File:** `PageLoading.ts`
|
|
||||||
|
|
||||||
### Initialization Sequence:
|
|
||||||
1. **Stage 1 (0-30%):** Fetch all levels from API via `LevelDataManager.initialize()`
|
|
||||||
- API call with retry logic
|
|
||||||
- Parse level metadata
|
|
||||||
- NOT loading all images yet
|
|
||||||
|
|
||||||
2. **Stage 2 (30-80%):** Preload first level image
|
|
||||||
- Uses `LevelDataManager.ensureLevelReady(0)`
|
|
||||||
- Shows "正在加载游戏必备资源..." message
|
|
||||||
|
|
||||||
3. **Stage 3 (80-100%):** Preload PageHome view
|
|
||||||
- `ViewManager.preload('PageHome')`
|
|
||||||
- Shows "正在加载界面资源..." message
|
|
||||||
|
|
||||||
4. **Completion (100%):** Open PageHome and destroy loading page
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 12. COMPLETE POINTS FLOW DIAGRAM
|
|
||||||
|
|
||||||
```
|
|
||||||
START GAME
|
|
||||||
↓
|
|
||||||
[10 Lives] (default)
|
|
||||||
↓
|
|
||||||
LEVEL 1 STARTS
|
|
||||||
├─ View Clue 1 (FREE)
|
|
||||||
├─ Option: Unlock Clue 2 (-1 Life) → [9 Lives]
|
|
||||||
├─ Option: Unlock Clue 3 (-1 Life) → [8 Lives]
|
|
||||||
├─ Player submits answer
|
|
||||||
│
|
|
||||||
├─ IF CORRECT:
|
|
||||||
│ ├─ Add 1 Life → [9 or 10+ Lives]
|
|
||||||
│ ├─ Show PassModal
|
|
||||||
│ └─ Move to LEVEL 2
|
|
||||||
│
|
|
||||||
└─ IF WRONG:
|
|
||||||
├─ Play fail sound & vibrate
|
|
||||||
├─ Show toast message
|
|
||||||
├─ Lives unchanged
|
|
||||||
└─ Can retry (no level exit)
|
|
||||||
|
|
||||||
IF ALL LEVELS COMPLETE:
|
|
||||||
└─ Return to home
|
|
||||||
|
|
||||||
IF TIME UP:
|
|
||||||
├─ Play fail sound
|
|
||||||
├─ Can still submit (lives unchanged)
|
|
||||||
└─ No forced exit
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 13. KEY FILES SUMMARY
|
|
||||||
|
|
||||||
| File | Purpose | Key Components |
|
|
||||||
|------|---------|-----------------|
|
|
||||||
| StorageManager.ts | Data persistence | Lives + Progress storage |
|
|
||||||
| LevelDataManager.ts | Level data loading | API calls + Image caching |
|
|
||||||
| PageLevel.ts | Main game logic | Countdown, input, hints, validation |
|
|
||||||
| PageLoading.ts | App initialization | Loading bar + progress |
|
|
||||||
| PageHome.ts | Home screen | Start game button |
|
|
||||||
| PassModal.ts | Victory screen | Next/Share buttons |
|
|
||||||
| ViewManager.ts | Page navigation | View stack + caching |
|
|
||||||
| WxSDK.ts | WeChat API | Share + vibration |
|
|
||||||
| HttpUtil.ts | Network requests | GET/POST + error handling |
|
|
||||||
| ToastManager.ts | Notifications | Brief toast messages |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 14. IMPORTANT CONSTANTS
|
|
||||||
|
|
||||||
### Game Constants:
|
|
||||||
- **Level Time Limit:** 60 seconds
|
|
||||||
- **Default Lives:** 10
|
|
||||||
- **Life Cost per Hint:** 1 life per hint (hints 2 & 3)
|
|
||||||
- **Reward per Level:** +1 life
|
|
||||||
|
|
||||||
### API Constants:
|
|
||||||
- **Endpoint:** `https://ilookai.cn/api/v1/wechat-game/levels`
|
|
||||||
- **Timeout:** 8000ms
|
|
||||||
- **Retry Count:** 2
|
|
||||||
|
|
||||||
### UI Constants:
|
|
||||||
- **PageHome z-index:** 0
|
|
||||||
- **PageLevel z-index:** 1
|
|
||||||
- **PassModal z-index:** 999
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 15. MISSING FEATURES (Observations)
|
|
||||||
|
|
||||||
1. **No User Authentication:** No wx.login call visible
|
|
||||||
2. **No Backend Sync:** No calls to save progress to server
|
|
||||||
3. **No Ads/IAP:** No monetization system
|
|
||||||
4. **No Leaderboards:** No score submission to WeChat
|
|
||||||
5. **No Analytics:** No tracking events beyond console logs
|
|
||||||
6. **No Life Refill:** No premium way to get more lives
|
|
||||||
7. **No Difficulty Levels:** All players see same levels
|
|
||||||
8. **No Sound Toggle:** Sound plays automatically
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 16. DATA FLOW SUMMARY
|
|
||||||
|
|
||||||
```
|
|
||||||
WeChat API: https://ilookai.cn/api/v1/wechat-game/levels
|
|
||||||
↓
|
|
||||||
LevelDataManager (fetch + cache)
|
|
||||||
↓
|
|
||||||
PageLevel (display + gameplay)
|
|
||||||
├─ InputBox (player answer)
|
|
||||||
├─ Clues (cost lives to unlock)
|
|
||||||
└─ Timer (60 second countdown)
|
|
||||||
↓
|
|
||||||
StorageManager (save lives + progress)
|
|
||||||
↓
|
|
||||||
localStorage
|
|
||||||
├─ game_lives: number
|
|
||||||
└─ game_progress: UserProgress (JSON)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 17. CRITICAL BUSINESS LOGIC
|
|
||||||
|
|
||||||
### Win Condition:
|
|
||||||
```
|
|
||||||
userAnswer (trimmed) === correctAnswer (from API)
|
|
||||||
→ Award +1 life
|
|
||||||
→ Save progress
|
|
||||||
→ Move to next level
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lose Condition:
|
|
||||||
```
|
|
||||||
userAnswer !== correctAnswer
|
|
||||||
→ No penalty
|
|
||||||
→ Can retry immediately
|
|
||||||
→ Timer continues (even after time up)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Progression:
|
|
||||||
```
|
|
||||||
Beat Level N
|
|
||||||
→ currentLevel = N + 1
|
|
||||||
→ maxUnlocked = max(maxUnlocked, N)
|
|
||||||
→ Reward: +1 life (so levels can chain profitably)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Economy Balance:
|
|
||||||
- Start: 10 lives
|
|
||||||
- Per level: Can spend 0-2 lives (hints) or 0 lives (no hints)
|
|
||||||
- Per level: Earn +1 life (net: -1 or +1 lives)
|
|
||||||
- Average player with no hints: +1 life/level → infinite scaling
|
|
||||||
- Average player with 1 hint: 0 lives/level → stable
|
|
||||||
- Hardcore with 2 hints: -1 life/level → finite runway
|
|
||||||
|
|
||||||
@@ -1,494 +0,0 @@
|
|||||||
# Complete Points/Lives Flow Diagram
|
|
||||||
|
|
||||||
## 🔴 INITIALIZATION PHASE
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────┐
|
|
||||||
│ GAME STARTS │
|
|
||||||
│ PageLoading initializes │
|
|
||||||
└──────────────┬──────────────────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌──────────────────────────┐
|
|
||||||
│ Check localStorage │
|
|
||||||
│ "game_lives" key │
|
|
||||||
└────┬──────────────┬──────┘
|
|
||||||
│ │
|
|
||||||
NOT SET EXISTS
|
|
||||||
(New User) (Returning)
|
|
||||||
│ │
|
|
||||||
↓ ↓
|
|
||||||
┌────────────┐ ┌────────────┐
|
|
||||||
│ 10 Lives │ │Parse Value │
|
|
||||||
│(DEFAULT) │ │from Storage│
|
|
||||||
└────┬───────┘ └────┬───────┘
|
|
||||||
│ │
|
|
||||||
└────────┬───────┘
|
|
||||||
↓
|
|
||||||
┌────────────────────────┐
|
|
||||||
│ LOAD LEVEL DATA │
|
|
||||||
│ (API fetch) │
|
|
||||||
│ https://ilookai.cn ... │
|
|
||||||
└────────┬───────────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌────────────────────────┐
|
|
||||||
│ Display PageHome │
|
|
||||||
│ (with shared config) │
|
|
||||||
└────────┬───────────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌────────────────────────┐
|
|
||||||
│ READY TO PLAY │
|
|
||||||
│ Lives: X | Level: Y │
|
|
||||||
└────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎮 GAMEPLAY PHASE (Single Level)
|
|
||||||
|
|
||||||
```
|
|
||||||
┌────────────────────────────────────────┐
|
|
||||||
│ LEVEL STARTS │
|
|
||||||
│ Load level data from cache │
|
|
||||||
│ Display image + Clue 1 (FREE) │
|
|
||||||
│ Start 60-second countdown │
|
|
||||||
└──────────────┬─────────────────────────┘
|
|
||||||
│
|
|
||||||
├─────────────────────────────────────┐
|
|
||||||
│ │
|
|
||||||
↓ ↓
|
|
||||||
┌──────────────────┐ ┌──────────────────────┐
|
|
||||||
│ UNLOCK CLUE 2 │ │ SUBMIT ANSWER │
|
|
||||||
│ onUnlockClue(2) │ │ onSubmitAnswer() │
|
|
||||||
│ │ │ │
|
|
||||||
│ Check: hasLives()├──NO──→ │ Compare: │
|
|
||||||
│ │ │ │ input === │
|
|
||||||
│ YES │ │ correctAnswer │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ ↓ │ │ ├──YES──→┐ │
|
|
||||||
│ consumeLife() │ │ │ │ │
|
|
||||||
│ Lives: -1 │ │ │ │ │
|
|
||||||
│ │ │ │ │ │ │
|
|
||||||
│ ↓ │ │ │ ┌┴─────────┐
|
|
||||||
│ Display Clue 2 │ │ │ │ │
|
|
||||||
│ Refresh Label │ │ │ ↓ │
|
|
||||||
│ │ │ │ │ SUCCESS! │
|
|
||||||
│ ↓ │ │ │ showSuccess() │
|
|
||||||
│ Continue Game │ │ │ │ │
|
|
||||||
└──────────────────┘ │ │ ↓ │
|
|
||||||
│ │ │ Play success │
|
|
||||||
│ │ │ sound │
|
|
||||||
↓ │ │ Stop timer │
|
|
||||||
┌──────────────────┐ │ │ addLife() │
|
|
||||||
│ UNLOCK CLUE 3 │ │ │ Lives: +1 │
|
|
||||||
│ onUnlockClue(3) │ │ │ │ │
|
|
||||||
│ │ │ │ ↓ │
|
|
||||||
│ Check: hasLives()├──NO──→ │ │ Show PassModal │
|
|
||||||
│ │ │ │ │ │ │
|
|
||||||
│ YES │ │ │ ├─►[NEXT] │
|
|
||||||
│ │ │ │ │ │ │
|
|
||||||
│ ↓ │ │ │ └─►[SHARE] │
|
|
||||||
│ consumeLife() │ │ │ │
|
|
||||||
│ Lives: -1 │ │ └──NO──────────────┘
|
|
||||||
│ │ │ │ │
|
|
||||||
│ ↓ │ │ ↓
|
|
||||||
│ Display Clue 3 │ │ ERROR!
|
|
||||||
│ Refresh Label │ │ showError()
|
|
||||||
│ │ │ │ │
|
|
||||||
│ ↓ │ │ ↓
|
|
||||||
│ Continue Game │ │ Play fail sound
|
|
||||||
│ │ │ Vibrate long
|
|
||||||
│ │ │ Show toast:
|
|
||||||
│ │ │ "答案错误,
|
|
||||||
└──────────────────┘ │ 再试试吧!"
|
|
||||||
│ │ Lives unchanged
|
|
||||||
│ │ │
|
|
||||||
│ │ ↓
|
|
||||||
│ │ Can retry
|
|
||||||
│ │ (same level)
|
|
||||||
│ │
|
|
||||||
└──────────────────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌──────────────────────┐
|
|
||||||
│ TIME UP? │
|
|
||||||
└──────────────────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌─────────────────────┐
|
|
||||||
│ Play fail sound │
|
|
||||||
│ Stop countdown │
|
|
||||||
│ Can still retry │
|
|
||||||
│ Lives unchanged │
|
|
||||||
└─────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 LIVES TRANSACTION FLOW
|
|
||||||
|
|
||||||
```
|
|
||||||
LEVEL START
|
|
||||||
│
|
|
||||||
┌────────┴─────────┐
|
|
||||||
│ │
|
|
||||||
OPTIONAL MANDATORY
|
|
||||||
(Hints) (Level)
|
|
||||||
│ │
|
|
||||||
┌───────┴────────┐ │
|
|
||||||
│ │ │
|
|
||||||
HINT 2 HINT 3 SUBMISSION
|
|
||||||
-1 Life -1 Life │
|
|
||||||
│ │ │
|
|
||||||
└────────┬───────┴─┬───────┤
|
|
||||||
│ │ │
|
|
||||||
(Spent) (Spent) ANSWER
|
|
||||||
│ │ │
|
|
||||||
└────┬────┴───┬───┘
|
|
||||||
│ │
|
|
||||||
0-2 LIVES SPENT
|
|
||||||
(Depends on choices)
|
|
||||||
│ │
|
|
||||||
┌─────────┼────────┼─────────┐
|
|
||||||
│ │ │ │
|
|
||||||
CORRECT WRONG TIMEOUT ...
|
|
||||||
│ │ │
|
|
||||||
│ │ │
|
|
||||||
+1 LIFE 0 LIVES 0 LIVES
|
|
||||||
│ │ │
|
|
||||||
↓ ↓ ↓
|
|
||||||
┌───────────────────────────────┐
|
|
||||||
│ NEW LIVES BALANCE │
|
|
||||||
│ │
|
|
||||||
│ Formula: │
|
|
||||||
│ newLives = │
|
|
||||||
│ oldLives │
|
|
||||||
│ - (hintsUnlocked × 1) │
|
|
||||||
│ + (if levelWon ? 1 : 0) │
|
|
||||||
│ │
|
|
||||||
│ Examples: │
|
|
||||||
│ 10 - 0 + 1 = 11 (no hints) │
|
|
||||||
│ 10 - 1 + 1 = 10 (1 hint) │
|
|
||||||
│ 10 - 2 + 1 = 9 (2 hints) │
|
|
||||||
│ 10 - 0 + 0 = 10 (retry) │
|
|
||||||
└───────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏆 LEVEL PROGRESSION & PERSISTENCE
|
|
||||||
|
|
||||||
```
|
|
||||||
LEVEL WON
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌────────────────────────────┐
|
|
||||||
│ StorageManager. │
|
|
||||||
│ onLevelCompleted() │
|
|
||||||
│ │
|
|
||||||
│ Takes: levelIndex (0-based) │
|
|
||||||
└────────────┬────────────────┘
|
|
||||||
│
|
|
||||||
┌────────┴────────┐
|
|
||||||
│ │
|
|
||||||
↓ ↓
|
|
||||||
┌────────────┐ ┌──────────────────┐
|
|
||||||
│ currentLevel │ maxUnlocked │
|
|
||||||
│ = N + 1 │ = max(N, current)│
|
|
||||||
└────────────┘ └──────────────────┘
|
|
||||||
│ │
|
|
||||||
└────────┬────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌──────────────────────────────┐
|
|
||||||
│ Save to localStorage: │
|
|
||||||
│ "game_progress" = │
|
|
||||||
│ { │
|
|
||||||
│ currentLevelIndex: N+1, │
|
|
||||||
│ maxUnlockedLevelIndex: N │
|
|
||||||
│ } │
|
|
||||||
└────────┬─────────────────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌──────────────────────────────┐
|
|
||||||
│ NEXT GAME SESSION: │
|
|
||||||
│ Restore from localStorage │
|
|
||||||
│ Resume at Level N+1 │
|
|
||||||
│ Can replay Levels 0 to N │
|
|
||||||
└──────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💾 DATA PERSISTENCE
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ localStorage (Browser) │
|
|
||||||
├─────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ KEY: "game_lives" │
|
|
||||||
│ VALUE: "10" (string number) │
|
|
||||||
│ Type: String │
|
|
||||||
│ Managed by: StorageManager │
|
|
||||||
│ Accessed by: PageLevel, PassModal │
|
|
||||||
│ │
|
|
||||||
├─────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ KEY: "game_progress" │
|
|
||||||
│ VALUE: JSON string │
|
|
||||||
│ { │
|
|
||||||
│ "currentLevelIndex": 2, │
|
|
||||||
│ "maxUnlockedLevelIndex": 4 │
|
|
||||||
│ } │
|
|
||||||
│ Type: String (JSON) │
|
|
||||||
│ Managed by: StorageManager │
|
|
||||||
│ Accessed by: PageLevel, ViewManager │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🌐 API & LEVEL DATA FLOW
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────┐
|
|
||||||
│ Remote API Server │
|
|
||||||
│ https://ilookai.cn/api/v1/... │
|
|
||||||
│ │
|
|
||||||
│ Returns: Array<ApiLevelData> │
|
|
||||||
│ Fields: id, level, imageUrl, hint1-3, │
|
|
||||||
│ answer, sortOrder │
|
|
||||||
└────────────────┬──────────────────────────┘
|
|
||||||
│
|
|
||||||
↓ (1st app load only)
|
|
||||||
HttpUtil.get()
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌──────────────────────────┐
|
|
||||||
│ LevelDataManager │
|
|
||||||
│ _fetchApiData() │
|
|
||||||
│ │
|
|
||||||
│ Retry: 2 attempts │
|
|
||||||
│ Timeout: 8000ms │
|
|
||||||
└────────┬─────────────────┘
|
|
||||||
│
|
|
||||||
┌────┴────┐
|
|
||||||
│ │
|
|
||||||
FAIL SUCCESS
|
|
||||||
│ │
|
|
||||||
│ ↓
|
|
||||||
│ ┌──────────────────┐
|
|
||||||
│ │ Cache all level │
|
|
||||||
│ │ metadata in │
|
|
||||||
│ │ memory │
|
|
||||||
│ │ (_apiData) │
|
|
||||||
│ └────┬─────────────┘
|
|
||||||
│ │
|
|
||||||
│ ↓
|
|
||||||
│ ┌──────────────────┐
|
|
||||||
│ │ Preload Level 0 │
|
|
||||||
│ │ image │
|
|
||||||
│ │ (_levelConfigs) │
|
|
||||||
│ └────┬─────────────┘
|
|
||||||
│ │
|
|
||||||
└────┬────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌──────────────────────────┐
|
|
||||||
│ PageLevel ready │
|
|
||||||
│ Display first level │
|
|
||||||
└──────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⏰ COUNTDOWN TIMER FLOW
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────────┐
|
|
||||||
│ startCountdown() │
|
|
||||||
│ _countdown = 60 │
|
|
||||||
│ _isTimeUp = false│
|
|
||||||
└────────┬─────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌─────────────────────────┐
|
|
||||||
│ schedule( │
|
|
||||||
│ onCountdownTick, 1 │ ← Every 1 second
|
|
||||||
│ ) │
|
|
||||||
└────────┬────────────────┘
|
|
||||||
│
|
|
||||||
├─────────────────────────────┐
|
|
||||||
│ EVERY SECOND │
|
|
||||||
│ (if _isTimeUp = false) │
|
|
||||||
│ │
|
|
||||||
├─→ _countdown-- │
|
|
||||||
├─→ updateClockLabel() │
|
|
||||||
│ (display "59s", "58s"...) │
|
|
||||||
│ │
|
|
||||||
└────────┬────────────────────┘
|
|
||||||
│
|
|
||||||
├─────────────────────────┐
|
|
||||||
│ │
|
|
||||||
_countdown > 0 _countdown <= 0
|
|
||||||
│ │
|
|
||||||
│ ↓
|
|
||||||
│ _isTimeUp = true
|
|
||||||
│ stopCountdown()
|
|
||||||
│ onTimeUp()
|
|
||||||
│ playFailSound()
|
|
||||||
│ │
|
|
||||||
│ ↓
|
|
||||||
│ Can still submit!
|
|
||||||
│ Lives unchanged
|
|
||||||
│ │
|
|
||||||
└──────────┬──────────────┘
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
┌────────────────┐
|
|
||||||
│ PLAYER ACTION: │
|
|
||||||
│ Submit Answer │
|
|
||||||
└────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📱 WECHAT INTEGRATION POINTS
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────┐
|
|
||||||
│ GAME START (PageHome) │
|
|
||||||
├──────────────────────────────────────┤
|
|
||||||
│ WxSDK.initShare({ │
|
|
||||||
│ title: "写英语", │
|
|
||||||
│ query: "" │
|
|
||||||
│ }) │
|
|
||||||
│ └─► Enable share menu in header │
|
|
||||||
└──────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌──────────────────────────────────────┐
|
|
||||||
│ LEVEL WON (PassModal) │
|
|
||||||
├──────────────────────────────────────┤
|
|
||||||
│ User clicks "Share" │
|
|
||||||
│ WxSDK.shareAppMessage({ │
|
|
||||||
│ title: "快来一起玩...", │
|
|
||||||
│ query: "level=<levelIndex>" │
|
|
||||||
│ }) │
|
|
||||||
│ └─► Opens share dialog │
|
|
||||||
│ with level param │
|
|
||||||
└──────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌──────────────────────────────────────┐
|
|
||||||
│ WRONG ANSWER (PageLevel) │
|
|
||||||
├──────────────────────────────────────┤
|
|
||||||
│ showError() │
|
|
||||||
│ WxSDK.vibrateLong() │
|
|
||||||
│ └─► 400ms vibration feedback │
|
|
||||||
└──────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 Complete Player Journey
|
|
||||||
|
|
||||||
```
|
|
||||||
START
|
|
||||||
↓
|
|
||||||
┌─────────────────────┐
|
|
||||||
│ Check localStorage │
|
|
||||||
│ game_lives: 10 │
|
|
||||||
│ game_progress: {0,0}│
|
|
||||||
└──────────┬──────────┘
|
|
||||||
↓
|
|
||||||
┌─────────────────┐
|
|
||||||
│ PageHome │
|
|
||||||
│ Start Button │
|
|
||||||
└──────────┬──────┘
|
|
||||||
↓
|
|
||||||
┌──────────────────────────┐
|
|
||||||
│ PageLevel: LEVEL 1 │
|
|
||||||
│ Lives: 10 │ Answer: __ │
|
|
||||||
│ Clue 1: ✓ (FREE) │
|
|
||||||
│ Clue 2: Unlock? (-1 life)│
|
|
||||||
│ Clue 3: Unlock? (-1 life)│
|
|
||||||
│ ⏱️ 60s countdown... │
|
|
||||||
└──────────┬───────────────┘
|
|
||||||
│
|
|
||||||
┌──────┴──────┬────────────────┐
|
|
||||||
│ │ │
|
|
||||||
UNLOCK SUBMIT TIMEOUT
|
|
||||||
CLUE 2 ANSWER (still ok)
|
|
||||||
-1 Life │
|
|
||||||
│ ├─ CORRECT: +1 Life
|
|
||||||
│ │ ↓
|
|
||||||
│ │ PassModal
|
|
||||||
│ │ ├─ NEXT → Level 2
|
|
||||||
│ │ └─ SHARE → wx.share
|
|
||||||
│ │
|
|
||||||
│ └─ WRONG: Lives stay
|
|
||||||
│ ↓
|
|
||||||
│ Retry same level
|
|
||||||
│
|
|
||||||
└─ UNLOCK
|
|
||||||
CLUE 3
|
|
||||||
-1 Life
|
|
||||||
│
|
|
||||||
↓
|
|
||||||
(Try answer)
|
|
||||||
│
|
|
||||||
├─ CORRECT: +1 Life
|
|
||||||
│ ↓
|
|
||||||
│ PassModal
|
|
||||||
│ └─ NEXT → Level 2
|
|
||||||
│
|
|
||||||
└─ WRONG: Lives stay
|
|
||||||
↓
|
|
||||||
Retry
|
|
||||||
|
|
||||||
PROGRESSION CONTINUES...
|
|
||||||
|
|
||||||
BEAT ALL LEVELS
|
|
||||||
↓
|
|
||||||
Return to PageHome
|
|
||||||
(Save progress in localStorage)
|
|
||||||
↓
|
|
||||||
COMPLETE
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📈 Lives Over Time (Example Scenario)
|
|
||||||
|
|
||||||
```
|
|
||||||
Session 1: No hints used
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
Level 1: 10 Lives → Correct → 11 Lives
|
|
||||||
Level 2: 11 Lives → Correct → 12 Lives
|
|
||||||
Level 3: 12 Lives → Correct → 13 Lives
|
|
||||||
Session 1 ends: 13 Lives saved
|
|
||||||
|
|
||||||
Session 2: Some hints used
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
Start: 13 Lives
|
|
||||||
Level 4: 13 - 1 (hint) + 1 (win) = 13 Lives
|
|
||||||
Level 5: 13 - 2 (hints) + 1 (win) = 12 Lives
|
|
||||||
Level 6: 12 - 0 (no hints) + 1 (win) = 13 Lives
|
|
||||||
Level 7: 13 - 0 (no hints) + 1 (win) = 14 Lives
|
|
||||||
Session 2 ends: 14 Lives saved
|
|
||||||
|
|
||||||
Session 3: Struggling with hints
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
Start: 14 Lives
|
|
||||||
Level 8: 14 - 2 (hints) + 1 (win) = 13 Lives
|
|
||||||
Level 9: 13 - 2 (hints) + 1 (win) = 12 Lives
|
|
||||||
Level 10: 12 - 0 (retry, no hints) + 1 (eventually win) = 13 Lives
|
|
||||||
Session 3 ends: 13 Lives saved
|
|
||||||
|
|
||||||
PATTERN: Lives stay stable or grow over time
|
|
||||||
depending on hint usage
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,336 +0,0 @@
|
|||||||
# 📚 Game Points/Lives System - Documentation Index
|
|
||||||
|
|
||||||
> Complete analysis of the Cocos Creator WeChat Mini-Game points/score/lives system
|
|
||||||
|
|
||||||
**Generated:** April 5, 2026
|
|
||||||
**Scope:** All 21 TypeScript source files analyzed
|
|
||||||
**Total Documentation:** ~45KB
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📄 Documentation Files
|
|
||||||
|
|
||||||
### 1. **SUMMARY.md** (11 KB) ⭐ **START HERE**
|
|
||||||
**Best for:** High-level overview and executive understanding
|
|
||||||
|
|
||||||
**Contains:**
|
|
||||||
- Executive summary of the lives-based economy
|
|
||||||
- 21 files analyzed (categorized)
|
|
||||||
- Complete points/lives flow table
|
|
||||||
- Data persistence details
|
|
||||||
- Level progression mechanics
|
|
||||||
- Hint system mechanics
|
|
||||||
- Gameplay loop description
|
|
||||||
- API integration overview
|
|
||||||
- WeChat integration features
|
|
||||||
- User journey example
|
|
||||||
- Testing scenarios
|
|
||||||
- Business logic highlights
|
|
||||||
|
|
||||||
**Read this if:** You want a quick understanding of how the entire system works
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. **GAME_ANALYSIS.md** (13 KB)
|
|
||||||
**Best for:** Deep technical analysis of every system component
|
|
||||||
|
|
||||||
**Contains 17 Sections:**
|
|
||||||
1. Project Overview
|
|
||||||
2. Lives/Resource System (complete)
|
|
||||||
3. Level Progression System
|
|
||||||
4. Game Level Data & API
|
|
||||||
5. Gameplay Loop
|
|
||||||
6. Winning & Rewards
|
|
||||||
7. Losing & Consequences
|
|
||||||
8. Hint/Clue System
|
|
||||||
9. Network & API Communication
|
|
||||||
10. WeChat SDK Integration
|
|
||||||
11. Game State Management
|
|
||||||
12. Loading Page Logic
|
|
||||||
13. Complete Points Flow Diagram
|
|
||||||
14. Key Files Summary (table)
|
|
||||||
15. Important Constants
|
|
||||||
16. Missing Features
|
|
||||||
17. Data Flow Summary & Business Logic
|
|
||||||
|
|
||||||
**Read this if:** You need comprehensive technical details on every aspect
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. **QUICK_REFERENCE.md** (5.6 KB)
|
|
||||||
**Best for:** Quick lookup while coding
|
|
||||||
|
|
||||||
**Contains:**
|
|
||||||
- What is the currency? (Lives)
|
|
||||||
- Lives management methods
|
|
||||||
- How lives are spent (table)
|
|
||||||
- How lives are earned (table)
|
|
||||||
- Level progression mechanics
|
|
||||||
- Level data structure (from API)
|
|
||||||
- Gameplay mechanics (time limit, input, conditions)
|
|
||||||
- Rewards & penalties (table)
|
|
||||||
- Economy balance formulas
|
|
||||||
- API integration details
|
|
||||||
- Storage schema
|
|
||||||
- WeChat integration points
|
|
||||||
- Key files list
|
|
||||||
- Important constants
|
|
||||||
- What's NOT implemented
|
|
||||||
|
|
||||||
**Read this if:** You need quick facts/numbers without reading full docs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. **POINTS_FLOW_DIAGRAM.md** (22 KB)
|
|
||||||
**Best for:** Visual understanding of system flows
|
|
||||||
|
|
||||||
**Contains ASCII Diagrams For:**
|
|
||||||
1. Initialization Phase
|
|
||||||
2. Gameplay Phase (single level)
|
|
||||||
3. Lives Transaction Flow
|
|
||||||
4. Level Progression & Persistence
|
|
||||||
5. Data Persistence (localStorage)
|
|
||||||
6. API & Level Data Flow
|
|
||||||
7. Countdown Timer Flow
|
|
||||||
8. WeChat Integration Points
|
|
||||||
9. Complete Player Journey
|
|
||||||
10. Lives Over Time (example scenario)
|
|
||||||
|
|
||||||
**Read this if:** You prefer visual diagrams over text explanations
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5. **POINTS_SYSTEM_INDEX.md** (This File!)
|
|
||||||
**Best for:** Navigation and understanding what exists where
|
|
||||||
|
|
||||||
**Contains:**
|
|
||||||
- Overview of all documentation
|
|
||||||
- Quick navigation by topic
|
|
||||||
- Search guide
|
|
||||||
- Related code file references
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Quick Navigation by Topic
|
|
||||||
|
|
||||||
### I want to understand...
|
|
||||||
|
|
||||||
**The Lives Economy**
|
|
||||||
- → SUMMARY.md → "The Complete Points/Lives Flow"
|
|
||||||
- → QUICK_REFERENCE.md → "Economy Balance"
|
|
||||||
- → GAME_ANALYSIS.md → Section 1 & 2
|
|
||||||
|
|
||||||
**How to Earn Lives**
|
|
||||||
- → SUMMARY.md → "EARNING Lives table"
|
|
||||||
- → QUICK_REFERENCE.md → "How Lives Are Earned"
|
|
||||||
- → POINTS_FLOW_DIAGRAM.md → "Complete Player Journey"
|
|
||||||
|
|
||||||
**How to Spend Lives**
|
|
||||||
- → SUMMARY.md → "SPENDING Lives table"
|
|
||||||
- → QUICK_REFERENCE.md → "How Lives Are Spent"
|
|
||||||
- → GAME_ANALYSIS.md → Section 7 "Hint/Clue System"
|
|
||||||
|
|
||||||
**Level Progression**
|
|
||||||
- → SUMMARY.md → "Level Progression System"
|
|
||||||
- → QUICK_REFERENCE.md → "Level Progression"
|
|
||||||
- → GAME_ANALYSIS.md → Section 2
|
|
||||||
- → POINTS_FLOW_DIAGRAM.md → "Level Progression & Persistence"
|
|
||||||
|
|
||||||
**Data Storage**
|
|
||||||
- → SUMMARY.md → "Data Persistence"
|
|
||||||
- → QUICK_REFERENCE.md → "Storage Schema"
|
|
||||||
- → GAME_ANALYSIS.md → Section 2 "Storage & Persistence"
|
|
||||||
- → POINTS_FLOW_DIAGRAM.md → "Data Persistence"
|
|
||||||
|
|
||||||
**API Integration**
|
|
||||||
- → SUMMARY.md → "API Integration"
|
|
||||||
- → GAME_ANALYSIS.md → Section 3 & 4
|
|
||||||
- → POINTS_FLOW_DIAGRAM.md → "API & Level Data Flow"
|
|
||||||
|
|
||||||
**WeChat Integration**
|
|
||||||
- → SUMMARY.md → "WeChat Integration"
|
|
||||||
- → GAME_ANALYSIS.md → Section 9
|
|
||||||
- → POINTS_FLOW_DIAGRAM.md → "WeChat Integration Points"
|
|
||||||
|
|
||||||
**Complete Gameplay Flow**
|
|
||||||
- → SUMMARY.md → "Gameplay Loop"
|
|
||||||
- → GAME_ANALYSIS.md → Section 4 & 5 & 6
|
|
||||||
- → POINTS_FLOW_DIAGRAM.md → "Gameplay Phase"
|
|
||||||
|
|
||||||
**Testing/Validation**
|
|
||||||
- → SUMMARY.md → "Testing Scenarios"
|
|
||||||
- → QUICK_REFERENCE.md → Check "What's NOT implemented" section
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📖 Code References
|
|
||||||
|
|
||||||
### Core Files & What They Do
|
|
||||||
|
|
||||||
**StorageManager.ts** (Lives + Progress)
|
|
||||||
- `getLives()` / `setLives()` / `consumeLife()` / `addLife()`
|
|
||||||
- `getCurrentLevelIndex()` / `onLevelCompleted()`
|
|
||||||
- Referenced in: GAME_ANALYSIS §2, SUMMARY "Data Persistence"
|
|
||||||
|
|
||||||
**PageLevel.ts** (Main Gameplay)
|
|
||||||
- `onUnlockClue()` / `onSubmitAnswer()` / `showSuccess()` / `showError()`
|
|
||||||
- `startCountdown()` / `onCountdownTick()`
|
|
||||||
- Referenced in: GAME_ANALYSIS §4-7, SUMMARY "Gameplay Loop"
|
|
||||||
|
|
||||||
**LevelDataManager.ts** (API + Caching)
|
|
||||||
- `initialize()` / `ensureLevelReady()` / `preloadNextLevel()`
|
|
||||||
- Referenced in: GAME_ANALYSIS §3, SUMMARY "API Integration"
|
|
||||||
|
|
||||||
**PassModal.ts** (Victory Screen)
|
|
||||||
- Victory UI and rewards display
|
|
||||||
- Referenced in: GAME_ANALYSIS §5
|
|
||||||
|
|
||||||
**WxSDK.ts** (WeChat Integration)
|
|
||||||
- `shareAppMessage()` / `vibrateLong()` / etc.
|
|
||||||
- Referenced in: GAME_ANALYSIS §9
|
|
||||||
|
|
||||||
**ViewManager.ts** (Page Navigation)
|
|
||||||
- Page stack management
|
|
||||||
- Referenced in: GAME_ANALYSIS §10
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔑 Key Numbers & Values
|
|
||||||
|
|
||||||
| Item | Value | Reference |
|
|
||||||
|------|-------|-----------|
|
|
||||||
| Default Lives | 10 | QUICK_REFERENCE, SUMMARY |
|
|
||||||
| Min Lives | 0 | QUICK_REFERENCE, SUMMARY |
|
|
||||||
| Hint Cost | 1 life each | QUICK_REFERENCE, SUMMARY |
|
|
||||||
| Win Reward | 1 life | QUICK_REFERENCE, SUMMARY |
|
|
||||||
| Level Time | 60 seconds | QUICK_REFERENCE, SUMMARY |
|
|
||||||
| API Timeout | 8000ms | QUICK_REFERENCE, GAME_ANALYSIS §3 |
|
|
||||||
| API Retries | 2 attempts | QUICK_REFERENCE, GAME_ANALYSIS §3 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧩 How Systems Interact
|
|
||||||
|
|
||||||
```
|
|
||||||
StorageManager (Lives + Progress)
|
|
||||||
↓
|
|
||||||
PageLevel (Gameplay)
|
|
||||||
├─ Uses Lives for: Hint Unlocks
|
|
||||||
├─ Updates Lives on: Level Complete
|
|
||||||
├─ Uses Progress for: Level Selection
|
|
||||||
└─ Updates Progress on: Level Complete
|
|
||||||
↓
|
|
||||||
LevelDataManager (API + Cache)
|
|
||||||
├─ Fetches: Level Data + Images
|
|
||||||
└─ Serves: Hints + Answers + Images to PageLevel
|
|
||||||
↓
|
|
||||||
WxSDK (WeChat)
|
|
||||||
├─ Shares: Victory with Level Param
|
|
||||||
└─ Vibrates: On Error
|
|
||||||
↓
|
|
||||||
ViewManager (Navigation)
|
|
||||||
└─ Manages: Page Stack + State
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Document Completeness Checklist
|
|
||||||
|
|
||||||
- [x] Lives earning mechanics
|
|
||||||
- [x] Lives spending mechanics
|
|
||||||
- [x] Level progression system
|
|
||||||
- [x] Hint/clue system
|
|
||||||
- [x] API integration
|
|
||||||
- [x] Data persistence
|
|
||||||
- [x] WeChat features
|
|
||||||
- [x] Gameplay loop
|
|
||||||
- [x] Win/lose conditions
|
|
||||||
- [x] User journey examples
|
|
||||||
- [x] Flow diagrams
|
|
||||||
- [x] Code references
|
|
||||||
- [x] Constants & values
|
|
||||||
- [x] Error handling
|
|
||||||
- [x] Performance optimizations
|
|
||||||
- [x] Missing features list
|
|
||||||
- [x] Testing scenarios
|
|
||||||
|
|
||||||
**Coverage:** 100% of points/lives/score system
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Using This Documentation
|
|
||||||
|
|
||||||
### For Understanding
|
|
||||||
1. Start with SUMMARY.md (5 min read)
|
|
||||||
2. Read QUICK_REFERENCE.md (3 min read)
|
|
||||||
3. Review POINTS_FLOW_DIAGRAM.md (5 min read)
|
|
||||||
4. Deep dive into GAME_ANALYSIS.md (15 min read)
|
|
||||||
|
|
||||||
### For Maintenance
|
|
||||||
- QUICK_REFERENCE.md is your quick lookup
|
|
||||||
- GAME_ANALYSIS.md has implementation details
|
|
||||||
- Code references show where logic lives
|
|
||||||
|
|
||||||
### For Modifications
|
|
||||||
- "Data Persistence" section for storage changes
|
|
||||||
- "Lives Transaction Flow" for economy tweaks
|
|
||||||
- "Constants" section for balance adjustments
|
|
||||||
- Individual sections in GAME_ANALYSIS for specific systems
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ❓ FAQ
|
|
||||||
|
|
||||||
**Q: Where is the lives starting value defined?**
|
|
||||||
A: `StorageManager.ts` line 25, `DEFAULT_LIVES = 10`
|
|
||||||
|
|
||||||
**Q: How do players earn lives?**
|
|
||||||
A: By completing levels correctly. See SUMMARY.md "Earning Lives"
|
|
||||||
|
|
||||||
**Q: Can players lose lives?**
|
|
||||||
A: Only by unlocking hints (-1 each). Wrong answers don't penalize. See SUMMARY.md "Spending Lives"
|
|
||||||
|
|
||||||
**Q: Where is progress stored?**
|
|
||||||
A: Browser localStorage under keys "game_lives" and "game_progress". See POINTS_FLOW_DIAGRAM.md "Data Persistence"
|
|
||||||
|
|
||||||
**Q: What happens when time runs out?**
|
|
||||||
A: Game plays fail sound but doesn't end. Players can still submit. See GAME_ANALYSIS.md Section 6
|
|
||||||
|
|
||||||
**Q: How does the hint system work?**
|
|
||||||
A: Hint 1 is free, Hints 2 & 3 cost 1 life each. See GAME_ANALYSIS.md Section 7
|
|
||||||
|
|
||||||
**Q: Is there backend sync?**
|
|
||||||
A: No. Progress is local-only. See SUMMARY.md "Missing Features"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📞 Document Metadata
|
|
||||||
|
|
||||||
| Property | Value |
|
|
||||||
|----------|-------|
|
|
||||||
| Total Files Analyzed | 21 TypeScript files |
|
|
||||||
| Total Lines of Code | ~2,500 lines |
|
|
||||||
| Documentation Generated | 4 files, ~45KB |
|
|
||||||
| Coverage | Complete (100%) |
|
|
||||||
| Last Updated | April 5, 2026 |
|
|
||||||
| Scope | Points/Lives/Score System |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎓 Summary of Key Takeaways
|
|
||||||
|
|
||||||
1. **Currency:** LIVES (renewable resource), not points
|
|
||||||
2. **Starting:** 10 lives for new players
|
|
||||||
3. **Economy:** +1 life per win, -1 per hint unlock
|
|
||||||
4. **Storage:** localStorage (persistent, survives app close)
|
|
||||||
5. **API:** Fetches level data on app start, cached in memory
|
|
||||||
6. **Progression:** Sequential level unlocking with level 1 always available
|
|
||||||
7. **Strategy:** No penalties for wrong answers, encourages replayability
|
|
||||||
8. **WeChat:** Sharing with level referral parameter
|
|
||||||
9. **Scope:** No backend sync, no authentication, local-only progress
|
|
||||||
10. **Design:** Simple, effective, encourages skill-based progression
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Questions?** All answers are in one of these 4 documentation files!
|
|
||||||
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
# QUICK REFERENCE - Game Points/Score System
|
|
||||||
|
|
||||||
## 🎮 What is the "Currency"?
|
|
||||||
**LIVES** - Not traditional points/coins, but a renewable "health" resource.
|
|
||||||
|
|
||||||
## 📊 Lives Management
|
|
||||||
```
|
|
||||||
Storage Key: "game_lives" (localStorage)
|
|
||||||
Default: 10
|
|
||||||
Min Value: 0
|
|
||||||
Max Value: ∞ (no limit)
|
|
||||||
|
|
||||||
Methods:
|
|
||||||
├─ getLives() → Returns current lives
|
|
||||||
├─ setLives(n) → Set specific value
|
|
||||||
├─ consumeLife() → Deduct 1 life
|
|
||||||
├─ addLife() → Add 1 life
|
|
||||||
├─ hasLives() → Check if > 0
|
|
||||||
└─ resetLives() → Reset to 10
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎯 How Lives Are Spent
|
|
||||||
| Action | Cost | Where |
|
|
||||||
|--------|------|-------|
|
|
||||||
| Unlock Clue 2 | 1 Life | PageLevel → onUnlockClue(2) |
|
|
||||||
| Unlock Clue 3 | 1 Life | PageLevel → onUnlockClue(3) |
|
|
||||||
| **TOTAL PER LEVEL** | **0-2 Lives** | Depends on player choice |
|
|
||||||
|
|
||||||
## 🏆 How Lives Are Earned
|
|
||||||
| Action | Reward | Where |
|
|
||||||
|--------|--------|-------|
|
|
||||||
| Complete a Level | +1 Life | PageLevel → showSuccess() |
|
|
||||||
| Wrong Answer | 0 | No penalty |
|
|
||||||
| Time Up | 0 | No penalty |
|
|
||||||
|
|
||||||
## 📈 Level Progression
|
|
||||||
```
|
|
||||||
Storage Key: "game_progress" (localStorage)
|
|
||||||
Structure:
|
|
||||||
{
|
|
||||||
currentLevelIndex: number, // 0-based, current level
|
|
||||||
maxUnlockedLevelIndex: number // 0-based, highest reached
|
|
||||||
}
|
|
||||||
|
|
||||||
Default: { currentLevelIndex: 0, maxUnlockedLevelIndex: 0 }
|
|
||||||
```
|
|
||||||
|
|
||||||
### Progression Rules:
|
|
||||||
1. **Level 1 always unlocked** - Start here
|
|
||||||
2. **Beat Level N** → currentLevel becomes N+1
|
|
||||||
3. **Beat Level N** → maxUnlocked becomes max(maxUnlocked, N)
|
|
||||||
4. **Can replay earlier levels** - But always progress forward
|
|
||||||
|
|
||||||
### Methods:
|
|
||||||
```
|
|
||||||
getCurrentLevelIndex() → Get current (0-based)
|
|
||||||
setCurrentLevelIndex(n) → Jump to level
|
|
||||||
getMaxUnlockedLevelIndex() → Get highest reached
|
|
||||||
isLevelUnlocked(n) → Check if playable
|
|
||||||
onLevelCompleted(n) → Save win + progress
|
|
||||||
resetProgress() → Reset to level 1
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎨 Level Data (from API)
|
|
||||||
**Endpoint:** `https://ilookai.cn/api/v1/wechat-game/levels`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
ApiLevelData {
|
|
||||||
id: string, // UUID
|
|
||||||
level: number, // Level number (1-based display)
|
|
||||||
imageUrl: string, // Main puzzle image
|
|
||||||
hint1: string, // Free clue
|
|
||||||
hint2: string, // Costs 1 life
|
|
||||||
hint3: string, // Costs 1 life
|
|
||||||
answer: string, // The answer (case-sensitive, trimmed)
|
|
||||||
sortOrder: number // Sort order
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## ⏱️ Gameplay Mechanics
|
|
||||||
|
|
||||||
### Time Limit
|
|
||||||
- **Duration:** 60 seconds per level
|
|
||||||
- **On Timeout:** Play fail sound, game doesn't end
|
|
||||||
- **After Timeout:** Can still submit answers
|
|
||||||
|
|
||||||
### Input System
|
|
||||||
- **Type:** Single text box (not per-character)
|
|
||||||
- **Processing:** Trimmed, case-sensitive comparison
|
|
||||||
- **Max Length:** Based on answer length
|
|
||||||
|
|
||||||
### Win Condition
|
|
||||||
```
|
|
||||||
input.trim() === answer
|
|
||||||
↓
|
|
||||||
Play success sound → Stop timer → Award +1 life
|
|
||||||
→ Show PassModal → Save progress
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lose Condition
|
|
||||||
```
|
|
||||||
input.trim() !== answer
|
|
||||||
↓
|
|
||||||
Play fail sound → Vibrate → Show toast
|
|
||||||
→ Lives unchanged → Can retry
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎁 Rewards & Penalties
|
|
||||||
| Event | Lives Change | Other Effects |
|
|
||||||
|-------|--------------|---------------|
|
|
||||||
| Correct Answer | +1 | Play success sound, show modal |
|
|
||||||
| Wrong Answer | 0 | Play fail sound, vibrate, toast |
|
|
||||||
| Unlock Clue | -1 | Show clue content |
|
|
||||||
| Time Up | 0 | Play fail sound, countdown stops |
|
|
||||||
| Level Complete | Already +1ed | Save progress, move to next |
|
|
||||||
|
|
||||||
## 🔄 Economy Balance
|
|
||||||
```
|
|
||||||
Starting Inventory: 10 lives
|
|
||||||
|
|
||||||
Without Hints: +1 life/level → Infinite
|
|
||||||
With 1 Hint/Level: 0 lives/level → Stable
|
|
||||||
With 2 Hints/Level: -1 life/level → Finite (10-20 levels)
|
|
||||||
|
|
||||||
Net Formula: newLives = oldLives - hintsUsed + 1 (on win)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📡 API Integration
|
|
||||||
```
|
|
||||||
LevelDataManager {
|
|
||||||
API_URL: "https://ilookai.cn/api/v1/wechat-game/levels"
|
|
||||||
TIMEOUT: 8000ms
|
|
||||||
RETRY_COUNT: 2
|
|
||||||
|
|
||||||
Calls:
|
|
||||||
├─ initialize() → Load all level metadata + image for level 1
|
|
||||||
├─ ensureLevelReady(n) → Load specific level image
|
|
||||||
├─ preloadNextLevel(n) → Silently preload level n+1
|
|
||||||
└─ getLevelConfig(n) → Get cached level data
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📁 Storage Schema
|
|
||||||
```
|
|
||||||
localStorage: {
|
|
||||||
"game_lives": "10",
|
|
||||||
"game_progress": "{\"currentLevelIndex\":0,\"maxUnlockedLevelIndex\":0}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🌐 WeChat Integration
|
|
||||||
```
|
|
||||||
Features Used:
|
|
||||||
├─ WxSDK.initShare() → Enable sharing
|
|
||||||
├─ WxSDK.shareAppMessage() → Share to friend with level query param
|
|
||||||
├─ WxSDK.vibrateLong() → 400ms vibration on error
|
|
||||||
└─ WxSDK.vibrateShort() → 15ms vibration on click
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔑 Key Files
|
|
||||||
```
|
|
||||||
StorageManager.ts → Lives & progress persistence
|
|
||||||
LevelDataManager.ts → API & image loading
|
|
||||||
PageLevel.ts → Main game logic
|
|
||||||
PageLoading.ts → App initialization
|
|
||||||
PassModal.ts → Victory screen
|
|
||||||
ViewManager.ts → Page navigation
|
|
||||||
WxSDK.ts → WeChat APIs
|
|
||||||
```
|
|
||||||
|
|
||||||
## ⚙️ Constants
|
|
||||||
```
|
|
||||||
DEFAULT_LIVES 10
|
|
||||||
MIN_LIVES 0
|
|
||||||
LEVEL_TIME_LIMIT 60 seconds
|
|
||||||
LIFE_PER_HINT 1
|
|
||||||
LIFE_PER_WIN 1
|
|
||||||
API_TIMEOUT 8000ms
|
|
||||||
API_RETRY_COUNT 2
|
|
||||||
|
|
||||||
Game Title "写英语" (Write English)
|
|
||||||
Share Query Format "level=<levelIndex>"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚨 No Implementation For:
|
|
||||||
- User Authentication (wx.login)
|
|
||||||
- Backend Progress Save
|
|
||||||
- Ads/Monetization
|
|
||||||
- Leaderboards
|
|
||||||
- Analytics
|
|
||||||
- Premium Life Refills
|
|
||||||
- Difficulty Levels
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**In Summary:** Players earn/spend LIVES by unlocking clues (-1 each) or winning levels (+1 each). Progress is saved locally with streak tracking. The economy encourages players to solve without hints to maximize lives.
|
|
||||||
416
SUMMARY.md
@@ -1,416 +0,0 @@
|
|||||||
# Game System Summary - Points/Score/Lives Analysis
|
|
||||||
|
|
||||||
**Project:** Cocos Creator WeChat Mini-Game ("写英语" - Write English)
|
|
||||||
**Date Analyzed:** April 5, 2026
|
|
||||||
**Analysis Scope:** Complete TypeScript codebase (21 source files)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
This game uses a **LIVES-based economy** rather than traditional points/coins:
|
|
||||||
|
|
||||||
- **Currency:** Lives (renewable resource)
|
|
||||||
- **Starting Value:** 10 lives per new player
|
|
||||||
- **Earning Mechanic:** +1 life per completed level
|
|
||||||
- **Spending Mechanic:** -1 life per hint unlock (optional, 2 hints available)
|
|
||||||
- **Net Effect:** Players naturally gain lives if they solve without hints, stay stable with 1 hint/level, or lose lives if using both hints
|
|
||||||
|
|
||||||
The system is **fully persistent** (saved to localStorage) and **progression-aware** (can replay earlier levels while advancing).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Analyzed (21 total)
|
|
||||||
|
|
||||||
### Core Game Logic (4 files)
|
|
||||||
1. **PageLevel.ts** (786 lines) - Main gameplay, hint system, answer validation
|
|
||||||
2. **LevelDataManager.ts** (312 lines) - API calls, level caching, image loading
|
|
||||||
3. **StorageManager.ts** (240 lines) - Lives & progress persistence
|
|
||||||
4. **PageLoading.ts** (88 lines) - App initialization, preloading
|
|
||||||
|
|
||||||
### UI/Navigation (3 files)
|
|
||||||
5. **ViewManager.ts** (320 lines) - Page stack management
|
|
||||||
6. **BaseView.ts** (132 lines) - View lifecycle
|
|
||||||
7. **PassModal.ts** (155 lines) - Victory screen with rewards
|
|
||||||
|
|
||||||
### Utilities (5 files)
|
|
||||||
8. **ToastManager.ts** (59 lines) - Toast notifications
|
|
||||||
9. **WxSDK.ts** (188 lines) - WeChat API wrapper
|
|
||||||
10. **HttpUtil.ts** (76 lines) - HTTP requests
|
|
||||||
11. **Toast.ts** (50 lines) - Toast display component
|
|
||||||
12. **LevelTypes.ts** (59 lines) - TypeScript interfaces
|
|
||||||
|
|
||||||
### Prefabs & Entry Points (3 files)
|
|
||||||
13. **PageHome.ts** (78 lines) - Home page
|
|
||||||
14. **main.ts** (59 lines) - App entry point
|
|
||||||
15. Plus UI utilities (BackgroundScaler, RoundedRectMask)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Complete Points/Lives Flow
|
|
||||||
|
|
||||||
### 🟢 EARNING Lives
|
|
||||||
| Event | Amount | Condition |
|
|
||||||
|-------|--------|-----------|
|
|
||||||
| Correct Answer | +1 | Submitted answer matches API answer exactly (case-sensitive, trimmed) |
|
|
||||||
| New Game | +10 | First time players only (default) |
|
|
||||||
| **Cannot Earn** | 0 | Wrong answers, timeouts, hint unlocks, returning players don't reset |
|
|
||||||
|
|
||||||
### 🔴 SPENDING Lives
|
|
||||||
| Event | Amount | Condition |
|
|
||||||
|--------|--------|-----------|
|
|
||||||
| Unlock Hint 2 | -1 | Player clicks unlock, must have lives > 0 |
|
|
||||||
| Unlock Hint 3 | -1 | Player clicks unlock, must have lives > 0 |
|
|
||||||
| No Other Costs | - | No penalties for wrong answers or timeouts |
|
|
||||||
|
|
||||||
### 📊 Net Economy Per Level
|
|
||||||
```
|
|
||||||
Best Case (No Hints): +1 life/level → Infinite scaling
|
|
||||||
Average Case (1 Hint): 0 lives/level → Stable indefinitely
|
|
||||||
Hard Case (2 Hints): -1 life/level → Runs out after 10-20 levels
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Data Persistence
|
|
||||||
|
|
||||||
### localStorage Keys
|
|
||||||
```javascript
|
|
||||||
{
|
|
||||||
"game_lives": "10", // Current lives count
|
|
||||||
"game_progress": "{ // Player progression
|
|
||||||
\"currentLevelIndex\": 0,
|
|
||||||
\"maxUnlockedLevelIndex\": 0
|
|
||||||
}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lifespan
|
|
||||||
- **Initial:** Set when first loading game
|
|
||||||
- **Updates:** Every level completion or hint unlock
|
|
||||||
- **Persistence:** Survives app close/reopen (native browser storage)
|
|
||||||
- **Manual Reset:** Available via `StorageManager.resetAll()`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Level Progression System
|
|
||||||
|
|
||||||
### Mechanics
|
|
||||||
1. **Level 1 Always Unlocked** - New players start here
|
|
||||||
2. **Sequential Unlocking** - Beat level N to unlock level N+1
|
|
||||||
3. **Non-Linear Progress** - Can replay earlier levels anytime
|
|
||||||
4. **Max Tracking** - Tracks highest level reached for achievements
|
|
||||||
|
|
||||||
### Data Structure
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
currentLevelIndex: number, // Which level to play next (0-based)
|
|
||||||
maxUnlockedLevelIndex: number // Highest level player has beaten
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example Progression
|
|
||||||
```
|
|
||||||
User beats Level 3 (index 2)
|
|
||||||
↓
|
|
||||||
currentLevelIndex → 2+1 = 3 (level 4)
|
|
||||||
maxUnlockedLevelIndex → max(2, previous) = 2
|
|
||||||
↓
|
|
||||||
Can now play levels 0-3
|
|
||||||
Must complete level 3 to unlock level 4
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Hint System
|
|
||||||
|
|
||||||
### Mechanics
|
|
||||||
- **Hint 1:** Always visible, completely free
|
|
||||||
- **Hint 2:** Hidden by default, costs 1 life to unlock
|
|
||||||
- **Hint 3:** Hidden by default, costs 1 life to unlock
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
```typescript
|
|
||||||
onUnlockClue(index: 2|3) {
|
|
||||||
if (!hasLives()) return; // Must have >= 1 life
|
|
||||||
consumeLife(); // Deduct 1 life
|
|
||||||
showClue(index); // Reveal the clue content
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategic Element
|
|
||||||
Players must decide if they want to spend lives for hints or solve blindly to accumulate more lives for future levels.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Gameplay Loop
|
|
||||||
|
|
||||||
### Per-Level Sequence
|
|
||||||
1. Load level image from API cache
|
|
||||||
2. Display Hint 1 (free) + two "Unlock" buttons
|
|
||||||
3. Start 60-second countdown
|
|
||||||
4. Player can:
|
|
||||||
- Unlock hints by spending lives (optional, repeatable)
|
|
||||||
- Type their answer in single text box
|
|
||||||
- Submit answer
|
|
||||||
5. Outcome:
|
|
||||||
- **Correct:** Reward +1 life, show victory modal
|
|
||||||
- **Wrong:** No penalty, show error toast, can retry
|
|
||||||
- **Timeout:** Play fail sound, can still submit
|
|
||||||
|
|
||||||
### Victory Rewards
|
|
||||||
```
|
|
||||||
onSubmitAnswer(userAnswer) {
|
|
||||||
if (userAnswer.trim() === correctAnswer) {
|
|
||||||
playSuccessSound();
|
|
||||||
addLife(); // +1 life
|
|
||||||
StorageManager.onLevelCompleted(currentLevel);
|
|
||||||
showPassModal(); // Next/Share buttons
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API Integration
|
|
||||||
|
|
||||||
### Endpoint
|
|
||||||
```
|
|
||||||
GET https://ilookai.cn/api/v1/wechat-game/levels
|
|
||||||
```
|
|
||||||
|
|
||||||
### Response Format
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
success: boolean,
|
|
||||||
message: string | null,
|
|
||||||
data: {
|
|
||||||
levels: [
|
|
||||||
{
|
|
||||||
id: "uuid",
|
|
||||||
level: 1,
|
|
||||||
imageUrl: "https://...",
|
|
||||||
hint1: "Free clue",
|
|
||||||
hint2: "Paid clue",
|
|
||||||
hint3: "Paid clue",
|
|
||||||
answer: "CORRECT_ANSWER",
|
|
||||||
sortOrder: 1
|
|
||||||
},
|
|
||||||
// ... more levels
|
|
||||||
],
|
|
||||||
total: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Reliability Features
|
|
||||||
- **Retry Logic:** 2 attempts on failure
|
|
||||||
- **Timeout:** 8 seconds per request
|
|
||||||
- **Fallback:** Shows error message if all retries fail
|
|
||||||
- **Caching:** All levels cached in memory after first load
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## WeChat Integration
|
|
||||||
|
|
||||||
### Features Implemented
|
|
||||||
1. **Sharing** - Share game to friends with level parameter
|
|
||||||
2. **Vibration** - Haptic feedback on errors
|
|
||||||
3. **Platform Detection** - Gracefully degrade on non-WeChat platforms
|
|
||||||
|
|
||||||
### Share Implementation
|
|
||||||
```typescript
|
|
||||||
// On victory, user can click "Share"
|
|
||||||
WxSDK.shareAppMessage({
|
|
||||||
title: "快来一起玩这款游戏吧",
|
|
||||||
query: `level=${victoryLevelIndex}`
|
|
||||||
});
|
|
||||||
// Opens WeChat share dialog with referral link
|
|
||||||
```
|
|
||||||
|
|
||||||
### Not Implemented
|
|
||||||
- ❌ User authentication (wx.login)
|
|
||||||
- ❌ Backend progress sync
|
|
||||||
- ❌ Analytics
|
|
||||||
- ❌ Ads/Monetization
|
|
||||||
- ❌ Leaderboards
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## User Journey Example
|
|
||||||
|
|
||||||
```
|
|
||||||
New User Opens Game
|
|
||||||
↓
|
|
||||||
[Initialize: 10 lives, Level 1]
|
|
||||||
↓
|
|
||||||
Attempt Level 1
|
|
||||||
├─ Unlocks Hint 2 (-1 life) → 9 lives
|
|
||||||
├─ Unlocks Hint 3 (-1 life) → 8 lives
|
|
||||||
├─ Submits Answer
|
|
||||||
│
|
|
||||||
├─ CORRECT
|
|
||||||
│ ├─ Awards +1 life → 9 lives
|
|
||||||
│ ├─ Saves progress (level → 2)
|
|
||||||
│ └─ Shows PassModal
|
|
||||||
│ ├─ Can click "Next Level" → Level 2
|
|
||||||
│ └─ Can click "Share" → wx.share
|
|
||||||
│
|
|
||||||
└─ WRONG
|
|
||||||
├─ No penalty → 9 lives unchanged
|
|
||||||
├─ Shows error toast
|
|
||||||
└─ Can retry immediately
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Loading & Initialization
|
|
||||||
|
|
||||||
### On App Start
|
|
||||||
1. **Detect New vs. Returning User**
|
|
||||||
- Check localStorage "game_lives" key
|
|
||||||
- New: Initialize to 10
|
|
||||||
- Returning: Restore value
|
|
||||||
|
|
||||||
2. **Load Level Metadata**
|
|
||||||
- API call to fetch all levels
|
|
||||||
- Retry up to 2 times on failure
|
|
||||||
- Cache all level data in memory
|
|
||||||
|
|
||||||
3. **Preload First Level**
|
|
||||||
- Download image for level 1
|
|
||||||
- Cache in memory for instant display
|
|
||||||
|
|
||||||
4. **Show Home Screen**
|
|
||||||
- Display "Start Game" button
|
|
||||||
- Initialize WeChat sharing
|
|
||||||
|
|
||||||
### On Subsequent Game Sessions
|
|
||||||
1. Restore lives from localStorage
|
|
||||||
2. Restore progress from localStorage
|
|
||||||
3. Resume at saved level
|
|
||||||
4. API already cached (no refetch unless app restarted)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Key Constants
|
|
||||||
|
|
||||||
| Constant | Value | Usage |
|
|
||||||
|----------|-------|-------|
|
|
||||||
| DEFAULT_LIVES | 10 | New player starting amount |
|
|
||||||
| MIN_LIVES | 0 | Cannot go negative |
|
|
||||||
| LEVEL_TIME_LIMIT | 60 seconds | Countdown timer |
|
|
||||||
| API_TIMEOUT | 8000ms | HTTP request timeout |
|
|
||||||
| API_RETRY_COUNT | 2 | Attempts on failure |
|
|
||||||
| HINT_COST | 1 life each | Unlock clue 2 or 3 |
|
|
||||||
| WIN_REWARD | 1 life | Completion bonus |
|
|
||||||
| MODAL_Z_INDEX | 999 | Victory modal layer |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Business Logic Highlights
|
|
||||||
|
|
||||||
### Win Condition
|
|
||||||
```typescript
|
|
||||||
userAnswer.trim() === correctAnswer
|
|
||||||
```
|
|
||||||
- Case-sensitive
|
|
||||||
- Whitespace trimmed
|
|
||||||
- Must match exactly
|
|
||||||
|
|
||||||
### No Lose Condition
|
|
||||||
- Wrong answers: No penalty
|
|
||||||
- Time up: No penalty
|
|
||||||
- Can retry infinitely on same level
|
|
||||||
|
|
||||||
### Safety Checks
|
|
||||||
- Can't unlock hints if lives ≤ 0
|
|
||||||
- Can't go below 0 lives
|
|
||||||
- Can't exceed total levels
|
|
||||||
- Invalid data resets to defaults
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Performance Optimizations
|
|
||||||
|
|
||||||
1. **Image Caching** - Downloaded images cached in memory
|
|
||||||
2. **Level Metadata Caching** - API data cached to avoid re-fetching
|
|
||||||
3. **Progress Caching** - localStorage data cached to reduce reads
|
|
||||||
4. **Async Preloading** - Next level preloaded silently
|
|
||||||
5. **Efficient UI** - Single EditBox (not per-character)
|
|
||||||
6. **Lazy Loading** - Pages cached after first load
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Missing Features / Gaps
|
|
||||||
|
|
||||||
| Feature | Status | Impact |
|
|
||||||
|---------|--------|--------|
|
|
||||||
| User Authentication | ❌ | No way to sync across devices |
|
|
||||||
| Backend Progress Save | ❌ | Progress lost if localStorage clears |
|
|
||||||
| Monetization | ❌ | No revenue stream |
|
|
||||||
| Ads | ❌ | No ad integration |
|
|
||||||
| Analytics | ❌ | Can't track player behavior |
|
|
||||||
| Leaderboards | ❌ | No competition mechanics |
|
|
||||||
| Sound Toggle | ❌ | Always plays sounds |
|
|
||||||
| Difficulty Levels | ❌ | All players see same levels |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Scenarios
|
|
||||||
|
|
||||||
### Test Case 1: Lives Economy
|
|
||||||
```
|
|
||||||
1. New game → 10 lives
|
|
||||||
2. Beat level without hints → 11 lives
|
|
||||||
3. Beat level with 1 hint → 11 lives (net 0)
|
|
||||||
4. Beat level with 2 hints → 10 lives (net -1)
|
|
||||||
→ Verify localStorage updated after each
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Case 2: Progression
|
|
||||||
```
|
|
||||||
1. Complete level 1
|
|
||||||
2. Verify currentLevel → 2
|
|
||||||
3. Verify maxUnlocked → 1
|
|
||||||
4. Restart app
|
|
||||||
5. Verify levels still saved
|
|
||||||
6. Replay level 1
|
|
||||||
7. Verify no duplicate progress
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Case 3: Hint Cost
|
|
||||||
```
|
|
||||||
1. Start with 10 lives
|
|
||||||
2. Unlock hint 2 → 9 lives displayed
|
|
||||||
3. Unlock hint 3 → 8 lives displayed
|
|
||||||
4. Can't unlock again (button inactive)
|
|
||||||
5. Wrong answer → 8 lives still
|
|
||||||
6. Correct answer → 9 lives (net -1)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
This is a **well-architected mini-game** with:
|
|
||||||
- ✅ Clear lives-based economy
|
|
||||||
- ✅ Persistent progress tracking
|
|
||||||
- ✅ Strategic hint system
|
|
||||||
- ✅ Reliable API integration
|
|
||||||
- ✅ Good error handling
|
|
||||||
- ✅ WeChat platform integration
|
|
||||||
|
|
||||||
The point system is **intentionally forgiving** - players who solve puzzles smartly gain lives indefinitely, while those using hints maintain stability. This encourages skill development without hard progress walls.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Documentation Files Generated
|
|
||||||
|
|
||||||
1. **GAME_ANALYSIS.md** - Comprehensive 17-section analysis (13KB)
|
|
||||||
2. **QUICK_REFERENCE.md** - Quick lookup guide (5.6KB)
|
|
||||||
3. **POINTS_FLOW_DIAGRAM.md** - Visual flow diagrams (15KB)
|
|
||||||
4. **SUMMARY.md** - This executive summary (8KB)
|
|
||||||
|
|
||||||
**Total:** 42KB of detailed documentation covering every aspect of the points/score/lives system.
|
|
||||||
|
|
||||||
BIN
assets/.DS_Store
vendored
Normal file
@@ -176,7 +176,7 @@
|
|||||||
"a": 255
|
"a": 255
|
||||||
},
|
},
|
||||||
"_spriteFrame": {
|
"_spriteFrame": {
|
||||||
"__uuid__": "d532045e-55f8-47c2-9493-b918e18364b0@f9941",
|
"__uuid__": "10047f2e-bf2c-46f0-ba98-6fc23cf7ea87@f9941",
|
||||||
"__expectedType__": "cc.SpriteFrame"
|
"__expectedType__": "cc.SpriteFrame"
|
||||||
},
|
},
|
||||||
"_type": 0,
|
"_type": 0,
|
||||||
@@ -597,8 +597,8 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 80,
|
"width": 88,
|
||||||
"height": 50.4
|
"height": 58.4
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
@@ -646,19 +646,19 @@
|
|||||||
"_isSystemFontUsed": true,
|
"_isSystemFontUsed": true,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_isItalic": false,
|
"_isItalic": false,
|
||||||
"_isBold": false,
|
"_isBold": true,
|
||||||
"_isUnderline": false,
|
"_isUnderline": false,
|
||||||
"_underlineHeight": 2,
|
"_underlineHeight": 2,
|
||||||
"_cacheMode": 0,
|
"_cacheMode": 0,
|
||||||
"_enableOutline": false,
|
"_enableOutline": true,
|
||||||
"_outlineColor": {
|
"_outlineColor": {
|
||||||
"__type__": "cc.Color",
|
"__type__": "cc.Color",
|
||||||
"r": 0,
|
"r": 72,
|
||||||
"g": 0,
|
"g": 158,
|
||||||
"b": 0,
|
"b": 35,
|
||||||
"a": 255
|
"a": 255
|
||||||
},
|
},
|
||||||
"_outlineWidth": 2,
|
"_outlineWidth": 4,
|
||||||
"_enableShadow": false,
|
"_enableShadow": false,
|
||||||
"_shadowColor": {
|
"_shadowColor": {
|
||||||
"__type__": "cc.Color",
|
"__type__": "cc.Color",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { _decorator, Component, ProgressBar, Label } from 'cc';
|
import { _decorator, Component, ProgressBar, Label, assetManager } from 'cc';
|
||||||
|
import type { AssetManager } from 'cc';
|
||||||
import { ViewManager } from './scripts/core/ViewManager';
|
import { ViewManager } from './scripts/core/ViewManager';
|
||||||
import { LevelDataManager } from './scripts/utils/LevelDataManager';
|
import { LevelDataManager } from './scripts/utils/LevelDataManager';
|
||||||
import { AuthManager } from './scripts/utils/AuthManager';
|
import { AuthManager } from './scripts/utils/AuthManager';
|
||||||
import { StorageManager } from './scripts/utils/StorageManager';
|
|
||||||
import { ShareManager } from './scripts/utils/ShareManager';
|
import { ShareManager } from './scripts/utils/ShareManager';
|
||||||
import { WxSDK } from './scripts/utils/WxSDK';
|
import { WxSDK } from './scripts/utils/WxSDK';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
@@ -10,10 +10,12 @@ const { ccclass, property } = _decorator;
|
|||||||
/**
|
/**
|
||||||
* 页面加载组件
|
* 页面加载组件
|
||||||
* 负责用户登录、预加载资源并显示加载进度
|
* 负责用户登录、预加载资源并显示加载进度
|
||||||
* 登录与关卡数据加载并行执行以减少等待时间
|
* 流程:登录 + game-data → 拿到 nextLevel → 加载首关图片 → 进入首页
|
||||||
*/
|
*/
|
||||||
@ccclass('PageLoading')
|
@ccclass('PageLoading')
|
||||||
export class PageLoading extends Component {
|
export class PageLoading extends Component {
|
||||||
|
private static readonly FONT_BUNDLE_NAME = 'fonts';
|
||||||
|
|
||||||
@property(ProgressBar)
|
@property(ProgressBar)
|
||||||
progressBar: ProgressBar | null = null;
|
progressBar: ProgressBar | null = null;
|
||||||
|
|
||||||
@@ -31,15 +33,11 @@ export class PageLoading extends Component {
|
|||||||
|
|
||||||
this._updateStatusLabel('正在加载...');
|
this._updateStatusLabel('正在加载...');
|
||||||
|
|
||||||
// 登录和关卡数据并行加载
|
// 阶段1: 登录 + 获取 game-data(含 nextLevel)
|
||||||
const [loginSuccess, levelSuccess] = await Promise.all([
|
this._updateProgress(0);
|
||||||
AuthManager.instance.initialize(),
|
this._updateStatusLabel('正在连接服务器...');
|
||||||
LevelDataManager.instance.initialize((progress, message) => {
|
|
||||||
// 关卡加载占 0-80% 进度
|
const loginSuccess = await AuthManager.instance.initialize();
|
||||||
this._updateProgress(progress);
|
|
||||||
this._updateStatusLabel(message);
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (loginSuccess) {
|
if (loginSuccess) {
|
||||||
console.log('[PageLoading] 用户登录成功');
|
console.log('[PageLoading] 用户登录成功');
|
||||||
@@ -47,14 +45,38 @@ export class PageLoading extends Component {
|
|||||||
console.warn('[PageLoading] 登录失败,继续离线模式');
|
console.warn('[PageLoading] 登录失败,继续离线模式');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._updateProgress(0.2);
|
||||||
|
|
||||||
|
// 阶段2: 加载首关图片(如果有 nextLevel)
|
||||||
|
const nextLevel = AuthManager.instance.nextLevel;
|
||||||
|
let levelSuccess = false;
|
||||||
|
|
||||||
|
if (nextLevel) {
|
||||||
|
levelSuccess = await LevelDataManager.instance.initialize(nextLevel, (progress, message) => {
|
||||||
|
// 关卡图片加载占 20%-80% 进度
|
||||||
|
this._updateProgress(0.2 + progress * 0.6);
|
||||||
|
this._updateStatusLabel(message);
|
||||||
|
});
|
||||||
|
|
||||||
if (!levelSuccess) {
|
if (!levelSuccess) {
|
||||||
|
this._updateStatusLabel('资源加载失败,请重新打开游戏');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (loginSuccess) {
|
||||||
|
// nextLevel 为 null → 全部通关(或服务端无关卡)
|
||||||
|
console.log('[PageLoading] 全部通关或无可用关卡');
|
||||||
|
this._updateProgress(0.8);
|
||||||
|
} else {
|
||||||
|
// 登录失败且没有 nextLevel
|
||||||
this._updateStatusLabel('加载失败,请重新打开游戏');
|
this._updateStatusLabel('加载失败,请重新打开游戏');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录 + 关卡数据都就绪后,用服务端进度覆盖本地进度
|
// 阶段3: 加载字体分包
|
||||||
if (loginSuccess) {
|
const fontSuccess = await this._loadFontBundle();
|
||||||
this._syncProgressFromServer();
|
if (!fontSuccess) {
|
||||||
|
this._updateStatusLabel('字体资源加载失败,请重新打开游戏');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测分享码:从微信启动参数中获取
|
// 检测分享码:从微信启动参数中获取
|
||||||
@@ -77,10 +99,10 @@ export class PageLoading extends Component {
|
|||||||
console.warn('[PageLoading] 加入分享失败,进入正常模式');
|
console.warn('[PageLoading] 加入分享失败,进入正常模式');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 正常流程:预加载 PageHome (80-100%)
|
// 正常流程:预加载 PageHome (82-100%)
|
||||||
ViewManager.instance.preload('PageHome',
|
ViewManager.instance.preload('PageHome',
|
||||||
(progress) => {
|
(progress) => {
|
||||||
this._updateProgress(0.8 + progress * 0.2);
|
this._updateProgress(0.82 + progress * 0.18);
|
||||||
this._updateStatusLabel('正在加载界面资源...');
|
this._updateStatusLabel('正在加载界面资源...');
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
@@ -113,28 +135,32 @@ export class PageLoading extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用服务端通关进度覆盖本地进度
|
* 加载字体分包,避免字体资源进入小游戏主包
|
||||||
* 将 completedLevelIds 转换为本地的 currentLevelIndex / maxUnlockedLevelIndex
|
|
||||||
*/
|
*/
|
||||||
private _syncProgressFromServer(): void {
|
private _loadFontBundle(): Promise<boolean> {
|
||||||
const completedIds = AuthManager.instance.completedLevelIds;
|
const bundleName = PageLoading.FONT_BUNDLE_NAME;
|
||||||
if (completedIds.length === 0) {
|
const cachedBundle = assetManager.getBundle(bundleName);
|
||||||
console.log('[PageLoading] 服务端无通关记录,使用本地进度');
|
if (cachedBundle) {
|
||||||
|
console.log(`[PageLoading] 字体分包已加载: ${bundleName}`);
|
||||||
|
this._updateProgress(0.82);
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateStatusLabel('正在加载字体资源...');
|
||||||
|
this._updateProgress(0.8);
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
assetManager.loadBundle(bundleName, (err: Error | null, bundle: AssetManager.Bundle | null) => {
|
||||||
|
if (err || !bundle) {
|
||||||
|
console.error(`[PageLoading] 字体分包加载失败: ${bundleName}`, err);
|
||||||
|
resolve(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxCompletedIndex = LevelDataManager.instance.getMaxCompletedIndex(completedIds);
|
console.log(`[PageLoading] 字体分包加载完成: ${bundleName}`);
|
||||||
if (maxCompletedIndex < 0) {
|
this._updateProgress(0.82);
|
||||||
return;
|
resolve(true);
|
||||||
}
|
});
|
||||||
|
});
|
||||||
const localMax = StorageManager.getMaxUnlockedLevelIndex();
|
|
||||||
|
|
||||||
// 取服务端和本地的较大值,防止进度回退
|
|
||||||
if (maxCompletedIndex > localMax) {
|
|
||||||
// onLevelCompleted 会同时设置 currentLevelIndex = maxCompletedIndex + 1 和 maxUnlockedLevelIndex
|
|
||||||
StorageManager.onLevelCompleted(maxCompletedIndex);
|
|
||||||
console.log(`[PageLoading] 服务端进度同步:已通关到第 ${maxCompletedIndex + 1} 关`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
assets/fonts.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.2.0",
|
||||||
|
"importer": "directory",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "fc1f44af-699f-467c-ba2d-f54994551c4d",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"isBundle": true
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/fonts/Game011_3.ttf
Normal file
12
assets/fonts/Game011_3.ttf.meta
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.1",
|
||||||
|
"importer": "ttf-font",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "fb4acba6-6bc7-4eb3-be34-8f2ac9823a80",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
"Game011_3.ttf"
|
||||||
|
],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
9
assets/levels.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.2.0",
|
||||||
|
"importer": "directory",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "0b928321-a809-4339-8af8-5a053aeda2d5",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
import { _decorator, Node, Button } from 'cc';
|
import { _decorator, Node, Button, Label, tween, Vec3, UIOpacity, UITransform, Color, instantiate } from 'cc';
|
||||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||||
import { WxSDK, checkPrivacySetting, requirePrivacyAuthorize } from 'db://assets/scripts/utils/WxSDK';
|
import { WxSDK, checkPrivacySetting, requirePrivacyAuthorize } from 'db://assets/scripts/utils/WxSDK';
|
||||||
|
import { StaminaManager } from 'db://assets/scripts/utils/StaminaManager';
|
||||||
|
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
||||||
|
import { StaminaInfo } from 'db://assets/scripts/types/ApiTypes';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,12 +13,34 @@ const { ccclass, property } = _decorator;
|
|||||||
*/
|
*/
|
||||||
@ccclass('PageHome')
|
@ccclass('PageHome')
|
||||||
export class PageHome extends BaseView {
|
export class PageHome extends BaseView {
|
||||||
|
/** 默认体力上限 */
|
||||||
|
private static readonly DEFAULT_STAMINA_MAX = 50;
|
||||||
|
|
||||||
@property({ type: Node, tooltip: '开始游戏按钮' })
|
@property({ type: Node, tooltip: '开始游戏按钮' })
|
||||||
startGameBtn: Node | null = null;
|
startGameBtn: Node | null = null;
|
||||||
|
|
||||||
@property({ type: Node, tooltip: 'PK按钮' })
|
@property({ type: Node, tooltip: 'PK按钮' })
|
||||||
pkBtn: Node | null = null;
|
pkBtn: Node | null = null;
|
||||||
|
|
||||||
|
/** 体力值显示标签 */
|
||||||
|
@property(Label)
|
||||||
|
liveLabel: Label | null = null;
|
||||||
|
|
||||||
|
/** 飞行动画持续时间(秒) */
|
||||||
|
private static readonly FLY_DURATION = 0.5;
|
||||||
|
|
||||||
|
/** 到达后弹跳持续时间(秒) */
|
||||||
|
private static readonly BOUNCE_DURATION = 0.15;
|
||||||
|
|
||||||
|
/** 浮动文本动画持续时间(秒) */
|
||||||
|
private static readonly FLOAT_DURATION = 0.8;
|
||||||
|
|
||||||
|
/** 浮动文本上移距离 */
|
||||||
|
private static readonly FLOAT_OFFSET_Y = 120;
|
||||||
|
|
||||||
|
/** 是否正在播放体力消耗动画 */
|
||||||
|
private _isAnimating: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 页面首次加载时调用
|
* 页面首次加载时调用
|
||||||
*/
|
*/
|
||||||
@@ -76,8 +101,29 @@ export class PageHome extends BaseView {
|
|||||||
* 开始游戏按钮点击回调
|
* 开始游戏按钮点击回调
|
||||||
*/
|
*/
|
||||||
private _onStartGameClick(): void {
|
private _onStartGameClick(): void {
|
||||||
|
if (this._isAnimating) return;
|
||||||
|
|
||||||
console.log('[PageHome] 开始游戏按钮点击');
|
console.log('[PageHome] 开始游戏按钮点击');
|
||||||
|
|
||||||
|
// 体力检查
|
||||||
|
if (!StaminaManager.instance.hasStamina()) {
|
||||||
|
ToastManager.show('体力不足,请等待恢复');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isAnimating = true;
|
||||||
|
this._playStaminaCostAnimation()
|
||||||
|
.then(() => {
|
||||||
ViewManager.instance.open('PageLevel');
|
ViewManager.instance.open('PageLevel');
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error('[PageHome] 体力消耗动画异常:', err);
|
||||||
|
// 异常兜底:直接进入关卡
|
||||||
|
ViewManager.instance.open('PageLevel');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this._isAnimating = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,11 +134,198 @@ export class PageHome extends BaseView {
|
|||||||
ViewManager.instance.open('PageWriteLevels');
|
ViewManager.instance.open('PageWriteLevels');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 体力消耗动画 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过节点路径查找 IconLive
|
||||||
|
*/
|
||||||
|
private _findIconLive(): Node | null {
|
||||||
|
return this.node
|
||||||
|
.getChildByName('TopLayout')
|
||||||
|
?.getChildByName('Live')
|
||||||
|
?.getChildByName('IconLive') ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将节点的世界坐标转换为目标父节点的本地坐标
|
||||||
|
*/
|
||||||
|
private _worldToLocal(worldPos: Vec3, parent: Node): Vec3 {
|
||||||
|
const parentTransform = parent.getComponent(UITransform);
|
||||||
|
if (!parentTransform) return worldPos;
|
||||||
|
return parentTransform.convertToNodeSpaceAR(worldPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取节点的世界坐标
|
||||||
|
*/
|
||||||
|
private _getWorldPos(node: Node): Vec3 {
|
||||||
|
const transform = node.getComponent(UITransform);
|
||||||
|
if (!transform) return node.worldPosition.clone();
|
||||||
|
return transform.convertToWorldSpaceAR(Vec3.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 播放体力消耗动画
|
||||||
|
* 1. 克隆 IconLive 飞向 StarGame 按钮
|
||||||
|
* 2. 到达后弹跳
|
||||||
|
* 3. "体力值-1" 浮动文本上移渐隐
|
||||||
|
* 4. 同步更新体力数字
|
||||||
|
*/
|
||||||
|
private _playStaminaCostAnimation(): Promise<void> {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
const iconLive = this._findIconLive();
|
||||||
|
const targetBtn = this.startGameBtn;
|
||||||
|
|
||||||
|
if (!iconLive || !targetBtn) {
|
||||||
|
console.warn('[PageHome] 动画节点未找到,跳过动画');
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 坐标计算 ---
|
||||||
|
const iconWorldPos = this._getWorldPos(iconLive);
|
||||||
|
const targetWorldPos = this._getWorldPos(targetBtn);
|
||||||
|
const rootNode = this.node;
|
||||||
|
|
||||||
|
// 起始和终点在 root 本地空间的坐标
|
||||||
|
const startLocal = this._worldToLocal(iconWorldPos, rootNode);
|
||||||
|
const endLocal = this._worldToLocal(targetWorldPos, rootNode);
|
||||||
|
|
||||||
|
// --- 克隆飞行节点 ---
|
||||||
|
const flyNode = instantiate(iconLive);
|
||||||
|
flyNode.name = '_flyIcon';
|
||||||
|
flyNode.setPosition(startLocal);
|
||||||
|
// 保持与原始 IconLive 相同的缩放
|
||||||
|
flyNode.setScale(iconLive.worldScale.clone());
|
||||||
|
rootNode.addChild(flyNode);
|
||||||
|
|
||||||
|
// 隐藏原始 IconLive
|
||||||
|
iconLive.active = false;
|
||||||
|
|
||||||
|
// --- 飞行路径(带弧度的抛物线效果) ---
|
||||||
|
// 中间控制点:x 取中点,y 取较高值 + 偏移形成弧线
|
||||||
|
const midX = (startLocal.x + endLocal.x) / 2;
|
||||||
|
const midY = Math.max(startLocal.y, endLocal.y) + 150;
|
||||||
|
const midPoint = new Vec3(midX, midY, 0);
|
||||||
|
|
||||||
|
// 阶段1:飞到弧线顶点
|
||||||
|
const halfDuration = PageHome.FLY_DURATION / 2;
|
||||||
|
|
||||||
|
tween(flyNode)
|
||||||
|
.to(halfDuration, { position: midPoint }, { easing: 'quadOut' })
|
||||||
|
.to(halfDuration, { position: endLocal }, { easing: 'quadIn' })
|
||||||
|
// 阶段2:到达弹跳
|
||||||
|
.to(PageHome.BOUNCE_DURATION / 2, { scale: new Vec3(0.4, 0.4, 1) }, { easing: 'quadOut' })
|
||||||
|
.to(PageHome.BOUNCE_DURATION / 2, { scale: new Vec3(0.3, 0.3, 1) }, { easing: 'quadIn' })
|
||||||
|
.call(() => {
|
||||||
|
// 飞行完成 — flyNode 使命结束,立即清理
|
||||||
|
flyNode.destroy();
|
||||||
|
iconLive.active = true;
|
||||||
|
|
||||||
|
// 创建浮动文本
|
||||||
|
this._showFloatText(targetBtn, rootNode);
|
||||||
|
|
||||||
|
// 乐观更新体力数字
|
||||||
|
this._optimisticUpdateStamina();
|
||||||
|
|
||||||
|
// 等浮动文本播完再 resolve(用 setTimeout,不依赖已销毁节点的 tween)
|
||||||
|
setTimeout(() => resolve(), PageHome.FLOAT_DURATION * 1000);
|
||||||
|
})
|
||||||
|
.start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示浮动提示文本 "体力值-1"
|
||||||
|
* 从按钮位置向上漂移并渐隐
|
||||||
|
*/
|
||||||
|
private _showFloatText(anchorNode: Node, parentNode: Node): void {
|
||||||
|
// 创建文本节点
|
||||||
|
const textNode = new Node('_floatText');
|
||||||
|
textNode.addComponent(UITransform);
|
||||||
|
|
||||||
|
const label = textNode.addComponent(Label);
|
||||||
|
label.string = '体力值-1';
|
||||||
|
label.fontSize = 36;
|
||||||
|
label.lineHeight = 40;
|
||||||
|
label.color = new Color(255, 80, 80, 255);
|
||||||
|
label.isBold = true;
|
||||||
|
|
||||||
|
// 复用 liveLabel 的字体(如果有)
|
||||||
|
if (this.liveLabel?.font) {
|
||||||
|
label.font = this.liveLabel.font;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加 UIOpacity 用于渐隐
|
||||||
|
const opacity = textNode.addComponent(UIOpacity);
|
||||||
|
opacity.opacity = 255;
|
||||||
|
|
||||||
|
// 定位到按钮上方
|
||||||
|
const anchorWorldPos = this._getWorldPos(anchorNode);
|
||||||
|
const localPos = this._worldToLocal(anchorWorldPos, parentNode);
|
||||||
|
// 起始位置在按钮上方偏移
|
||||||
|
localPos.y += 120;
|
||||||
|
textNode.setPosition(localPos);
|
||||||
|
|
||||||
|
parentNode.addChild(textNode);
|
||||||
|
|
||||||
|
// 向上漂移 + 渐隐
|
||||||
|
const floatTarget = new Vec3(localPos.x, localPos.y + PageHome.FLOAT_OFFSET_Y, 0);
|
||||||
|
tween(textNode)
|
||||||
|
.to(PageHome.FLOAT_DURATION, { position: floatTarget }, { easing: 'quadOut' })
|
||||||
|
.call(() => {
|
||||||
|
textNode.destroy();
|
||||||
|
})
|
||||||
|
.start();
|
||||||
|
|
||||||
|
tween(opacity)
|
||||||
|
.delay(PageHome.FLOAT_DURATION * 0.3)
|
||||||
|
.to(PageHome.FLOAT_DURATION * 0.7, { opacity: 0 }, { easing: 'quadIn' })
|
||||||
|
.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 乐观更新体力标签(本地 -1 预扣显示)
|
||||||
|
*/
|
||||||
|
private _optimisticUpdateStamina(): void {
|
||||||
|
if (!this.liveLabel) return;
|
||||||
|
|
||||||
|
const stamina = StaminaManager.instance.getStamina();
|
||||||
|
const maxStamina = this._getStaminaMax(stamina);
|
||||||
|
const displayCurrent = Math.max(0, stamina.current - 1);
|
||||||
|
this.liveLabel.string = `${displayCurrent}/${maxStamina}`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 页面每次显示时调用
|
* 页面每次显示时调用
|
||||||
*/
|
*/
|
||||||
onViewShow(): void {
|
onViewShow(): void {
|
||||||
console.log('[PageHome] onViewShow');
|
console.log('[PageHome] onViewShow');
|
||||||
|
this.updateStaminaLabel();
|
||||||
|
|
||||||
|
// 保险恢复:防止动画中途被打断导致 IconLive 隐藏残留
|
||||||
|
const iconLive = this._findIconLive();
|
||||||
|
if (iconLive && !iconLive.active) {
|
||||||
|
iconLive.active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取体力上限
|
||||||
|
*/
|
||||||
|
private _getStaminaMax(stamina: StaminaInfo): number {
|
||||||
|
return typeof stamina.max === 'number' ? stamina.max : PageHome.DEFAULT_STAMINA_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新体力值显示
|
||||||
|
*/
|
||||||
|
private updateStaminaLabel(): void {
|
||||||
|
if (this.liveLabel) {
|
||||||
|
const stamina = StaminaManager.instance.getStamina();
|
||||||
|
const maxStamina = this._getStaminaMax(stamina);
|
||||||
|
this.liveLabel.string = `${stamina.current}/${maxStamina}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { _decorator, Node, Button } from 'cc';
|
import { _decorator, Node, Button } from 'cc';
|
||||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||||
|
import { CreatedShareItem } 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;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
@ccclass('PagePKData')
|
@ccclass('PagePKData')
|
||||||
@@ -8,6 +11,9 @@ export class PagePKData extends BaseView {
|
|||||||
@property({ type: Node, tooltip: '返回按钮' })
|
@property({ type: Node, tooltip: '返回按钮' })
|
||||||
backBtn: Node | null = null;
|
backBtn: Node | null = null;
|
||||||
|
|
||||||
|
private _createdShares: CreatedShareItem[] = [];
|
||||||
|
private _isLoading: boolean = false;
|
||||||
|
|
||||||
onViewLoad(): void {
|
onViewLoad(): void {
|
||||||
if (this.backBtn) {
|
if (this.backBtn) {
|
||||||
this.backBtn.on(Button.EventType.CLICK, this._onBackClick, this);
|
this.backBtn.on(Button.EventType.CLICK, this._onBackClick, this);
|
||||||
@@ -15,6 +21,7 @@ export class PagePKData extends BaseView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onViewShow(): void {
|
onViewShow(): void {
|
||||||
|
void this._loadCreatedShares();
|
||||||
}
|
}
|
||||||
|
|
||||||
onViewHide(): void {
|
onViewHide(): void {
|
||||||
@@ -24,6 +31,26 @@ export class PagePKData extends BaseView {
|
|||||||
ViewManager.instance.back();
|
ViewManager.instance.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _loadCreatedShares(): Promise<void> {
|
||||||
|
if (this._isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isLoading = true;
|
||||||
|
try {
|
||||||
|
const items = await ShareManager.instance.fetchCreatedShares();
|
||||||
|
if (!items) {
|
||||||
|
ToastManager.instance.show('获取挑战列表失败,请稍后重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._createdShares = items;
|
||||||
|
console.log('[PagePKData] 我创建的挑战列表:', this._createdShares);
|
||||||
|
} finally {
|
||||||
|
this._isLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onViewDestroy(): void {
|
onViewDestroy(): void {
|
||||||
if (this.backBtn) {
|
if (this.backBtn) {
|
||||||
this.backBtn.off(Button.EventType.CLICK, this._onBackClick, this);
|
this.backBtn.off(Button.EventType.CLICK, this._onBackClick, this);
|
||||||
|
|||||||
@@ -1,29 +1,22 @@
|
|||||||
import { _decorator, Node, Button, Sprite, Label, ScrollView, instantiate, UITransform, Vec2 } from 'cc';
|
import { _decorator, Node, Button, Label, ScrollView, instantiate, UITransform } from 'cc';
|
||||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||||
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
|
import { CompletedLevelsManager } from 'db://assets/scripts/utils/CompletedLevelsManager';
|
||||||
|
import { PreviewLevelItem } from './PreviewLevelItem';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预览试卷页面
|
* 预览试卷页面
|
||||||
* 垂直滚动展示用户在 PageWriteLevels 中选中的 6 个关卡
|
* 垂直滚动展示用户在 PageWriteLevels 中选中的 6 个关卡
|
||||||
* 每个关卡展示:封面图、提示1、提示2、答案
|
* 每个关卡展示:封面图、线索1、线索2、线索3、答案
|
||||||
*
|
*
|
||||||
* prefab 节点结构(已在编辑器中搭建):
|
* 节点结构(仅 ScrollView 侧需要固定):
|
||||||
* PagePreviewLevels
|
* PagePreviewLevels
|
||||||
* ├── Bg
|
* ├── ScrollView / view / content ← listContent 容器
|
||||||
* ├── IconBack ← backBtn (返回按钮)
|
* └── ListTpl ← listTemplate 模板根节点
|
||||||
* ├── PKTitle ← 标题 "挑战"
|
* (挂 PreviewLevelItem 组件,字段由编辑器拖拽绑定)
|
||||||
* ├── ScrollView ← scrollView
|
*
|
||||||
* │ ├── scrollBar
|
* item 内部节点层级/命名对本文件透明:所有引用都来自 PreviewLevelItem 的 @property。
|
||||||
* │ └── view
|
|
||||||
* │ └── content ← listContent
|
|
||||||
* ├── ListTpl ← listTemplate (关卡模板)
|
|
||||||
* │ ├── LevelCover ← Sprite 封面图
|
|
||||||
* │ ├── Tips1 ← Label 提示1
|
|
||||||
* │ ├── Tips2 ← Label 提示2
|
|
||||||
* │ └── Answer ← Label 答案
|
|
||||||
* └── BackButton ← backButton (底部返回按钮)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** 布局配置 — 垂直列表 */
|
/** 布局配置 — 垂直列表 */
|
||||||
@@ -197,44 +190,26 @@ export class PagePreviewLevels extends BaseView {
|
|||||||
* 异步加载关卡数据并填充到 item 节点
|
* 异步加载关卡数据并填充到 item 节点
|
||||||
*/
|
*/
|
||||||
private async _loadLevelData(item: Node, levelIndex: number, displayIndex: number): Promise<void> {
|
private async _loadLevelData(item: Node, levelIndex: number, displayIndex: number): Promise<void> {
|
||||||
const config = await LevelDataManager.instance.ensureLevelReady(levelIndex);
|
const level = CompletedLevelsManager.instance.getByIndex(levelIndex);
|
||||||
if (!config || !item.isValid) return;
|
if (!level || !item.isValid) return;
|
||||||
|
|
||||||
// 填充封面图
|
const view = item.getComponent(PreviewLevelItem);
|
||||||
const levelCover = item.getChildByName('LevelCover');
|
if (!view) {
|
||||||
if (levelCover) {
|
console.warn('[PagePreviewLevels] listTemplate 缺少 PreviewLevelItem 组件');
|
||||||
const sprite = levelCover.getComponent(Sprite);
|
return;
|
||||||
if (sprite && config.spriteFrame) {
|
|
||||||
sprite.spriteFrame = config.spriteFrame;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 填充提示1
|
view.setTexts({
|
||||||
const tips1 = item.getChildByName('Tips1');
|
answer: level.answer || '',
|
||||||
if (tips1) {
|
hint1: level.hint1 || '',
|
||||||
const label = tips1.getComponent(Label);
|
hint2: level.hint2 || '',
|
||||||
if (label) {
|
hint3: level.hint3 || '',
|
||||||
label.string = `线索一:${config.clue1 || ''}`;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 填充提示2
|
// 异步加载封面图(通常已由 WriteLevels 预热到缓存)
|
||||||
const tips2 = item.getChildByName('Tips2');
|
const spriteFrame = await CompletedLevelsManager.instance.loadImage(level.image1Url);
|
||||||
if (tips2) {
|
if (!spriteFrame || !item.isValid) return;
|
||||||
const label = tips2.getComponent(Label);
|
view.setCover(spriteFrame);
|
||||||
if (label) {
|
|
||||||
label.string = `线索二:${config.clue2 || ''}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 填充答案
|
|
||||||
const answer = item.getChildByName('Answer');
|
|
||||||
if (answer) {
|
|
||||||
const label = answer.getComponent(Label);
|
|
||||||
if (label) {
|
|
||||||
label.string = `答案:${config.answer || ''}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── 事件处理 ───────────────────────────────────────
|
// ─── 事件处理 ───────────────────────────────────────
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { _decorator, Node, Button, Sprite, Label, Toggle, ScrollView, EditBox, instantiate, UITransform, Vec2, EventTouch } from 'cc';
|
import { _decorator, Node, Button, Sprite, Label, Toggle, ScrollView, EditBox, instantiate, UITransform, Vec2, EventTouch } from 'cc';
|
||||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||||
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
|
import { CompletedLevelsManager } from 'db://assets/scripts/utils/CompletedLevelsManager';
|
||||||
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
import { ToastManager } from 'db://assets/scripts/utils/ToastManager';
|
||||||
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
import { ShareManager } from 'db://assets/scripts/utils/ShareManager';
|
||||||
import { StorageManager } from 'db://assets/scripts/utils/StorageManager';
|
import { StorageManager } from 'db://assets/scripts/utils/StorageManager';
|
||||||
@@ -9,28 +9,27 @@ import { WxSDK, getUserProfile } from 'db://assets/scripts/utils/WxSDK';
|
|||||||
import { AuthManager } from 'db://assets/scripts/utils/AuthManager';
|
import { AuthManager } from 'db://assets/scripts/utils/AuthManager';
|
||||||
import { API_ENDPOINTS, API_TIMEOUT } from 'db://assets/scripts/config/ApiConfig';
|
import { API_ENDPOINTS, API_TIMEOUT } from 'db://assets/scripts/config/ApiConfig';
|
||||||
import { HttpUtil } from 'db://assets/scripts/utils/HttpUtil';
|
import { HttpUtil } from 'db://assets/scripts/utils/HttpUtil';
|
||||||
|
import { ApiEnvelope } from 'db://assets/scripts/types/ApiTypes';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 布局配置
|
* 布局配置
|
||||||
* 基于实际 prefab 尺寸计算:
|
* view (ScrollView 的可视窗口) 宽 900,高 1000,anchor (0.5, 1) 顶部中点
|
||||||
* ScrollView / view 宽 900,高 1300
|
|
||||||
* ListTpl (item) 宽 300,高 400
|
* ListTpl (item) 宽 300,高 400
|
||||||
*
|
*
|
||||||
* 水平居中:2 × 300 + 1 × 40 = 640, padding_left = (900 - 640) / 2 = 130
|
* 每页 2 行 × 2 列 = 4 个关卡
|
||||||
* 垂直居中:3 × 400 + 2 × 25 = 1250, padding_top = (1300 - 1250) / 2 = 25
|
* PADDING 不再手写,由 VIEW / ITEM / SPACING 自动派生(见 _getHorizontalPadding / _getVerticalPadding),
|
||||||
|
* 保证 item 网格在 view 内始终居中。改 SPACING 时不用再算 PADDING。
|
||||||
*/
|
*/
|
||||||
const LAYOUT_CONFIG = {
|
const LAYOUT_CONFIG = {
|
||||||
COLS: 2,
|
COLS: 2,
|
||||||
ROWS: 3,
|
ROWS: 2,
|
||||||
ITEM_WIDTH: 300,
|
ITEM_WIDTH: 300,
|
||||||
ITEM_HEIGHT: 400,
|
ITEM_HEIGHT: 400,
|
||||||
SPACING_X: 40,
|
SPACING_X: 160,
|
||||||
SPACING_Y: 25,
|
SPACING_Y: 180,
|
||||||
PADDING_LEFT: 130,
|
|
||||||
PADDING_TOP: 25,
|
|
||||||
VIEW_WIDTH: 900,
|
VIEW_WIDTH: 900,
|
||||||
VIEW_HEIGHT: 1300,
|
VIEW_HEIGHT: 1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 必须选择的关卡数量 */
|
/** 必须选择的关卡数量 */
|
||||||
@@ -140,7 +139,7 @@ export class PageWriteLevels extends BaseView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onTouchStart(event: EventTouch): void {
|
private _onTouchStart(_event: EventTouch): void {
|
||||||
if (!this._scrollViewComp) return;
|
if (!this._scrollViewComp) return;
|
||||||
this._touchStartOffsetX = this._scrollViewComp.getScrollOffset().x;
|
this._touchStartOffsetX = this._scrollViewComp.getScrollOffset().x;
|
||||||
this._touchStartTime = Date.now();
|
this._touchStartTime = Date.now();
|
||||||
@@ -149,7 +148,7 @@ export class PageWriteLevels extends BaseView {
|
|||||||
/**
|
/**
|
||||||
* 触摸结束:根据滑动距离和速度决定翻页方向
|
* 触摸结束:根据滑动距离和速度决定翻页方向
|
||||||
*/
|
*/
|
||||||
private _onTouchEnd(event: EventTouch): void {
|
private _onTouchEnd(_event: EventTouch): void {
|
||||||
if (!this._scrollViewComp || this._totalPages <= 1) return;
|
if (!this._scrollViewComp || this._totalPages <= 1) return;
|
||||||
|
|
||||||
const currentOffsetX = this._scrollViewComp.getScrollOffset().x;
|
const currentOffsetX = this._scrollViewComp.getScrollOffset().x;
|
||||||
@@ -176,18 +175,27 @@ export class PageWriteLevels extends BaseView {
|
|||||||
console.log('[PageWriteLevels] onViewShow');
|
console.log('[PageWriteLevels] onViewShow');
|
||||||
// 仅首次初始化列表,从预览页返回时保留选中状态
|
// 仅首次初始化列表,从预览页返回时保留选中状态
|
||||||
if (this._itemNodes.length === 0) {
|
if (this._itemNodes.length === 0) {
|
||||||
this._initLevelList();
|
void this._initLevelList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _initLevelList(): void {
|
private async _initLevelList(): Promise<void> {
|
||||||
this._clearList();
|
this._clearList();
|
||||||
|
|
||||||
this._levelCount = LevelDataManager.instance.getLevelCount();
|
// 拉取当前用户所有已通关关卡
|
||||||
console.log('[PageWriteLevels] 关卡总数:', this._levelCount);
|
const levels = await CompletedLevelsManager.instance.fetch();
|
||||||
|
if (levels === null) {
|
||||||
|
console.warn('[PageWriteLevels] 获取已通关关卡失败');
|
||||||
|
ToastManager.instance.show('获取关卡列表失败,请稍后重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._levelCount = levels.length;
|
||||||
|
console.log('[PageWriteLevels] 已通关关卡总数:', this._levelCount);
|
||||||
|
|
||||||
if (this._levelCount === 0) {
|
if (this._levelCount === 0) {
|
||||||
console.warn('[PageWriteLevels] 没有关卡数据');
|
console.warn('[PageWriteLevels] 用户尚未通关任何关卡');
|
||||||
|
ToastManager.instance.show('还没有已通关的关卡,快去玩几关吧');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +220,25 @@ export class PageWriteLevels extends BaseView {
|
|||||||
this._selectedIndices.clear();
|
this._selectedIndices.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 水平 padding:让整行 item 在 view 宽度内居中
|
||||||
|
* padding_left = (VIEW_WIDTH - cols*ITEM_WIDTH - (cols-1)*SPACING_X) / 2
|
||||||
|
*/
|
||||||
|
private _getHorizontalPadding(): number {
|
||||||
|
const { VIEW_WIDTH, COLS, ITEM_WIDTH, SPACING_X } = LAYOUT_CONFIG;
|
||||||
|
const gridWidth = COLS * ITEM_WIDTH + (COLS - 1) * SPACING_X;
|
||||||
|
return (VIEW_WIDTH - gridWidth) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 垂直 padding:让整列 item 在 view 高度内居中
|
||||||
|
*/
|
||||||
|
private _getVerticalPadding(): number {
|
||||||
|
const { VIEW_HEIGHT, ROWS, ITEM_HEIGHT, SPACING_Y } = LAYOUT_CONFIG;
|
||||||
|
const gridHeight = ROWS * ITEM_HEIGHT + (ROWS - 1) * SPACING_Y;
|
||||||
|
return (VIEW_HEIGHT - gridHeight) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
private _updateContentSize(): void {
|
private _updateContentSize(): void {
|
||||||
if (!this.listContent) return;
|
if (!this.listContent) return;
|
||||||
|
|
||||||
@@ -221,11 +248,12 @@ export class PageWriteLevels extends BaseView {
|
|||||||
const totalWidth = this._totalPages * LAYOUT_CONFIG.VIEW_WIDTH;
|
const totalWidth = this._totalPages * LAYOUT_CONFIG.VIEW_WIDTH;
|
||||||
contentTransform.setContentSize(totalWidth, LAYOUT_CONFIG.VIEW_HEIGHT);
|
contentTransform.setContentSize(totalWidth, LAYOUT_CONFIG.VIEW_HEIGHT);
|
||||||
|
|
||||||
// anchor=(0,1),将 content 左上角对齐到 view 左上角
|
// content anchor=(0,1),view anchor=(0.5,1)。
|
||||||
|
// view 本地坐标系下,view 的左上角 = (-viewWidth/2, 0)。
|
||||||
|
// content 的 anchor 点(左上角)需要贴到 view 的左上角。
|
||||||
if (this._viewTransform) {
|
if (this._viewTransform) {
|
||||||
const viewWidth = this._viewTransform.contentSize.width;
|
const viewWidth = this._viewTransform.contentSize.width;
|
||||||
const viewHeight = this._viewTransform.contentSize.height;
|
this.listContent.setPosition(-viewWidth / 2, 0, 0);
|
||||||
this.listContent.setPosition(-viewWidth / 2, viewHeight / 2, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,12 +303,15 @@ export class PageWriteLevels extends BaseView {
|
|||||||
const col = localIndex % LAYOUT_CONFIG.COLS;
|
const col = localIndex % LAYOUT_CONFIG.COLS;
|
||||||
const row = Math.floor(localIndex / LAYOUT_CONFIG.COLS);
|
const row = Math.floor(localIndex / LAYOUT_CONFIG.COLS);
|
||||||
|
|
||||||
|
const paddingLeft = this._getHorizontalPadding();
|
||||||
|
const paddingTop = this._getVerticalPadding();
|
||||||
|
|
||||||
const x = pageIndex * LAYOUT_CONFIG.VIEW_WIDTH
|
const x = pageIndex * LAYOUT_CONFIG.VIEW_WIDTH
|
||||||
+ LAYOUT_CONFIG.PADDING_LEFT
|
+ paddingLeft
|
||||||
+ col * (LAYOUT_CONFIG.ITEM_WIDTH + LAYOUT_CONFIG.SPACING_X)
|
+ col * (LAYOUT_CONFIG.ITEM_WIDTH + LAYOUT_CONFIG.SPACING_X)
|
||||||
+ LAYOUT_CONFIG.ITEM_WIDTH / 2;
|
+ LAYOUT_CONFIG.ITEM_WIDTH / 2;
|
||||||
|
|
||||||
const y = -(LAYOUT_CONFIG.PADDING_TOP
|
const y = -(paddingTop
|
||||||
+ row * (LAYOUT_CONFIG.ITEM_HEIGHT + LAYOUT_CONFIG.SPACING_Y)
|
+ row * (LAYOUT_CONFIG.ITEM_HEIGHT + LAYOUT_CONFIG.SPACING_Y)
|
||||||
+ LAYOUT_CONFIG.ITEM_HEIGHT / 2);
|
+ LAYOUT_CONFIG.ITEM_HEIGHT / 2);
|
||||||
|
|
||||||
@@ -291,11 +322,12 @@ export class PageWriteLevels extends BaseView {
|
|||||||
* 初始化 item 的默认名称和选中状态(不设置封面,由异步加载负责)
|
* 初始化 item 的默认名称和选中状态(不设置封面,由异步加载负责)
|
||||||
*/
|
*/
|
||||||
private _initItemState(item: Node, index: number): void {
|
private _initItemState(item: Node, index: number): void {
|
||||||
|
const level = CompletedLevelsManager.instance.getByIndex(index);
|
||||||
const levelName = item.getChildByName('LevelName');
|
const levelName = item.getChildByName('LevelName');
|
||||||
if (levelName) {
|
if (levelName) {
|
||||||
const label = levelName.getComponent(Label);
|
const label = levelName.getComponent(Label);
|
||||||
if (label) {
|
if (label) {
|
||||||
label.string = `第${index + 1}关`;
|
label.string = level ? `第${level.level}关` : `第${index + 1}关`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,27 +347,20 @@ export class PageWriteLevels extends BaseView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步加载关卡资源并刷新封面图和名称。
|
* 异步加载关卡封面图并填充到 item
|
||||||
* LevelDataManager 采用懒加载,初始化时只加载了第一关图片,
|
|
||||||
* 其余关卡通过 ensureLevelReady 按需加载。
|
|
||||||
*/
|
*/
|
||||||
private async _loadAndRefreshCover(item: Node, index: number): Promise<void> {
|
private async _loadAndRefreshCover(item: Node, index: number): Promise<void> {
|
||||||
const config = await LevelDataManager.instance.ensureLevelReady(index);
|
const level = CompletedLevelsManager.instance.getByIndex(index);
|
||||||
if (!config || !item.isValid) return;
|
if (!level || !item.isValid) return;
|
||||||
|
|
||||||
|
const spriteFrame = await CompletedLevelsManager.instance.loadImage(level.image1Url);
|
||||||
|
if (!spriteFrame || !item.isValid) return;
|
||||||
|
|
||||||
const levelCover = item.getChildByName('LevelCover');
|
const levelCover = item.getChildByName('LevelCover');
|
||||||
if (levelCover) {
|
if (levelCover) {
|
||||||
const sprite = levelCover.getComponent(Sprite);
|
const sprite = levelCover.getComponent(Sprite);
|
||||||
if (sprite && config.spriteFrame) {
|
if (sprite) {
|
||||||
sprite.spriteFrame = config.spriteFrame;
|
sprite.spriteFrame = spriteFrame;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const levelName = item.getChildByName('LevelName');
|
|
||||||
if (levelName) {
|
|
||||||
const label = levelName.getComponent(Label);
|
|
||||||
if (label) {
|
|
||||||
label.string = config.name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -551,9 +576,9 @@ export class PageWriteLevels extends BaseView {
|
|||||||
const ids: string[] = [];
|
const ids: string[] = [];
|
||||||
const sortedIndices = Array.from(this._selectedIndices).sort((a, b) => a - b);
|
const sortedIndices = Array.from(this._selectedIndices).sort((a, b) => a - b);
|
||||||
for (const index of sortedIndices) {
|
for (const index of sortedIndices) {
|
||||||
const config = LevelDataManager.instance.getLevelConfig(index);
|
const level = CompletedLevelsManager.instance.getByIndex(index);
|
||||||
if (config) {
|
if (level) {
|
||||||
ids.push(config.id);
|
ids.push(level.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ids;
|
return ids;
|
||||||
@@ -589,7 +614,7 @@ export class PageWriteLevels extends BaseView {
|
|||||||
StorageManager.setUserInfo(userInfo);
|
StorageManager.setUserInfo(userInfo);
|
||||||
|
|
||||||
// 上传到服务端
|
// 上传到服务端
|
||||||
const response = await HttpUtil.post(
|
const response = await HttpUtil.post<ApiEnvelope<unknown>>(
|
||||||
API_ENDPOINTS.USER_INFO,
|
API_ENDPOINTS.USER_INFO,
|
||||||
{
|
{
|
||||||
userId: userId,
|
userId: userId,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { _decorator, Node, Label, AudioClip, AudioSource, view, UITransform, Size } from 'cc';
|
import { _decorator, Node, Label, AudioClip, AudioSource, view, UITransform, Size, ProgressBar } from 'cc';
|
||||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
import { BaseModal } from 'db://assets/scripts/core/BaseModal';
|
||||||
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
|
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
@@ -13,12 +13,23 @@ export interface PassModalCallbacks {
|
|||||||
onShare?: () => void;
|
onShare?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PassModalTitleInfo {
|
||||||
|
titleText?: string;
|
||||||
|
nextTitleProgress?: number;
|
||||||
|
progressText?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PassModalParams {
|
||||||
|
levelIndex?: number;
|
||||||
|
titleInfo?: PassModalTitleInfo;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通关弹窗组件
|
* 通关弹窗组件
|
||||||
* 继承 BaseView,显示通关成功弹窗,提供"下一关"和"分享给好友"两个按钮
|
* 继承 BaseModal,显示通关成功弹窗,提供"下一关"和"分享给好友"两个按钮
|
||||||
*/
|
*/
|
||||||
@ccclass('PassModal')
|
@ccclass('PassModal')
|
||||||
export class PassModal extends BaseView {
|
export class PassModal extends BaseModal {
|
||||||
/** 静态常量:弹窗层级 */
|
/** 静态常量:弹窗层级 */
|
||||||
public static readonly MODAL_Z_INDEX = 999;
|
public static readonly MODAL_Z_INDEX = 999;
|
||||||
|
|
||||||
@@ -30,9 +41,17 @@ export class PassModal extends BaseView {
|
|||||||
@property(Node)
|
@property(Node)
|
||||||
shareButton: Node | null = null;
|
shareButton: Node | null = null;
|
||||||
|
|
||||||
/** 提示Label(如 +1 生命) */
|
/** 称号文字 */
|
||||||
@property(Label)
|
@property(Label)
|
||||||
tipLabel: Label | null = null;
|
titleLevelLabel: Label | null = null;
|
||||||
|
|
||||||
|
/** 距离下一个称号的进度 */
|
||||||
|
@property(ProgressBar)
|
||||||
|
titleProgressBar: ProgressBar | null = null;
|
||||||
|
|
||||||
|
/** 进度提示文案 */
|
||||||
|
@property(Label)
|
||||||
|
progressLabel: Label | null = null;
|
||||||
|
|
||||||
/** 通关音效 */
|
/** 通关音效 */
|
||||||
@property(AudioClip)
|
@property(AudioClip)
|
||||||
@@ -44,6 +63,21 @@ export class PassModal extends BaseView {
|
|||||||
/** 缓存的屏幕尺寸 */
|
/** 缓存的屏幕尺寸 */
|
||||||
private _screenSize: Size | null = null;
|
private _screenSize: Size | null = null;
|
||||||
|
|
||||||
|
/** 称号展示数据 */
|
||||||
|
private _titleInfo: PassModalTitleInfo = {
|
||||||
|
titleText: '冷场小白1级',
|
||||||
|
nextTitleProgress: 0,
|
||||||
|
progressText: '还差3题获得冷场小白2级'
|
||||||
|
};
|
||||||
|
|
||||||
|
setParams(params: PassModalParams): void {
|
||||||
|
super.setParams(params);
|
||||||
|
|
||||||
|
if (params?.titleInfo) {
|
||||||
|
this.setTitleInfo(params.titleInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置回调函数
|
* 设置回调函数
|
||||||
*/
|
*/
|
||||||
@@ -51,6 +85,17 @@ export class PassModal extends BaseView {
|
|||||||
this._callbacks = callbacks;
|
this._callbacks = callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置称号体系展示数据
|
||||||
|
*/
|
||||||
|
setTitleInfo(titleInfo: PassModalTitleInfo): void {
|
||||||
|
this._titleInfo = {
|
||||||
|
...this._titleInfo,
|
||||||
|
...titleInfo
|
||||||
|
};
|
||||||
|
this._updateTitleInfo();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 页面首次加载时调用
|
* 页面首次加载时调用
|
||||||
*/
|
*/
|
||||||
@@ -63,7 +108,9 @@ export class PassModal extends BaseView {
|
|||||||
* 页面每次显示时调用
|
* 页面每次显示时调用
|
||||||
*/
|
*/
|
||||||
onViewShow(): void {
|
onViewShow(): void {
|
||||||
|
super.onViewShow();
|
||||||
this._updateWidget();
|
this._updateWidget();
|
||||||
|
this._updateTitleInfo();
|
||||||
this._playSuccessSound();
|
this._playSuccessSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +176,37 @@ export class PassModal extends BaseView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新称号体系核心变量
|
||||||
|
*/
|
||||||
|
private _updateTitleInfo(): void {
|
||||||
|
if (this.titleLevelLabel && this._titleInfo.titleText !== undefined) {
|
||||||
|
this.titleLevelLabel.string = this._titleInfo.titleText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.titleProgressBar && this._titleInfo.nextTitleProgress !== undefined) {
|
||||||
|
this.titleProgressBar.progress = this._normalizeProgress(this._titleInfo.nextTitleProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.progressLabel && this._titleInfo.progressText !== undefined) {
|
||||||
|
this.progressLabel.string = this._titleInfo.progressText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规范化进度值
|
||||||
|
* 九宫格 Bar 的 Left+Right border = 240px,totalLength = 925px
|
||||||
|
* 当 width < 240px 时圆角会畸变,因此 progress > 0 时强制最小值
|
||||||
|
*/
|
||||||
|
private _normalizeProgress(progress: number): number {
|
||||||
|
if (!Number.isFinite(progress) || progress <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MIN_PROGRESS = 240 / 925;
|
||||||
|
return Math.max(MIN_PROGRESS, Math.min(1, progress));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下一关按钮点击
|
* 下一关按钮点击
|
||||||
*/
|
*/
|
||||||
|
|||||||
47
assets/prefabs/PreviewLevelItem.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { _decorator, Component, Node, Sprite, Label, SpriteFrame } from 'cc';
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预览页单个关卡 item 的视图组件
|
||||||
|
* 挂在 PagePreviewLevels 的 listTemplate 根节点上,由编辑器拖拽绑定子节点。
|
||||||
|
* instantiate 克隆 item 时,Cocos 会把这些 Node 引用自动重映射到克隆后的子节点,
|
||||||
|
* 所以每个 item 拿到的都是自己的封面/标签引用,与节点层级/命名解耦。
|
||||||
|
*/
|
||||||
|
@ccclass('PreviewLevelItem')
|
||||||
|
export class PreviewLevelItem extends Component {
|
||||||
|
@property({ type: Sprite, tooltip: '封面图 Sprite' })
|
||||||
|
levelCover: Sprite | null = null;
|
||||||
|
|
||||||
|
@property({ type: Label, tooltip: '答案 Label' })
|
||||||
|
answerLabel: Label | null = null;
|
||||||
|
|
||||||
|
@property({ type: Label, tooltip: '线索1 Label' })
|
||||||
|
tips1Label: Label | null = null;
|
||||||
|
|
||||||
|
@property({ type: Label, tooltip: '线索2 Label' })
|
||||||
|
tips2Label: Label | null = null;
|
||||||
|
|
||||||
|
@property({ type: Label, tooltip: '线索3 Label' })
|
||||||
|
tips3Label: Label | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一次性设置所有文本字段
|
||||||
|
*/
|
||||||
|
setTexts(opts: {
|
||||||
|
answer: string;
|
||||||
|
hint1: string;
|
||||||
|
hint2: string;
|
||||||
|
hint3: string;
|
||||||
|
}): void {
|
||||||
|
if (this.answerLabel) this.answerLabel.string = `答案:${opts.answer}`;
|
||||||
|
if (this.tips1Label) this.tips1Label.string = `线索一:${opts.hint1}`;
|
||||||
|
if (this.tips2Label) this.tips2Label.string = `线索二:${opts.hint2}`;
|
||||||
|
if (this.tips3Label) this.tips3Label.string = `线索三:${opts.hint3}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCover(spriteFrame: SpriteFrame | null): void {
|
||||||
|
if (this.levelCover && spriteFrame) {
|
||||||
|
this.levelCover.spriteFrame = spriteFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"ver": "4.0.24",
|
"ver": "4.0.24",
|
||||||
"importer": "typescript",
|
"importer": "typescript",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "ddba71db-75ed-468d-ac99-b4632c0b2ae4",
|
"uuid": "5fb357ec-a670-4fff-a5cd-f47f1a2d8ea3",
|
||||||
"files": [],
|
"files": [],
|
||||||
"subMetas": {},
|
"subMetas": {},
|
||||||
"userData": {}
|
"userData": {}
|
||||||
2845
assets/prefabs/TimeoutModal.prefab
Normal file
13
assets/prefabs/TimeoutModal.prefab.meta
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.50",
|
||||||
|
"importer": "prefab",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "e41c722f-f605-47f7-9ce4-abff0ed2020f",
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"syncNodeName": "TimeoutModal"
|
||||||
|
}
|
||||||
|
}
|
||||||
162
assets/prefabs/TimeoutModal.ts
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
import { _decorator, Node, view, UITransform, Size } from 'cc';
|
||||||
|
import { BaseModal } from 'db://assets/scripts/core/BaseModal';
|
||||||
|
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TimeoutModal 回调接口
|
||||||
|
*/
|
||||||
|
export interface TimeoutModalCallbacks {
|
||||||
|
/** 点击求助好友回调 */
|
||||||
|
onShare?: () => void;
|
||||||
|
/** 点击再次挑战回调 */
|
||||||
|
onRestart?: () => void;
|
||||||
|
/** 点击返回主页 / 关闭按钮回调 */
|
||||||
|
onHome?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TimeoutModalParams {
|
||||||
|
levelIndex?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间耗尽弹窗组件
|
||||||
|
* 继承 BaseModal,显示倒计时结束提示,提供"求助好友"、"再次挑战"和"返回主页"三个按钮
|
||||||
|
*/
|
||||||
|
@ccclass('TimeoutModal')
|
||||||
|
export class TimeoutModal extends BaseModal {
|
||||||
|
/** 静态常量:弹窗层级 */
|
||||||
|
public static readonly MODAL_Z_INDEX = 999;
|
||||||
|
|
||||||
|
/** 关闭按钮 */
|
||||||
|
@property(Node)
|
||||||
|
closeBtn: Node | null = null;
|
||||||
|
|
||||||
|
/** 求助好友按钮 */
|
||||||
|
@property(Node)
|
||||||
|
buttonShare: Node | null = null;
|
||||||
|
|
||||||
|
/** 再次挑战按钮 */
|
||||||
|
@property(Node)
|
||||||
|
buttonRestart: Node | null = null;
|
||||||
|
|
||||||
|
/** 返回主页按钮 */
|
||||||
|
@property(Node)
|
||||||
|
buttonHome: Node | null = null;
|
||||||
|
|
||||||
|
/** 回调函数 */
|
||||||
|
private _callbacks: TimeoutModalCallbacks = {};
|
||||||
|
|
||||||
|
/** 缓存的屏幕尺寸 */
|
||||||
|
private _screenSize: Size | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置回调函数
|
||||||
|
*/
|
||||||
|
setCallbacks(callbacks: TimeoutModalCallbacks): void {
|
||||||
|
this._callbacks = callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面首次加载时调用
|
||||||
|
*/
|
||||||
|
onViewLoad(): void {
|
||||||
|
console.log('[TimeoutModal] onViewLoad');
|
||||||
|
this._bindButtonEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面每次显示时调用
|
||||||
|
*/
|
||||||
|
onViewShow(): void {
|
||||||
|
super.onViewShow();
|
||||||
|
this._updateWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面销毁时调用
|
||||||
|
*/
|
||||||
|
onViewDestroy(): void {
|
||||||
|
this._unbindButtonEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置弹窗尺寸为全屏
|
||||||
|
*/
|
||||||
|
private _updateWidget(): void {
|
||||||
|
if (!this._screenSize) {
|
||||||
|
this._screenSize = view.getVisibleSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const uiTransform = this.node.getComponent(UITransform);
|
||||||
|
if (uiTransform) {
|
||||||
|
uiTransform.setContentSize(this._screenSize.width, this._screenSize.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定按钮事件
|
||||||
|
*/
|
||||||
|
private _bindButtonEvents(): void {
|
||||||
|
if (this.closeBtn) {
|
||||||
|
this.closeBtn.on(Node.EventType.TOUCH_END, this._onHomeClick, this);
|
||||||
|
}
|
||||||
|
if (this.buttonShare) {
|
||||||
|
this.buttonShare.on(Node.EventType.TOUCH_END, this._onShareClick, this);
|
||||||
|
}
|
||||||
|
if (this.buttonRestart) {
|
||||||
|
this.buttonRestart.on(Node.EventType.TOUCH_END, this._onRestartClick, this);
|
||||||
|
}
|
||||||
|
if (this.buttonHome) {
|
||||||
|
this.buttonHome.on(Node.EventType.TOUCH_END, this._onHomeClick, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解除按钮事件绑定
|
||||||
|
*/
|
||||||
|
private _unbindButtonEvents(): void {
|
||||||
|
if (this.closeBtn && this.closeBtn.isValid) {
|
||||||
|
this.closeBtn.off(Node.EventType.TOUCH_END, this._onHomeClick, this);
|
||||||
|
}
|
||||||
|
if (this.buttonShare && this.buttonShare.isValid) {
|
||||||
|
this.buttonShare.off(Node.EventType.TOUCH_END, this._onShareClick, this);
|
||||||
|
}
|
||||||
|
if (this.buttonRestart && this.buttonRestart.isValid) {
|
||||||
|
this.buttonRestart.off(Node.EventType.TOUCH_END, this._onRestartClick, this);
|
||||||
|
}
|
||||||
|
if (this.buttonHome && this.buttonHome.isValid) {
|
||||||
|
this.buttonHome.off(Node.EventType.TOUCH_END, this._onHomeClick, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 求助好友按钮点击
|
||||||
|
*/
|
||||||
|
private _onShareClick(): void {
|
||||||
|
console.log('[TimeoutModal] 点击求助好友');
|
||||||
|
|
||||||
|
WxSDK.shareAppMessage({
|
||||||
|
title: '这道题太难了,快来帮帮我!',
|
||||||
|
query: `level=${this._params?.levelIndex ?? 1}`
|
||||||
|
});
|
||||||
|
|
||||||
|
this._callbacks.onShare?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 再次挑战按钮点击
|
||||||
|
*/
|
||||||
|
private _onRestartClick(): void {
|
||||||
|
console.log('[TimeoutModal] 点击再次挑战');
|
||||||
|
this._callbacks.onRestart?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回主页 / 关闭按钮点击
|
||||||
|
*/
|
||||||
|
private _onHomeClick(): void {
|
||||||
|
console.log('[TimeoutModal] 点击返回主页');
|
||||||
|
this._callbacks.onHome?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
9
assets/prefabs/TimeoutModal.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "bdb18473-6efb-4592-bf67-48555845eec5",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
1776
assets/prefabs/WrongModal.prefab
Normal file
13
assets/prefabs/WrongModal.prefab.meta
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.50",
|
||||||
|
"importer": "prefab",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "455c7845-d090-4cd9-aeb4-1f5cad616bb5",
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"syncNodeName": "WrongModal"
|
||||||
|
}
|
||||||
|
}
|
||||||
111
assets/prefabs/WrongModal.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import { _decorator, Node, view, UITransform, Size } from 'cc';
|
||||||
|
import { BaseModal } from 'db://assets/scripts/core/BaseModal';
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WrongModal 回调接口
|
||||||
|
*/
|
||||||
|
export interface WrongModalCallbacks {
|
||||||
|
/** 点击继续挑战 / 关闭按钮回调 */
|
||||||
|
onContinue?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 答案错误弹窗组件
|
||||||
|
* 继承 BaseModal,显示答案错误提示,提供"继续挑战"和关闭按钮
|
||||||
|
*/
|
||||||
|
@ccclass('WrongModal')
|
||||||
|
export class WrongModal extends BaseModal {
|
||||||
|
/** 静态常量:弹窗层级 */
|
||||||
|
public static readonly MODAL_Z_INDEX = 999;
|
||||||
|
|
||||||
|
/** 关闭按钮 */
|
||||||
|
@property(Node)
|
||||||
|
closeBtn: Node | null = null;
|
||||||
|
|
||||||
|
/** 继续挑战按钮 */
|
||||||
|
@property(Node)
|
||||||
|
buttonHint: Node | null = null;
|
||||||
|
|
||||||
|
/** 回调函数 */
|
||||||
|
private _callbacks: WrongModalCallbacks = {};
|
||||||
|
|
||||||
|
/** 缓存的屏幕尺寸 */
|
||||||
|
private _screenSize: Size | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置回调函数
|
||||||
|
*/
|
||||||
|
setCallbacks(callbacks: WrongModalCallbacks): void {
|
||||||
|
this._callbacks = callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面首次加载时调用
|
||||||
|
*/
|
||||||
|
onViewLoad(): void {
|
||||||
|
console.log('[WrongModal] onViewLoad');
|
||||||
|
this._bindButtonEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面每次显示时调用
|
||||||
|
*/
|
||||||
|
onViewShow(): void {
|
||||||
|
super.onViewShow();
|
||||||
|
this._updateWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面销毁时调用
|
||||||
|
*/
|
||||||
|
onViewDestroy(): void {
|
||||||
|
this._unbindButtonEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置弹窗尺寸为全屏
|
||||||
|
*/
|
||||||
|
private _updateWidget(): void {
|
||||||
|
if (!this._screenSize) {
|
||||||
|
this._screenSize = view.getVisibleSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const uiTransform = this.node.getComponent(UITransform);
|
||||||
|
if (uiTransform) {
|
||||||
|
uiTransform.setContentSize(this._screenSize.width, this._screenSize.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定按钮事件
|
||||||
|
*/
|
||||||
|
private _bindButtonEvents(): void {
|
||||||
|
if (this.closeBtn) {
|
||||||
|
this.closeBtn.on(Node.EventType.TOUCH_END, this._onContinueClick, this);
|
||||||
|
}
|
||||||
|
if (this.buttonHint) {
|
||||||
|
this.buttonHint.on(Node.EventType.TOUCH_END, this._onContinueClick, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解除按钮事件绑定
|
||||||
|
*/
|
||||||
|
private _unbindButtonEvents(): void {
|
||||||
|
if (this.closeBtn && this.closeBtn.isValid) {
|
||||||
|
this.closeBtn.off(Node.EventType.TOUCH_END, this._onContinueClick, this);
|
||||||
|
}
|
||||||
|
if (this.buttonHint && this.buttonHint.isValid) {
|
||||||
|
this.buttonHint.off(Node.EventType.TOUCH_END, this._onContinueClick, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 继续挑战 / 关闭按钮点击
|
||||||
|
*/
|
||||||
|
private _onContinueClick(): void {
|
||||||
|
console.log('[WrongModal] 点击继续挑战');
|
||||||
|
this._callbacks.onContinue?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
9
assets/prefabs/WrongModal.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "972c57fc-10e7-493e-a1da-4849f3c1e555",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/BarStam.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
134
assets/resources/images/BarStam.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "85f4694c-9bb3-4a86-b961-6dbe12154989",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "85f4694c-9bb3-4a86-b961-6dbe12154989@6c48a",
|
||||||
|
"displayName": "BarStam",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "85f4694c-9bb3-4a86-b961-6dbe12154989",
|
||||||
|
"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": "85f4694c-9bb3-4a86-b961-6dbe12154989@f9941",
|
||||||
|
"displayName": "BarStam",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0.5,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 208,
|
||||||
|
"height": 81,
|
||||||
|
"rawWidth": 208,
|
||||||
|
"rawHeight": 82,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-104,
|
||||||
|
-40.5,
|
||||||
|
0,
|
||||||
|
104,
|
||||||
|
-40.5,
|
||||||
|
0,
|
||||||
|
-104,
|
||||||
|
40.5,
|
||||||
|
0,
|
||||||
|
104,
|
||||||
|
40.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
82,
|
||||||
|
208,
|
||||||
|
82,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
208,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0.012195121951219513,
|
||||||
|
1,
|
||||||
|
0.012195121951219513,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-104,
|
||||||
|
-40.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
104,
|
||||||
|
40.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "85f4694c-9bb3-4a86-b961-6dbe12154989@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "85f4694c-9bb3-4a86-b961-6dbe12154989@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/Bg.jpg
Normal file
|
After Width: | Height: | Size: 212 KiB |
134
assets/resources/images/Bg.jpg.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "10047f2e-bf2c-46f0-ba98-6fc23cf7ea87",
|
||||||
|
"files": [
|
||||||
|
".jpg",
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "10047f2e-bf2c-46f0-ba98-6fc23cf7ea87@6c48a",
|
||||||
|
"displayName": "Bg",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "10047f2e-bf2c-46f0-ba98-6fc23cf7ea87",
|
||||||
|
"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": "10047f2e-bf2c-46f0-ba98-6fc23cf7ea87@f9941",
|
||||||
|
"displayName": "Bg",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 1376,
|
||||||
|
"height": 3064,
|
||||||
|
"rawWidth": 1376,
|
||||||
|
"rawHeight": 3064,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-688,
|
||||||
|
-1532,
|
||||||
|
0,
|
||||||
|
688,
|
||||||
|
-1532,
|
||||||
|
0,
|
||||||
|
-688,
|
||||||
|
1532,
|
||||||
|
0,
|
||||||
|
688,
|
||||||
|
1532,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
3064,
|
||||||
|
1376,
|
||||||
|
3064,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1376,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-688,
|
||||||
|
-1532,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
688,
|
||||||
|
1532,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "10047f2e-bf2c-46f0-ba98-6fc23cf7ea87@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": false,
|
||||||
|
"redirect": "10047f2e-bf2c-46f0-ba98-6fc23cf7ea87@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 26 KiB |
BIN
assets/resources/images/ButtonSetting.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
134
assets/resources/images/ButtonSetting.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "7a8edfce-b0ad-41b3-8dc9-ec1c1ee22153",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "7a8edfce-b0ad-41b3-8dc9-ec1c1ee22153@6c48a",
|
||||||
|
"displayName": "ButtonSetting",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "7a8edfce-b0ad-41b3-8dc9-ec1c1ee22153",
|
||||||
|
"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": "7a8edfce-b0ad-41b3-8dc9-ec1c1ee22153@f9941",
|
||||||
|
"displayName": "ButtonSetting",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 115,
|
||||||
|
"height": 123,
|
||||||
|
"rawWidth": 115,
|
||||||
|
"rawHeight": 123,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-57.5,
|
||||||
|
-61.5,
|
||||||
|
0,
|
||||||
|
57.5,
|
||||||
|
-61.5,
|
||||||
|
0,
|
||||||
|
-57.5,
|
||||||
|
61.5,
|
||||||
|
0,
|
||||||
|
57.5,
|
||||||
|
61.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
123,
|
||||||
|
115,
|
||||||
|
123,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
115,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-57.5,
|
||||||
|
-61.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
57.5,
|
||||||
|
61.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "7a8edfce-b0ad-41b3-8dc9-ec1c1ee22153@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "7a8edfce-b0ad-41b3-8dc9-ec1c1ee22153@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
9
assets/resources/images/FlatIcon.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.2.0",
|
||||||
|
"importer": "directory",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "a6e360cb-d0cd-4f57-9e43-10b13f6f0d11",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/FlatIcon/flatIconHelp.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
@@ -2,7 +2,7 @@
|
|||||||
"ver": "1.0.27",
|
"ver": "1.0.27",
|
||||||
"importer": "image",
|
"importer": "image",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "010e6809-3636-4c23-8403-1424c771f0f8",
|
"uuid": "69f85753-6740-4686-ba40-5d2383292f39",
|
||||||
"files": [
|
"files": [
|
||||||
".json",
|
".json",
|
||||||
".png"
|
".png"
|
||||||
@@ -10,14 +10,14 @@
|
|||||||
"subMetas": {
|
"subMetas": {
|
||||||
"6c48a": {
|
"6c48a": {
|
||||||
"importer": "texture",
|
"importer": "texture",
|
||||||
"uuid": "010e6809-3636-4c23-8403-1424c771f0f8@6c48a",
|
"uuid": "69f85753-6740-4686-ba40-5d2383292f39@6c48a",
|
||||||
"displayName": "startGame",
|
"displayName": "flatIconHelp",
|
||||||
"id": "6c48a",
|
"id": "6c48a",
|
||||||
"name": "texture",
|
"name": "texture",
|
||||||
"userData": {
|
"userData": {
|
||||||
"wrapModeS": "clamp-to-edge",
|
"wrapModeS": "clamp-to-edge",
|
||||||
"wrapModeT": "clamp-to-edge",
|
"wrapModeT": "clamp-to-edge",
|
||||||
"imageUuidOrDatabaseUri": "010e6809-3636-4c23-8403-1424c771f0f8",
|
"imageUuidOrDatabaseUri": "69f85753-6740-4686-ba40-5d2383292f39",
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"minfilter": "linear",
|
"minfilter": "linear",
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
},
|
},
|
||||||
"f9941": {
|
"f9941": {
|
||||||
"importer": "sprite-frame",
|
"importer": "sprite-frame",
|
||||||
"uuid": "010e6809-3636-4c23-8403-1424c771f0f8@f9941",
|
"uuid": "69f85753-6740-4686-ba40-5d2383292f39@f9941",
|
||||||
"displayName": "startGame",
|
"displayName": "flatIconHelp",
|
||||||
"id": "f9941",
|
"id": "f9941",
|
||||||
"name": "spriteFrame",
|
"name": "spriteFrame",
|
||||||
"userData": {
|
"userData": {
|
||||||
@@ -45,10 +45,10 @@
|
|||||||
"offsetY": 0,
|
"offsetY": 0,
|
||||||
"trimX": 0,
|
"trimX": 0,
|
||||||
"trimY": 0,
|
"trimY": 0,
|
||||||
"width": 216,
|
"width": 468,
|
||||||
"height": 107,
|
"height": 468,
|
||||||
"rawWidth": 216,
|
"rawWidth": 468,
|
||||||
"rawHeight": 107,
|
"rawHeight": 468,
|
||||||
"borderTop": 0,
|
"borderTop": 0,
|
||||||
"borderBottom": 0,
|
"borderBottom": 0,
|
||||||
"borderLeft": 0,
|
"borderLeft": 0,
|
||||||
@@ -60,17 +60,17 @@
|
|||||||
"meshType": 0,
|
"meshType": 0,
|
||||||
"vertices": {
|
"vertices": {
|
||||||
"rawPosition": [
|
"rawPosition": [
|
||||||
-108,
|
-234,
|
||||||
-53.5,
|
-234,
|
||||||
0,
|
0,
|
||||||
108,
|
234,
|
||||||
-53.5,
|
-234,
|
||||||
0,
|
0,
|
||||||
-108,
|
-234,
|
||||||
53.5,
|
234,
|
||||||
0,
|
0,
|
||||||
108,
|
234,
|
||||||
53.5,
|
234,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"indexes": [
|
"indexes": [
|
||||||
@@ -83,12 +83,12 @@
|
|||||||
],
|
],
|
||||||
"uv": [
|
"uv": [
|
||||||
0,
|
0,
|
||||||
107,
|
468,
|
||||||
216,
|
468,
|
||||||
107,
|
468,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
216,
|
468,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"nuv": [
|
"nuv": [
|
||||||
@@ -102,18 +102,18 @@
|
|||||||
1
|
1
|
||||||
],
|
],
|
||||||
"minPos": [
|
"minPos": [
|
||||||
-108,
|
-234,
|
||||||
-53.5,
|
-234,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"maxPos": [
|
"maxPos": [
|
||||||
108,
|
234,
|
||||||
53.5,
|
234,
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"imageUuidOrDatabaseUri": "010e6809-3636-4c23-8403-1424c771f0f8@6c48a",
|
"imageUuidOrDatabaseUri": "69f85753-6740-4686-ba40-5d2383292f39@6c48a",
|
||||||
"atlasUuid": "",
|
"atlasUuid": "",
|
||||||
"trimType": "auto"
|
"trimType": "auto"
|
||||||
},
|
},
|
||||||
@@ -129,6 +129,6 @@
|
|||||||
"type": "sprite-frame",
|
"type": "sprite-frame",
|
||||||
"fixAlphaTransparencyArtifacts": false,
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
"hasAlpha": true,
|
"hasAlpha": true,
|
||||||
"redirect": "010e6809-3636-4c23-8403-1424c771f0f8@6c48a"
|
"redirect": "69f85753-6740-4686-ba40-5d2383292f39@6c48a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
assets/resources/images/FlatIcon/flatIconHome.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
134
assets/resources/images/FlatIcon/flatIconHome.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "fb73de29-d734-4eb4-853d-8cbdbb18a9c9",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "fb73de29-d734-4eb4-853d-8cbdbb18a9c9@6c48a",
|
||||||
|
"displayName": "flatIconHome",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "fb73de29-d734-4eb4-853d-8cbdbb18a9c9",
|
||||||
|
"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": "fb73de29-d734-4eb4-853d-8cbdbb18a9c9@f9941",
|
||||||
|
"displayName": "flatIconHome",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 427,
|
||||||
|
"height": 427,
|
||||||
|
"rawWidth": 427,
|
||||||
|
"rawHeight": 427,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-213.5,
|
||||||
|
-213.5,
|
||||||
|
0,
|
||||||
|
213.5,
|
||||||
|
-213.5,
|
||||||
|
0,
|
||||||
|
-213.5,
|
||||||
|
213.5,
|
||||||
|
0,
|
||||||
|
213.5,
|
||||||
|
213.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
427,
|
||||||
|
427,
|
||||||
|
427,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
427,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-213.5,
|
||||||
|
-213.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
213.5,
|
||||||
|
213.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "fb73de29-d734-4eb4-853d-8cbdbb18a9c9@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "fb73de29-d734-4eb4-853d-8cbdbb18a9c9@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/FlatIcon/flatIconNext.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
134
assets/resources/images/FlatIcon/flatIconNext.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "1c8a9e95-7b00-4e59-a0a2-72a4aa97c03c",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "1c8a9e95-7b00-4e59-a0a2-72a4aa97c03c@6c48a",
|
||||||
|
"displayName": "flatIconNext",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "1c8a9e95-7b00-4e59-a0a2-72a4aa97c03c",
|
||||||
|
"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": "1c8a9e95-7b00-4e59-a0a2-72a4aa97c03c@f9941",
|
||||||
|
"displayName": "flatIconNext",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 13.5,
|
||||||
|
"offsetY": -0.5,
|
||||||
|
"trimX": 82,
|
||||||
|
"trimY": 29,
|
||||||
|
"width": 375,
|
||||||
|
"height": 455,
|
||||||
|
"rawWidth": 512,
|
||||||
|
"rawHeight": 512,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-187.5,
|
||||||
|
-227.5,
|
||||||
|
0,
|
||||||
|
187.5,
|
||||||
|
-227.5,
|
||||||
|
0,
|
||||||
|
-187.5,
|
||||||
|
227.5,
|
||||||
|
0,
|
||||||
|
187.5,
|
||||||
|
227.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
82,
|
||||||
|
483,
|
||||||
|
457,
|
||||||
|
483,
|
||||||
|
82,
|
||||||
|
28,
|
||||||
|
457,
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0.16015625,
|
||||||
|
0.0546875,
|
||||||
|
0.892578125,
|
||||||
|
0.0546875,
|
||||||
|
0.16015625,
|
||||||
|
0.943359375,
|
||||||
|
0.892578125,
|
||||||
|
0.943359375
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-187.5,
|
||||||
|
-227.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
187.5,
|
||||||
|
227.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "1c8a9e95-7b00-4e59-a0a2-72a4aa97c03c@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "1c8a9e95-7b00-4e59-a0a2-72a4aa97c03c@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/FlatIcon/flatIconRestart.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
134
assets/resources/images/FlatIcon/flatIconRestart.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "c24760c9-312a-4638-ae56-6422010d93d0",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "c24760c9-312a-4638-ae56-6422010d93d0@6c48a",
|
||||||
|
"displayName": "flatIconRestart",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "c24760c9-312a-4638-ae56-6422010d93d0",
|
||||||
|
"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": "c24760c9-312a-4638-ae56-6422010d93d0@f9941",
|
||||||
|
"displayName": "flatIconRestart",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 490,
|
||||||
|
"height": 492,
|
||||||
|
"rawWidth": 490,
|
||||||
|
"rawHeight": 492,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-245,
|
||||||
|
-246,
|
||||||
|
0,
|
||||||
|
245,
|
||||||
|
-246,
|
||||||
|
0,
|
||||||
|
-245,
|
||||||
|
246,
|
||||||
|
0,
|
||||||
|
245,
|
||||||
|
246,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
492,
|
||||||
|
490,
|
||||||
|
492,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
490,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-245,
|
||||||
|
-246,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
245,
|
||||||
|
246,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "c24760c9-312a-4638-ae56-6422010d93d0@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "c24760c9-312a-4638-ae56-6422010d93d0@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/FlatIcon/flatIconShare.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
134
assets/resources/images/FlatIcon/flatIconShare.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "b9bec232-3d37-48a0-9ca8-62aab6c4083b",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "b9bec232-3d37-48a0-9ca8-62aab6c4083b@6c48a",
|
||||||
|
"displayName": "flatIconShare",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "b9bec232-3d37-48a0-9ca8-62aab6c4083b",
|
||||||
|
"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": "b9bec232-3d37-48a0-9ca8-62aab6c4083b@f9941",
|
||||||
|
"displayName": "flatIconShare",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 22,
|
||||||
|
"trimY": 11,
|
||||||
|
"width": 468,
|
||||||
|
"height": 490,
|
||||||
|
"rawWidth": 512,
|
||||||
|
"rawHeight": 512,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-234,
|
||||||
|
-245,
|
||||||
|
0,
|
||||||
|
234,
|
||||||
|
-245,
|
||||||
|
0,
|
||||||
|
-234,
|
||||||
|
245,
|
||||||
|
0,
|
||||||
|
234,
|
||||||
|
245,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
22,
|
||||||
|
501,
|
||||||
|
490,
|
||||||
|
501,
|
||||||
|
22,
|
||||||
|
11,
|
||||||
|
490,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0.04296875,
|
||||||
|
0.021484375,
|
||||||
|
0.95703125,
|
||||||
|
0.021484375,
|
||||||
|
0.04296875,
|
||||||
|
0.978515625,
|
||||||
|
0.95703125,
|
||||||
|
0.978515625
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-234,
|
||||||
|
-245,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
234,
|
||||||
|
245,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "b9bec232-3d37-48a0-9ca8-62aab6c4083b@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "b9bec232-3d37-48a0-9ca8-62aab6c4083b@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/FlatIcon/flatIconView.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
134
assets/resources/images/FlatIcon/flatIconView.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "cf6809c4-f69b-4107-9b50-bd692766213a",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "cf6809c4-f69b-4107-9b50-bd692766213a@6c48a",
|
||||||
|
"displayName": "flatIconView",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "cf6809c4-f69b-4107-9b50-bd692766213a",
|
||||||
|
"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": "cf6809c4-f69b-4107-9b50-bd692766213a@f9941",
|
||||||
|
"displayName": "flatIconView",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 27,
|
||||||
|
"trimY": 80,
|
||||||
|
"width": 458,
|
||||||
|
"height": 352,
|
||||||
|
"rawWidth": 512,
|
||||||
|
"rawHeight": 512,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-229,
|
||||||
|
-176,
|
||||||
|
0,
|
||||||
|
229,
|
||||||
|
-176,
|
||||||
|
0,
|
||||||
|
-229,
|
||||||
|
176,
|
||||||
|
0,
|
||||||
|
229,
|
||||||
|
176,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
27,
|
||||||
|
432,
|
||||||
|
485,
|
||||||
|
432,
|
||||||
|
27,
|
||||||
|
80,
|
||||||
|
485,
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0.052734375,
|
||||||
|
0.15625,
|
||||||
|
0.947265625,
|
||||||
|
0.15625,
|
||||||
|
0.052734375,
|
||||||
|
0.84375,
|
||||||
|
0.947265625,
|
||||||
|
0.84375
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-229,
|
||||||
|
-176,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
229,
|
||||||
|
176,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "cf6809c4-f69b-4107-9b50-bd692766213a@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "cf6809c4-f69b-4107-9b50-bd692766213a@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/IconAd.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
@@ -2,7 +2,7 @@
|
|||||||
"ver": "1.0.27",
|
"ver": "1.0.27",
|
||||||
"importer": "image",
|
"importer": "image",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "a34c93d2-cae0-42d4-a2eb-c3155052ad20",
|
"uuid": "5a832eca-5c6c-4fbc-9218-bf5aae721934",
|
||||||
"files": [
|
"files": [
|
||||||
".json",
|
".json",
|
||||||
".png"
|
".png"
|
||||||
@@ -10,14 +10,14 @@
|
|||||||
"subMetas": {
|
"subMetas": {
|
||||||
"6c48a": {
|
"6c48a": {
|
||||||
"importer": "texture",
|
"importer": "texture",
|
||||||
"uuid": "a34c93d2-cae0-42d4-a2eb-c3155052ad20@6c48a",
|
"uuid": "5a832eca-5c6c-4fbc-9218-bf5aae721934@6c48a",
|
||||||
"displayName": "ContentBg",
|
"displayName": "IconAd",
|
||||||
"id": "6c48a",
|
"id": "6c48a",
|
||||||
"name": "texture",
|
"name": "texture",
|
||||||
"userData": {
|
"userData": {
|
||||||
"wrapModeS": "clamp-to-edge",
|
"wrapModeS": "clamp-to-edge",
|
||||||
"wrapModeT": "clamp-to-edge",
|
"wrapModeT": "clamp-to-edge",
|
||||||
"imageUuidOrDatabaseUri": "a34c93d2-cae0-42d4-a2eb-c3155052ad20",
|
"imageUuidOrDatabaseUri": "5a832eca-5c6c-4fbc-9218-bf5aae721934",
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"minfilter": "linear",
|
"minfilter": "linear",
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
},
|
},
|
||||||
"f9941": {
|
"f9941": {
|
||||||
"importer": "sprite-frame",
|
"importer": "sprite-frame",
|
||||||
"uuid": "a34c93d2-cae0-42d4-a2eb-c3155052ad20@f9941",
|
"uuid": "5a832eca-5c6c-4fbc-9218-bf5aae721934@f9941",
|
||||||
"displayName": "ContentBg",
|
"displayName": "IconAd",
|
||||||
"id": "f9941",
|
"id": "f9941",
|
||||||
"name": "spriteFrame",
|
"name": "spriteFrame",
|
||||||
"userData": {
|
"userData": {
|
||||||
@@ -45,10 +45,10 @@
|
|||||||
"offsetY": 0,
|
"offsetY": 0,
|
||||||
"trimX": 0,
|
"trimX": 0,
|
||||||
"trimY": 0,
|
"trimY": 0,
|
||||||
"width": 304,
|
"width": 63,
|
||||||
"height": 404,
|
"height": 49,
|
||||||
"rawWidth": 304,
|
"rawWidth": 63,
|
||||||
"rawHeight": 404,
|
"rawHeight": 49,
|
||||||
"borderTop": 0,
|
"borderTop": 0,
|
||||||
"borderBottom": 0,
|
"borderBottom": 0,
|
||||||
"borderLeft": 0,
|
"borderLeft": 0,
|
||||||
@@ -60,17 +60,17 @@
|
|||||||
"meshType": 0,
|
"meshType": 0,
|
||||||
"vertices": {
|
"vertices": {
|
||||||
"rawPosition": [
|
"rawPosition": [
|
||||||
-152,
|
-31.5,
|
||||||
-202,
|
-24.5,
|
||||||
0,
|
0,
|
||||||
152,
|
31.5,
|
||||||
-202,
|
-24.5,
|
||||||
0,
|
0,
|
||||||
-152,
|
-31.5,
|
||||||
202,
|
24.5,
|
||||||
0,
|
0,
|
||||||
152,
|
31.5,
|
||||||
202,
|
24.5,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"indexes": [
|
"indexes": [
|
||||||
@@ -83,12 +83,12 @@
|
|||||||
],
|
],
|
||||||
"uv": [
|
"uv": [
|
||||||
0,
|
0,
|
||||||
404,
|
49,
|
||||||
304,
|
63,
|
||||||
404,
|
49,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
304,
|
63,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"nuv": [
|
"nuv": [
|
||||||
@@ -102,18 +102,18 @@
|
|||||||
1
|
1
|
||||||
],
|
],
|
||||||
"minPos": [
|
"minPos": [
|
||||||
-152,
|
-31.5,
|
||||||
-202,
|
-24.5,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"maxPos": [
|
"maxPos": [
|
||||||
152,
|
31.5,
|
||||||
202,
|
24.5,
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"imageUuidOrDatabaseUri": "a34c93d2-cae0-42d4-a2eb-c3155052ad20@6c48a",
|
"imageUuidOrDatabaseUri": "5a832eca-5c6c-4fbc-9218-bf5aae721934@6c48a",
|
||||||
"atlasUuid": "",
|
"atlasUuid": "",
|
||||||
"trimType": "auto"
|
"trimType": "auto"
|
||||||
},
|
},
|
||||||
@@ -127,8 +127,8 @@
|
|||||||
},
|
},
|
||||||
"userData": {
|
"userData": {
|
||||||
"type": "sprite-frame",
|
"type": "sprite-frame",
|
||||||
"fixAlphaTransparencyArtifacts": false,
|
|
||||||
"hasAlpha": true,
|
"hasAlpha": true,
|
||||||
"redirect": "a34c93d2-cae0-42d4-a2eb-c3155052ad20@6c48a"
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"redirect": "5a832eca-5c6c-4fbc-9218-bf5aae721934@6c48a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
assets/resources/images/IconStam2.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
134
assets/resources/images/IconStam2.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "d18c3099-87cb-4ee0-9778-b3b27468f7b7",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "d18c3099-87cb-4ee0-9778-b3b27468f7b7@6c48a",
|
||||||
|
"displayName": "IconStam2",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "d18c3099-87cb-4ee0-9778-b3b27468f7b7",
|
||||||
|
"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": "d18c3099-87cb-4ee0-9778-b3b27468f7b7@f9941",
|
||||||
|
"displayName": "IconStam2",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0.5,
|
||||||
|
"trimX": 86,
|
||||||
|
"trimY": 45,
|
||||||
|
"width": 228,
|
||||||
|
"height": 309,
|
||||||
|
"rawWidth": 400,
|
||||||
|
"rawHeight": 400,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-114,
|
||||||
|
-154.5,
|
||||||
|
0,
|
||||||
|
114,
|
||||||
|
-154.5,
|
||||||
|
0,
|
||||||
|
-114,
|
||||||
|
154.5,
|
||||||
|
0,
|
||||||
|
114,
|
||||||
|
154.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
86,
|
||||||
|
355,
|
||||||
|
314,
|
||||||
|
355,
|
||||||
|
86,
|
||||||
|
46,
|
||||||
|
314,
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0.215,
|
||||||
|
0.115,
|
||||||
|
0.785,
|
||||||
|
0.115,
|
||||||
|
0.215,
|
||||||
|
0.8875,
|
||||||
|
0.785,
|
||||||
|
0.8875
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-114,
|
||||||
|
-154.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
114,
|
||||||
|
154.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "d18c3099-87cb-4ee0-9778-b3b27468f7b7@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "d18c3099-87cb-4ee0-9778-b3b27468f7b7@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/Plus.png
Normal file
|
After Width: | Height: | Size: 341 B |
134
assets/resources/images/Plus.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "a2cba4c9-ed0a-46c4-9184-362cfd0d878d",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "a2cba4c9-ed0a-46c4-9184-362cfd0d878d@6c48a",
|
||||||
|
"displayName": "Plus",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "a2cba4c9-ed0a-46c4-9184-362cfd0d878d",
|
||||||
|
"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": "a2cba4c9-ed0a-46c4-9184-362cfd0d878d@f9941",
|
||||||
|
"displayName": "Plus",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 26,
|
||||||
|
"height": 26,
|
||||||
|
"rawWidth": 26,
|
||||||
|
"rawHeight": 26,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-13,
|
||||||
|
-13,
|
||||||
|
0,
|
||||||
|
13,
|
||||||
|
-13,
|
||||||
|
0,
|
||||||
|
-13,
|
||||||
|
13,
|
||||||
|
0,
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
26,
|
||||||
|
26,
|
||||||
|
26,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
26,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-13,
|
||||||
|
-13,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "a2cba4c9-ed0a-46c4-9184-362cfd0d878d@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "a2cba4c9-ed0a-46c4-9184-362cfd0d878d@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/bg_green.jpg
Normal file
|
After Width: | Height: | Size: 117 KiB |
134
assets/resources/images/bg_green.jpg.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "e9f94fb0-2acf-4004-8c6e-023e9deeb9cb",
|
||||||
|
"files": [
|
||||||
|
".jpg",
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "e9f94fb0-2acf-4004-8c6e-023e9deeb9cb@6c48a",
|
||||||
|
"displayName": "bg_green",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "e9f94fb0-2acf-4004-8c6e-023e9deeb9cb",
|
||||||
|
"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": "e9f94fb0-2acf-4004-8c6e-023e9deeb9cb@f9941",
|
||||||
|
"displayName": "bg_green",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 1376,
|
||||||
|
"height": 3064,
|
||||||
|
"rawWidth": 1376,
|
||||||
|
"rawHeight": 3064,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-688,
|
||||||
|
-1532,
|
||||||
|
0,
|
||||||
|
688,
|
||||||
|
-1532,
|
||||||
|
0,
|
||||||
|
-688,
|
||||||
|
1532,
|
||||||
|
0,
|
||||||
|
688,
|
||||||
|
1532,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
3064,
|
||||||
|
1376,
|
||||||
|
3064,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1376,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-688,
|
||||||
|
-1532,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
688,
|
||||||
|
1532,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "e9f94fb0-2acf-4004-8c6e-023e9deeb9cb@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": false,
|
||||||
|
"redirect": "e9f94fb0-2acf-4004-8c6e-023e9deeb9cb@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/level/BuyButtonBg.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
134
assets/resources/images/level/BuyButtonBg.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "39c1c6c3-43dd-4fa1-bbc2-fb394d8cf6d6",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "39c1c6c3-43dd-4fa1-bbc2-fb394d8cf6d6@6c48a",
|
||||||
|
"displayName": "BuyButtonBg",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "39c1c6c3-43dd-4fa1-bbc2-fb394d8cf6d6",
|
||||||
|
"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": "39c1c6c3-43dd-4fa1-bbc2-fb394d8cf6d6@f9941",
|
||||||
|
"displayName": "BuyButtonBg",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 326,
|
||||||
|
"height": 143,
|
||||||
|
"rawWidth": 326,
|
||||||
|
"rawHeight": 143,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-163,
|
||||||
|
-71.5,
|
||||||
|
0,
|
||||||
|
163,
|
||||||
|
-71.5,
|
||||||
|
0,
|
||||||
|
-163,
|
||||||
|
71.5,
|
||||||
|
0,
|
||||||
|
163,
|
||||||
|
71.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
143,
|
||||||
|
326,
|
||||||
|
143,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
326,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-163,
|
||||||
|
-71.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
163,
|
||||||
|
71.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "39c1c6c3-43dd-4fa1-bbc2-fb394d8cf6d6@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "39c1c6c3-43dd-4fa1-bbc2-fb394d8cf6d6@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageHome/HomeButtonGreen.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
134
assets/resources/images/pageHome/HomeButtonGreen.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "02047ea3-2a13-4f17-b4dd-5aefa0e182dc",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "02047ea3-2a13-4f17-b4dd-5aefa0e182dc@6c48a",
|
||||||
|
"displayName": "HomeButtonGreen",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "02047ea3-2a13-4f17-b4dd-5aefa0e182dc",
|
||||||
|
"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": "02047ea3-2a13-4f17-b4dd-5aefa0e182dc@f9941",
|
||||||
|
"displayName": "HomeButtonGreen",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 488,
|
||||||
|
"height": 197,
|
||||||
|
"rawWidth": 488,
|
||||||
|
"rawHeight": 197,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-244,
|
||||||
|
-98.5,
|
||||||
|
0,
|
||||||
|
244,
|
||||||
|
-98.5,
|
||||||
|
0,
|
||||||
|
-244,
|
||||||
|
98.5,
|
||||||
|
0,
|
||||||
|
244,
|
||||||
|
98.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
197,
|
||||||
|
488,
|
||||||
|
197,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
488,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-244,
|
||||||
|
-98.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
244,
|
||||||
|
98.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "02047ea3-2a13-4f17-b4dd-5aefa0e182dc@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "02047ea3-2a13-4f17-b4dd-5aefa0e182dc@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageHome/HomeButtonOrange.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
134
assets/resources/images/pageHome/HomeButtonOrange.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "2270362e-66d7-4d0f-ab51-b5cbca25a768",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "2270362e-66d7-4d0f-ab51-b5cbca25a768@6c48a",
|
||||||
|
"displayName": "HomeButtonOrange",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "2270362e-66d7-4d0f-ab51-b5cbca25a768",
|
||||||
|
"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": "2270362e-66d7-4d0f-ab51-b5cbca25a768@f9941",
|
||||||
|
"displayName": "HomeButtonOrange",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 488,
|
||||||
|
"height": 197,
|
||||||
|
"rawWidth": 488,
|
||||||
|
"rawHeight": 197,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-244,
|
||||||
|
-98.5,
|
||||||
|
0,
|
||||||
|
244,
|
||||||
|
-98.5,
|
||||||
|
0,
|
||||||
|
-244,
|
||||||
|
98.5,
|
||||||
|
0,
|
||||||
|
244,
|
||||||
|
98.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
197,
|
||||||
|
488,
|
||||||
|
197,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
488,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-244,
|
||||||
|
-98.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
244,
|
||||||
|
98.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "2270362e-66d7-4d0f-ab51-b5cbca25a768@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "2270362e-66d7-4d0f-ab51-b5cbca25a768@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageHome/friendChallenge.png
Normal file
|
After Width: | Height: | Size: 153 KiB |
@@ -2,7 +2,7 @@
|
|||||||
"ver": "1.0.27",
|
"ver": "1.0.27",
|
||||||
"importer": "image",
|
"importer": "image",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "729b014d-f0e9-4b67-b99d-177756102d0e",
|
"uuid": "12eb7a16-3f31-40d8-a9cd-30e18900a3a3",
|
||||||
"files": [
|
"files": [
|
||||||
".json",
|
".json",
|
||||||
".png"
|
".png"
|
||||||
@@ -10,14 +10,14 @@
|
|||||||
"subMetas": {
|
"subMetas": {
|
||||||
"6c48a": {
|
"6c48a": {
|
||||||
"importer": "texture",
|
"importer": "texture",
|
||||||
"uuid": "729b014d-f0e9-4b67-b99d-177756102d0e@6c48a",
|
"uuid": "12eb7a16-3f31-40d8-a9cd-30e18900a3a3@6c48a",
|
||||||
"displayName": "IconTips",
|
"displayName": "friendChallenge",
|
||||||
"id": "6c48a",
|
"id": "6c48a",
|
||||||
"name": "texture",
|
"name": "texture",
|
||||||
"userData": {
|
"userData": {
|
||||||
"wrapModeS": "clamp-to-edge",
|
"wrapModeS": "clamp-to-edge",
|
||||||
"wrapModeT": "clamp-to-edge",
|
"wrapModeT": "clamp-to-edge",
|
||||||
"imageUuidOrDatabaseUri": "729b014d-f0e9-4b67-b99d-177756102d0e",
|
"imageUuidOrDatabaseUri": "12eb7a16-3f31-40d8-a9cd-30e18900a3a3",
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"minfilter": "linear",
|
"minfilter": "linear",
|
||||||
@@ -34,21 +34,21 @@
|
|||||||
},
|
},
|
||||||
"f9941": {
|
"f9941": {
|
||||||
"importer": "sprite-frame",
|
"importer": "sprite-frame",
|
||||||
"uuid": "729b014d-f0e9-4b67-b99d-177756102d0e@f9941",
|
"uuid": "12eb7a16-3f31-40d8-a9cd-30e18900a3a3@f9941",
|
||||||
"displayName": "IconTips",
|
"displayName": "friendChallenge",
|
||||||
"id": "f9941",
|
"id": "f9941",
|
||||||
"name": "spriteFrame",
|
"name": "spriteFrame",
|
||||||
"userData": {
|
"userData": {
|
||||||
"trimThreshold": 1,
|
"trimThreshold": 1,
|
||||||
"rotated": false,
|
"rotated": false,
|
||||||
"offsetX": 0.5,
|
"offsetX": 0,
|
||||||
"offsetY": 0,
|
"offsetY": -8.5,
|
||||||
"trimX": 31,
|
"trimX": 170,
|
||||||
"trimY": 12,
|
"trimY": 243,
|
||||||
"width": 139,
|
"width": 684,
|
||||||
"height": 176,
|
"height": 555,
|
||||||
"rawWidth": 200,
|
"rawWidth": 1024,
|
||||||
"rawHeight": 200,
|
"rawHeight": 1024,
|
||||||
"borderTop": 0,
|
"borderTop": 0,
|
||||||
"borderBottom": 0,
|
"borderBottom": 0,
|
||||||
"borderLeft": 0,
|
"borderLeft": 0,
|
||||||
@@ -60,17 +60,17 @@
|
|||||||
"meshType": 0,
|
"meshType": 0,
|
||||||
"vertices": {
|
"vertices": {
|
||||||
"rawPosition": [
|
"rawPosition": [
|
||||||
-69.5,
|
-342,
|
||||||
-88,
|
-277.5,
|
||||||
0,
|
0,
|
||||||
69.5,
|
342,
|
||||||
-88,
|
-277.5,
|
||||||
0,
|
0,
|
||||||
-69.5,
|
-342,
|
||||||
88,
|
277.5,
|
||||||
0,
|
0,
|
||||||
69.5,
|
342,
|
||||||
88,
|
277.5,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"indexes": [
|
"indexes": [
|
||||||
@@ -82,38 +82,38 @@
|
|||||||
3
|
3
|
||||||
],
|
],
|
||||||
"uv": [
|
"uv": [
|
||||||
31,
|
|
||||||
188,
|
|
||||||
170,
|
170,
|
||||||
188,
|
781,
|
||||||
31,
|
854,
|
||||||
12,
|
781,
|
||||||
170,
|
170,
|
||||||
12
|
226,
|
||||||
|
854,
|
||||||
|
226
|
||||||
],
|
],
|
||||||
"nuv": [
|
"nuv": [
|
||||||
0.155,
|
0.166015625,
|
||||||
0.06,
|
0.220703125,
|
||||||
0.85,
|
0.833984375,
|
||||||
0.06,
|
0.220703125,
|
||||||
0.155,
|
0.166015625,
|
||||||
0.94,
|
0.7626953125,
|
||||||
0.85,
|
0.833984375,
|
||||||
0.94
|
0.7626953125
|
||||||
],
|
],
|
||||||
"minPos": [
|
"minPos": [
|
||||||
-69.5,
|
-342,
|
||||||
-88,
|
-277.5,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"maxPos": [
|
"maxPos": [
|
||||||
69.5,
|
342,
|
||||||
88,
|
277.5,
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"imageUuidOrDatabaseUri": "729b014d-f0e9-4b67-b99d-177756102d0e@6c48a",
|
"imageUuidOrDatabaseUri": "12eb7a16-3f31-40d8-a9cd-30e18900a3a3@6c48a",
|
||||||
"atlasUuid": "",
|
"atlasUuid": "",
|
||||||
"trimType": "auto"
|
"trimType": "auto"
|
||||||
},
|
},
|
||||||
@@ -129,6 +129,6 @@
|
|||||||
"type": "sprite-frame",
|
"type": "sprite-frame",
|
||||||
"fixAlphaTransparencyArtifacts": false,
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
"hasAlpha": true,
|
"hasAlpha": true,
|
||||||
"redirect": "729b014d-f0e9-4b67-b99d-177756102d0e@6c48a"
|
"redirect": "12eb7a16-3f31-40d8-a9cd-30e18900a3a3@6c48a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
assets/resources/images/pageHome/homeIconChallenge.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
@@ -2,7 +2,7 @@
|
|||||||
"ver": "1.0.27",
|
"ver": "1.0.27",
|
||||||
"importer": "image",
|
"importer": "image",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "d532045e-55f8-47c2-9493-b918e18364b0",
|
"uuid": "894c2169-ec35-4aeb-b656-3caa09604b09",
|
||||||
"files": [
|
"files": [
|
||||||
".json",
|
".json",
|
||||||
".png"
|
".png"
|
||||||
@@ -10,14 +10,14 @@
|
|||||||
"subMetas": {
|
"subMetas": {
|
||||||
"6c48a": {
|
"6c48a": {
|
||||||
"importer": "texture",
|
"importer": "texture",
|
||||||
"uuid": "d532045e-55f8-47c2-9493-b918e18364b0@6c48a",
|
"uuid": "894c2169-ec35-4aeb-b656-3caa09604b09@6c48a",
|
||||||
"displayName": "Bg",
|
"displayName": "homeIconChallenge",
|
||||||
"id": "6c48a",
|
"id": "6c48a",
|
||||||
"name": "texture",
|
"name": "texture",
|
||||||
"userData": {
|
"userData": {
|
||||||
"wrapModeS": "clamp-to-edge",
|
"wrapModeS": "clamp-to-edge",
|
||||||
"wrapModeT": "clamp-to-edge",
|
"wrapModeT": "clamp-to-edge",
|
||||||
"imageUuidOrDatabaseUri": "d532045e-55f8-47c2-9493-b918e18364b0",
|
"imageUuidOrDatabaseUri": "894c2169-ec35-4aeb-b656-3caa09604b09",
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"minfilter": "linear",
|
"minfilter": "linear",
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
},
|
},
|
||||||
"f9941": {
|
"f9941": {
|
||||||
"importer": "sprite-frame",
|
"importer": "sprite-frame",
|
||||||
"uuid": "d532045e-55f8-47c2-9493-b918e18364b0@f9941",
|
"uuid": "894c2169-ec35-4aeb-b656-3caa09604b09@f9941",
|
||||||
"displayName": "Bg",
|
"displayName": "homeIconChallenge",
|
||||||
"id": "f9941",
|
"id": "f9941",
|
||||||
"name": "spriteFrame",
|
"name": "spriteFrame",
|
||||||
"userData": {
|
"userData": {
|
||||||
@@ -45,10 +45,10 @@
|
|||||||
"offsetY": 0,
|
"offsetY": 0,
|
||||||
"trimX": 0,
|
"trimX": 0,
|
||||||
"trimY": 0,
|
"trimY": 0,
|
||||||
"width": 750,
|
"width": 375,
|
||||||
"height": 1626,
|
"height": 183,
|
||||||
"rawWidth": 750,
|
"rawWidth": 375,
|
||||||
"rawHeight": 1626,
|
"rawHeight": 183,
|
||||||
"borderTop": 0,
|
"borderTop": 0,
|
||||||
"borderBottom": 0,
|
"borderBottom": 0,
|
||||||
"borderLeft": 0,
|
"borderLeft": 0,
|
||||||
@@ -60,17 +60,17 @@
|
|||||||
"meshType": 0,
|
"meshType": 0,
|
||||||
"vertices": {
|
"vertices": {
|
||||||
"rawPosition": [
|
"rawPosition": [
|
||||||
-375,
|
-187.5,
|
||||||
-813,
|
-91.5,
|
||||||
0,
|
0,
|
||||||
375,
|
187.5,
|
||||||
-813,
|
-91.5,
|
||||||
0,
|
0,
|
||||||
-375,
|
-187.5,
|
||||||
813,
|
91.5,
|
||||||
0,
|
0,
|
||||||
375,
|
187.5,
|
||||||
813,
|
91.5,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"indexes": [
|
"indexes": [
|
||||||
@@ -83,12 +83,12 @@
|
|||||||
],
|
],
|
||||||
"uv": [
|
"uv": [
|
||||||
0,
|
0,
|
||||||
1626,
|
183,
|
||||||
750,
|
375,
|
||||||
1626,
|
183,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
750,
|
375,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"nuv": [
|
"nuv": [
|
||||||
@@ -102,18 +102,18 @@
|
|||||||
1
|
1
|
||||||
],
|
],
|
||||||
"minPos": [
|
"minPos": [
|
||||||
-375,
|
-187.5,
|
||||||
-813,
|
-91.5,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"maxPos": [
|
"maxPos": [
|
||||||
375,
|
187.5,
|
||||||
813,
|
91.5,
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"imageUuidOrDatabaseUri": "d532045e-55f8-47c2-9493-b918e18364b0@6c48a",
|
"imageUuidOrDatabaseUri": "894c2169-ec35-4aeb-b656-3caa09604b09@6c48a",
|
||||||
"atlasUuid": "",
|
"atlasUuid": "",
|
||||||
"trimType": "auto"
|
"trimType": "auto"
|
||||||
},
|
},
|
||||||
@@ -129,6 +129,6 @@
|
|||||||
"type": "sprite-frame",
|
"type": "sprite-frame",
|
||||||
"fixAlphaTransparencyArtifacts": false,
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
"hasAlpha": true,
|
"hasAlpha": true,
|
||||||
"redirect": "d532045e-55f8-47c2-9493-b918e18364b0@6c48a"
|
"redirect": "894c2169-ec35-4aeb-b656-3caa09604b09@6c48a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
assets/resources/images/pageHome/homeIconCreate.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
134
assets/resources/images/pageHome/homeIconCreate.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "0253c893-2588-492f-9d96-911878b8a673",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "0253c893-2588-492f-9d96-911878b8a673@6c48a",
|
||||||
|
"displayName": "homeIconCreate",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "0253c893-2588-492f-9d96-911878b8a673",
|
||||||
|
"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": "0253c893-2588-492f-9d96-911878b8a673@f9941",
|
||||||
|
"displayName": "homeIconCreate",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": -0.5,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 1,
|
||||||
|
"width": 373,
|
||||||
|
"height": 232,
|
||||||
|
"rawWidth": 373,
|
||||||
|
"rawHeight": 233,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-186.5,
|
||||||
|
-116,
|
||||||
|
0,
|
||||||
|
186.5,
|
||||||
|
-116,
|
||||||
|
0,
|
||||||
|
-186.5,
|
||||||
|
116,
|
||||||
|
0,
|
||||||
|
186.5,
|
||||||
|
116,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
232,
|
||||||
|
373,
|
||||||
|
232,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
373,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0.9957081545064378,
|
||||||
|
1,
|
||||||
|
0.9957081545064378
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-186.5,
|
||||||
|
-116,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
186.5,
|
||||||
|
116,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "0253c893-2588-492f-9d96-911878b8a673@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "0253c893-2588-492f-9d96-911878b8a673@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageHome/homeIconFriend.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
134
assets/resources/images/pageHome/homeIconFriend.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "a85c793d-50ce-4db1-ac92-2af76b8aa505",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "a85c793d-50ce-4db1-ac92-2af76b8aa505@6c48a",
|
||||||
|
"displayName": "homeIconFriend",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "a85c793d-50ce-4db1-ac92-2af76b8aa505",
|
||||||
|
"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": "a85c793d-50ce-4db1-ac92-2af76b8aa505@f9941",
|
||||||
|
"displayName": "homeIconFriend",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 345,
|
||||||
|
"height": 260,
|
||||||
|
"rawWidth": 345,
|
||||||
|
"rawHeight": 260,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-172.5,
|
||||||
|
-130,
|
||||||
|
0,
|
||||||
|
172.5,
|
||||||
|
-130,
|
||||||
|
0,
|
||||||
|
-172.5,
|
||||||
|
130,
|
||||||
|
0,
|
||||||
|
172.5,
|
||||||
|
130,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
260,
|
||||||
|
345,
|
||||||
|
260,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
345,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-172.5,
|
||||||
|
-130,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
172.5,
|
||||||
|
130,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "a85c793d-50ce-4db1-ac92-2af76b8aa505@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "a85c793d-50ce-4db1-ac92-2af76b8aa505@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageHome/homeIconGift.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
134
assets/resources/images/pageHome/homeIconGift.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "496f93ae-424d-427d-b3eb-54e47e336fc8",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "496f93ae-424d-427d-b3eb-54e47e336fc8@6c48a",
|
||||||
|
"displayName": "homeIconGift",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "496f93ae-424d-427d-b3eb-54e47e336fc8",
|
||||||
|
"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": "496f93ae-424d-427d-b3eb-54e47e336fc8@f9941",
|
||||||
|
"displayName": "homeIconGift",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 283,
|
||||||
|
"height": 285,
|
||||||
|
"rawWidth": 283,
|
||||||
|
"rawHeight": 285,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-141.5,
|
||||||
|
-142.5,
|
||||||
|
0,
|
||||||
|
141.5,
|
||||||
|
-142.5,
|
||||||
|
0,
|
||||||
|
-141.5,
|
||||||
|
142.5,
|
||||||
|
0,
|
||||||
|
141.5,
|
||||||
|
142.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
285,
|
||||||
|
283,
|
||||||
|
285,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
283,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-141.5,
|
||||||
|
-142.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
141.5,
|
||||||
|
142.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "496f93ae-424d-427d-b3eb-54e47e336fc8@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "496f93ae-424d-427d-b3eb-54e47e336fc8@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageHome/homeIconRank.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
134
assets/resources/images/pageHome/homeIconRank.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "6cc6bad3-00c6-4416-b48f-0434317d96c2",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "6cc6bad3-00c6-4416-b48f-0434317d96c2@6c48a",
|
||||||
|
"displayName": "homeIconRank",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "6cc6bad3-00c6-4416-b48f-0434317d96c2",
|
||||||
|
"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": "6cc6bad3-00c6-4416-b48f-0434317d96c2@f9941",
|
||||||
|
"displayName": "homeIconRank",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": -0.5,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 1,
|
||||||
|
"width": 346,
|
||||||
|
"height": 307,
|
||||||
|
"rawWidth": 346,
|
||||||
|
"rawHeight": 308,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-173,
|
||||||
|
-153.5,
|
||||||
|
0,
|
||||||
|
173,
|
||||||
|
-153.5,
|
||||||
|
0,
|
||||||
|
-173,
|
||||||
|
153.5,
|
||||||
|
0,
|
||||||
|
173,
|
||||||
|
153.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
307,
|
||||||
|
346,
|
||||||
|
307,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
346,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0.9967532467532467,
|
||||||
|
1,
|
||||||
|
0.9967532467532467
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-173,
|
||||||
|
-153.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
173,
|
||||||
|
153.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "6cc6bad3-00c6-4416-b48f-0434317d96c2@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "6cc6bad3-00c6-4416-b48f-0434317d96c2@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 38 KiB |
BIN
assets/resources/images/pageLevel/1_0022_Layer-19.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
134
assets/resources/images/pageLevel/1_0022_Layer-19.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400@6c48a",
|
||||||
|
"displayName": "1_0022_Layer-19",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400",
|
||||||
|
"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": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400@f9941",
|
||||||
|
"displayName": "1_0022_Layer-19",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 1297,
|
||||||
|
"height": 1004,
|
||||||
|
"rawWidth": 1297,
|
||||||
|
"rawHeight": 1004,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-648.5,
|
||||||
|
-502,
|
||||||
|
0,
|
||||||
|
648.5,
|
||||||
|
-502,
|
||||||
|
0,
|
||||||
|
-648.5,
|
||||||
|
502,
|
||||||
|
0,
|
||||||
|
648.5,
|
||||||
|
502,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
1004,
|
||||||
|
1297,
|
||||||
|
1004,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1297,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-648.5,
|
||||||
|
-502,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
648.5,
|
||||||
|
502,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB |
BIN
assets/resources/images/pageLevel/ButtonGreen.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
134
assets/resources/images/pageLevel/ButtonGreen.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "f87d228a-c520-499a-bf3a-e66cbb6def64",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "f87d228a-c520-499a-bf3a-e66cbb6def64@6c48a",
|
||||||
|
"displayName": "ButtonGreen",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "f87d228a-c520-499a-bf3a-e66cbb6def64",
|
||||||
|
"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": "f87d228a-c520-499a-bf3a-e66cbb6def64@f9941",
|
||||||
|
"displayName": "ButtonGreen",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 666,
|
||||||
|
"height": 235,
|
||||||
|
"rawWidth": 666,
|
||||||
|
"rawHeight": 235,
|
||||||
|
"borderTop": 120,
|
||||||
|
"borderBottom": 115,
|
||||||
|
"borderLeft": 120,
|
||||||
|
"borderRight": 120,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-333,
|
||||||
|
-117.5,
|
||||||
|
0,
|
||||||
|
333,
|
||||||
|
-117.5,
|
||||||
|
0,
|
||||||
|
-333,
|
||||||
|
117.5,
|
||||||
|
0,
|
||||||
|
333,
|
||||||
|
117.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
235,
|
||||||
|
666,
|
||||||
|
235,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
666,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-333,
|
||||||
|
-117.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
333,
|
||||||
|
117.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "f87d228a-c520-499a-bf3a-e66cbb6def64@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "none"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "f87d228a-c520-499a-bf3a-e66cbb6def64@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageLevel/ButtonOrange.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
134
assets/resources/images/pageLevel/ButtonOrange.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "0366f161-d78c-43b1-b2cb-8d0666dd2fbd",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "0366f161-d78c-43b1-b2cb-8d0666dd2fbd@6c48a",
|
||||||
|
"displayName": "ButtonOrange",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "0366f161-d78c-43b1-b2cb-8d0666dd2fbd",
|
||||||
|
"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": "0366f161-d78c-43b1-b2cb-8d0666dd2fbd@f9941",
|
||||||
|
"displayName": "ButtonOrange",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 666,
|
||||||
|
"height": 235,
|
||||||
|
"rawWidth": 666,
|
||||||
|
"rawHeight": 235,
|
||||||
|
"borderTop": 112,
|
||||||
|
"borderBottom": 112,
|
||||||
|
"borderLeft": 112,
|
||||||
|
"borderRight": 112,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-333,
|
||||||
|
-117.5,
|
||||||
|
0,
|
||||||
|
333,
|
||||||
|
-117.5,
|
||||||
|
0,
|
||||||
|
-333,
|
||||||
|
117.5,
|
||||||
|
0,
|
||||||
|
333,
|
||||||
|
117.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
235,
|
||||||
|
666,
|
||||||
|
235,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
666,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-333,
|
||||||
|
-117.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
333,
|
||||||
|
117.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "0366f161-d78c-43b1-b2cb-8d0666dd2fbd@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "0366f161-d78c-43b1-b2cb-8d0666dd2fbd@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageLevel/ButtonYellow.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
134
assets/resources/images/pageLevel/ButtonYellow.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "ba58112d-788c-465d-a2f3-46b468026d03",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "ba58112d-788c-465d-a2f3-46b468026d03@6c48a",
|
||||||
|
"displayName": "ButtonYellow",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "ba58112d-788c-465d-a2f3-46b468026d03",
|
||||||
|
"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": "ba58112d-788c-465d-a2f3-46b468026d03@f9941",
|
||||||
|
"displayName": "ButtonYellow",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": -0.5,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 665,
|
||||||
|
"height": 235,
|
||||||
|
"rawWidth": 666,
|
||||||
|
"rawHeight": 235,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-332.5,
|
||||||
|
-117.5,
|
||||||
|
0,
|
||||||
|
332.5,
|
||||||
|
-117.5,
|
||||||
|
0,
|
||||||
|
-332.5,
|
||||||
|
117.5,
|
||||||
|
0,
|
||||||
|
332.5,
|
||||||
|
117.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
235,
|
||||||
|
665,
|
||||||
|
235,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
665,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0.9984984984984985,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0.9984984984984985,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-332.5,
|
||||||
|
-117.5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
332.5,
|
||||||
|
117.5,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "ba58112d-788c-465d-a2f3-46b468026d03@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "ba58112d-788c-465d-a2f3-46b468026d03@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/resources/images/pageLevel/CharBlock.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
@@ -2,7 +2,7 @@
|
|||||||
"ver": "1.0.27",
|
"ver": "1.0.27",
|
||||||
"importer": "image",
|
"importer": "image",
|
||||||
"imported": true,
|
"imported": true,
|
||||||
"uuid": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26",
|
"uuid": "31d2998e-4261-4284-bbcd-9a34ad9c73a6",
|
||||||
"files": [
|
"files": [
|
||||||
".json",
|
".json",
|
||||||
".png"
|
".png"
|
||||||
@@ -10,14 +10,14 @@
|
|||||||
"subMetas": {
|
"subMetas": {
|
||||||
"6c48a": {
|
"6c48a": {
|
||||||
"importer": "texture",
|
"importer": "texture",
|
||||||
"uuid": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@6c48a",
|
"uuid": "31d2998e-4261-4284-bbcd-9a34ad9c73a6@6c48a",
|
||||||
"displayName": "ButtonBg",
|
"displayName": "CharBlock",
|
||||||
"id": "6c48a",
|
"id": "6c48a",
|
||||||
"name": "texture",
|
"name": "texture",
|
||||||
"userData": {
|
"userData": {
|
||||||
"wrapModeS": "clamp-to-edge",
|
"wrapModeS": "clamp-to-edge",
|
||||||
"wrapModeT": "clamp-to-edge",
|
"wrapModeT": "clamp-to-edge",
|
||||||
"imageUuidOrDatabaseUri": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26",
|
"imageUuidOrDatabaseUri": "31d2998e-4261-4284-bbcd-9a34ad9c73a6",
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"minfilter": "linear",
|
"minfilter": "linear",
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
},
|
},
|
||||||
"f9941": {
|
"f9941": {
|
||||||
"importer": "sprite-frame",
|
"importer": "sprite-frame",
|
||||||
"uuid": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@f9941",
|
"uuid": "31d2998e-4261-4284-bbcd-9a34ad9c73a6@f9941",
|
||||||
"displayName": "ButtonBg",
|
"displayName": "CharBlock",
|
||||||
"id": "f9941",
|
"id": "f9941",
|
||||||
"name": "spriteFrame",
|
"name": "spriteFrame",
|
||||||
"userData": {
|
"userData": {
|
||||||
@@ -44,11 +44,11 @@
|
|||||||
"offsetX": 0,
|
"offsetX": 0,
|
||||||
"offsetY": 0.5,
|
"offsetY": 0.5,
|
||||||
"trimX": 1,
|
"trimX": 1,
|
||||||
"trimY": 0,
|
"trimY": 1,
|
||||||
"width": 306,
|
"width": 177,
|
||||||
"height": 77,
|
"height": 209,
|
||||||
"rawWidth": 308,
|
"rawWidth": 179,
|
||||||
"rawHeight": 78,
|
"rawHeight": 212,
|
||||||
"borderTop": 0,
|
"borderTop": 0,
|
||||||
"borderBottom": 0,
|
"borderBottom": 0,
|
||||||
"borderLeft": 0,
|
"borderLeft": 0,
|
||||||
@@ -60,17 +60,17 @@
|
|||||||
"meshType": 0,
|
"meshType": 0,
|
||||||
"vertices": {
|
"vertices": {
|
||||||
"rawPosition": [
|
"rawPosition": [
|
||||||
-153,
|
-88.5,
|
||||||
-38.5,
|
-104.5,
|
||||||
0,
|
0,
|
||||||
153,
|
88.5,
|
||||||
-38.5,
|
-104.5,
|
||||||
0,
|
0,
|
||||||
-153,
|
-88.5,
|
||||||
38.5,
|
104.5,
|
||||||
0,
|
0,
|
||||||
153,
|
88.5,
|
||||||
38.5,
|
104.5,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"indexes": [
|
"indexes": [
|
||||||
@@ -83,37 +83,37 @@
|
|||||||
],
|
],
|
||||||
"uv": [
|
"uv": [
|
||||||
1,
|
1,
|
||||||
78,
|
211,
|
||||||
307,
|
178,
|
||||||
78,
|
211,
|
||||||
1,
|
1,
|
||||||
1,
|
2,
|
||||||
307,
|
178,
|
||||||
1
|
2
|
||||||
],
|
],
|
||||||
"nuv": [
|
"nuv": [
|
||||||
0.003246753246753247,
|
0.00558659217877095,
|
||||||
0.01282051282051282,
|
0.009433962264150943,
|
||||||
0.9967532467532467,
|
0.994413407821229,
|
||||||
0.01282051282051282,
|
0.009433962264150943,
|
||||||
0.003246753246753247,
|
0.00558659217877095,
|
||||||
1,
|
0.9952830188679245,
|
||||||
0.9967532467532467,
|
0.994413407821229,
|
||||||
1
|
0.9952830188679245
|
||||||
],
|
],
|
||||||
"minPos": [
|
"minPos": [
|
||||||
-153,
|
-88.5,
|
||||||
-38.5,
|
-104.5,
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"maxPos": [
|
"maxPos": [
|
||||||
153,
|
88.5,
|
||||||
38.5,
|
104.5,
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"isUuid": true,
|
"isUuid": true,
|
||||||
"imageUuidOrDatabaseUri": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@6c48a",
|
"imageUuidOrDatabaseUri": "31d2998e-4261-4284-bbcd-9a34ad9c73a6@6c48a",
|
||||||
"atlasUuid": "",
|
"atlasUuid": "",
|
||||||
"trimType": "auto"
|
"trimType": "auto"
|
||||||
},
|
},
|
||||||
@@ -129,6 +129,6 @@
|
|||||||
"type": "sprite-frame",
|
"type": "sprite-frame",
|
||||||
"fixAlphaTransparencyArtifacts": false,
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
"hasAlpha": true,
|
"hasAlpha": true,
|
||||||
"redirect": "e1267c1b-ceb0-4483-b36d-bc9cb4d2fd26@6c48a"
|
"redirect": "31d2998e-4261-4284-bbcd-9a34ad9c73a6@6c48a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
assets/resources/images/pageLevel/CharBlock2.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
134
assets/resources/images/pageLevel/CharBlock2.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "88cc67ba-1a68-4e04-99de-db6fd60fe3d6",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "88cc67ba-1a68-4e04-99de-db6fd60fe3d6@6c48a",
|
||||||
|
"displayName": "CharBlock2",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "88cc67ba-1a68-4e04-99de-db6fd60fe3d6",
|
||||||
|
"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": "88cc67ba-1a68-4e04-99de-db6fd60fe3d6@f9941",
|
||||||
|
"displayName": "CharBlock2",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 0,
|
||||||
|
"trimY": 0,
|
||||||
|
"width": 178,
|
||||||
|
"height": 186,
|
||||||
|
"rawWidth": 178,
|
||||||
|
"rawHeight": 186,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-89,
|
||||||
|
-93,
|
||||||
|
0,
|
||||||
|
89,
|
||||||
|
-93,
|
||||||
|
0,
|
||||||
|
-89,
|
||||||
|
93,
|
||||||
|
0,
|
||||||
|
89,
|
||||||
|
93,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
186,
|
||||||
|
178,
|
||||||
|
186,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
178,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-89,
|
||||||
|
-93,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
89,
|
||||||
|
93,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "88cc67ba-1a68-4e04-99de-db6fd60fe3d6@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "88cc67ba-1a68-4e04-99de-db6fd60fe3d6@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 1.9 KiB |
BIN
assets/resources/images/pageLevel/IconBulb.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
134
assets/resources/images/pageLevel/IconBulb.png.meta
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.27",
|
||||||
|
"importer": "image",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "a428ffd4-ce8c-4682-bf0b-d127509c8f23",
|
||||||
|
"files": [
|
||||||
|
".json",
|
||||||
|
".png"
|
||||||
|
],
|
||||||
|
"subMetas": {
|
||||||
|
"6c48a": {
|
||||||
|
"importer": "texture",
|
||||||
|
"uuid": "a428ffd4-ce8c-4682-bf0b-d127509c8f23@6c48a",
|
||||||
|
"displayName": "IconBulb",
|
||||||
|
"id": "6c48a",
|
||||||
|
"name": "texture",
|
||||||
|
"userData": {
|
||||||
|
"wrapModeS": "clamp-to-edge",
|
||||||
|
"wrapModeT": "clamp-to-edge",
|
||||||
|
"imageUuidOrDatabaseUri": "a428ffd4-ce8c-4682-bf0b-d127509c8f23",
|
||||||
|
"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": "a428ffd4-ce8c-4682-bf0b-d127509c8f23@f9941",
|
||||||
|
"displayName": "IconBulb",
|
||||||
|
"id": "f9941",
|
||||||
|
"name": "spriteFrame",
|
||||||
|
"userData": {
|
||||||
|
"trimThreshold": 1,
|
||||||
|
"rotated": false,
|
||||||
|
"offsetX": 0,
|
||||||
|
"offsetY": 0,
|
||||||
|
"trimX": 59,
|
||||||
|
"trimY": 7,
|
||||||
|
"width": 382,
|
||||||
|
"height": 486,
|
||||||
|
"rawWidth": 500,
|
||||||
|
"rawHeight": 500,
|
||||||
|
"borderTop": 0,
|
||||||
|
"borderBottom": 0,
|
||||||
|
"borderLeft": 0,
|
||||||
|
"borderRight": 0,
|
||||||
|
"packable": true,
|
||||||
|
"pixelsToUnit": 100,
|
||||||
|
"pivotX": 0.5,
|
||||||
|
"pivotY": 0.5,
|
||||||
|
"meshType": 0,
|
||||||
|
"vertices": {
|
||||||
|
"rawPosition": [
|
||||||
|
-191,
|
||||||
|
-243,
|
||||||
|
0,
|
||||||
|
191,
|
||||||
|
-243,
|
||||||
|
0,
|
||||||
|
-191,
|
||||||
|
243,
|
||||||
|
0,
|
||||||
|
191,
|
||||||
|
243,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"uv": [
|
||||||
|
59,
|
||||||
|
493,
|
||||||
|
441,
|
||||||
|
493,
|
||||||
|
59,
|
||||||
|
7,
|
||||||
|
441,
|
||||||
|
7
|
||||||
|
],
|
||||||
|
"nuv": [
|
||||||
|
0.118,
|
||||||
|
0.014,
|
||||||
|
0.882,
|
||||||
|
0.014,
|
||||||
|
0.118,
|
||||||
|
0.986,
|
||||||
|
0.882,
|
||||||
|
0.986
|
||||||
|
],
|
||||||
|
"minPos": [
|
||||||
|
-191,
|
||||||
|
-243,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"maxPos": [
|
||||||
|
191,
|
||||||
|
243,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"isUuid": true,
|
||||||
|
"imageUuidOrDatabaseUri": "a428ffd4-ce8c-4682-bf0b-d127509c8f23@6c48a",
|
||||||
|
"atlasUuid": "",
|
||||||
|
"trimType": "auto"
|
||||||
|
},
|
||||||
|
"ver": "1.0.12",
|
||||||
|
"imported": true,
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"userData": {
|
||||||
|
"type": "sprite-frame",
|
||||||
|
"fixAlphaTransparencyArtifacts": false,
|
||||||
|
"hasAlpha": true,
|
||||||
|
"redirect": "a428ffd4-ce8c-4682-bf0b-d127509c8f23@6c48a"
|
||||||
|
}
|
||||||
|
}
|
||||||