perf: 删除不必要的文件
This commit is contained in:
496
ARCHITECTURE.md
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
|
||||
|
||||
@@ -1,665 +0,0 @@
|
||||
# Architecture & Flow Diagrams
|
||||
|
||||
## System Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Cocos Creator Runtime │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ UI Layer (This Analysis) │ │
|
||||
│ ├──────────────────────────────────────────────────────────┤ │
|
||||
│ │ │ │
|
||||
│ │ ┌────────────────┐ ┌──────────────┐ │ │
|
||||
│ │ │ main.ts │────────▶│ ViewManager │ │ │
|
||||
│ │ │ (Bootstrap) │ │ (Singleton) │ │ │
|
||||
│ │ └────────────────┘ └──────────────┘ │ │
|
||||
│ │ │ │ │
|
||||
│ │ Pages (All extend BaseView): │ │ │
|
||||
│ │ ┌─────────────────────────────────┼──────────────┐ │ │
|
||||
│ │ │ • PageLoading (init data) │ │ │ │
|
||||
│ │ │ • PageHome (hub) │ │ │ │
|
||||
│ │ │ • PageLevel (game - complex) ◀┘ │ │ │
|
||||
│ │ │ • PagePreviewLevels (list) │ │ │
|
||||
│ │ │ • PassModal (modal) │ │ │
|
||||
│ │ └────────────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ ┌────────────────┐ ┌──────────────┐ │ │
|
||||
│ │ │ ToastManager │────────▶│ Toast │ │ │
|
||||
│ │ │ (Singleton) │ │ (Component) │ │ │
|
||||
│ │ └────────────────┘ └──────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Data Layer (External - Not Analyzed) │ │
|
||||
│ ├──────────────────────────────────────────────────────────┤ │
|
||||
│ │ • AuthManager • LevelDataManager │ │
|
||||
│ │ • StorageManager • UserAssetsManager │ │
|
||||
│ │ • ShareManager • WxSDK │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Page State Machine
|
||||
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ Application Starts │
|
||||
└──────────────┬──────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ main.onLoad() │
|
||||
│ Registers all pages │
|
||||
└──────────┬───────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────┐
|
||||
│ PageLoading displayed │
|
||||
│ - Load auth + levels │
|
||||
│ - Sync progress │
|
||||
│ - Check share code │
|
||||
└──────────────┬───────────────┘
|
||||
│
|
||||
┌──────────────┴──────────────┐
|
||||
│ Normal Mode │ Share Mode │
|
||||
▼ ▼ │
|
||||
┌──────────────────┐ ┌───────────────┐ │
|
||||
│ PageHome │ │ PageLevel │ │
|
||||
│ [Start] [PK] │ │ (in share) │ │
|
||||
└────┬─────┬───────┘ └───────┬───────┘ │
|
||||
│ │ │ │
|
||||
┌────────▼─┐ └────────────┬──────┴────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
PageLevel PageWrite (Repeat levels)
|
||||
(game) Levels │
|
||||
│ (create) ▼
|
||||
│ │ PassModal
|
||||
│ ▼ [Share]
|
||||
│ PagePreview │
|
||||
│ Levels ▼
|
||||
│ (verify) Back to Home
|
||||
│ │
|
||||
│ ▼
|
||||
│ PassModal
|
||||
│ [Next/Share]
|
||||
│ │
|
||||
└──────────┼─────────┐
|
||||
│ │
|
||||
┌────▼──┐ ┌───▼────┐
|
||||
│ Next │ │ Share │
|
||||
│ Loop │ │ to WX │
|
||||
└───────┘ └────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Page Stack Visualization
|
||||
|
||||
### Session Trace
|
||||
|
||||
```
|
||||
INITIALIZATION:
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Stack: [] │
|
||||
│ (Nothing loaded yet) │
|
||||
└────────────────────────────────────────────┘
|
||||
│
|
||||
▼ main.onLoad()
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Stack: [] │
|
||||
│ ViewManager + pages registered in registry │
|
||||
└────────────────────────────────────────────┘
|
||||
│
|
||||
▼ PageLoading.start() → ViewManager.open('PageHome')
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Stack: [PageHome] │
|
||||
│ PageHome._doShow() called │
|
||||
└────────────────────────────────────────────┘
|
||||
|
||||
USER CLICKS "START GAME":
|
||||
▼ PageHome._onStartGameClick() → ViewManager.open('PageLevel')
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Stack: [PageHome, PageLevel] │
|
||||
│ PageHome._doHide() called │
|
||||
│ PageLevel._doShow() called │
|
||||
└────────────────────────────────────────────┘
|
||||
|
||||
COMPLETES LEVEL:
|
||||
▼ PageLevel shows PassModal (not in stack, drawn on top)
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Stack: [PageHome, PageLevel] │
|
||||
│ UI Layer: [PageLevel, PassModal@z999] │
|
||||
│ PassModal shown with instantiate() │
|
||||
└────────────────────────────────────────────┘
|
||||
|
||||
CLICKS "NEXT LEVEL":
|
||||
▼ PassModal closed, PageLevel.nextLevel()
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Stack: [PageHome, PageLevel] │
|
||||
│ PageLevel loads next level config │
|
||||
│ PassModal destroyed │
|
||||
└────────────────────────────────────────────┘
|
||||
|
||||
CLICKS BACK FROM PageLevel:
|
||||
▼ PageLevel.onIconSettingClick() → ViewManager.back()
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Stack: [PageHome] │
|
||||
│ PageLevel._doHide() called │
|
||||
│ PageLevel destroyed (cache=true, not kept) │
|
||||
│ PageHome._doShow() called │
|
||||
└────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Communication Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ ViewManager │
|
||||
│ (Singleton) │
|
||||
└──────────┬──────────┘
|
||||
│
|
||||
┌──────────────┼──────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
open() back() replace()
|
||||
│ │ │
|
||||
│ │ │
|
||||
┌───────────┴────┐ ┌───┴────┐ ┌──┴───────┐
|
||||
│ │ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼ ▼
|
||||
PageHome PageLevel PassModal (back) (new page)
|
||||
│ │ │
|
||||
│ ├─ Timer ────┐
|
||||
│ │ │
|
||||
│ ├─ Points │
|
||||
│ │ ↑ │
|
||||
│ │ │ │
|
||||
▼ ▼ │ ▼
|
||||
ToastMgr Hints │ PassModal
|
||||
│ │ │
|
||||
├──────┤ └──▶ Share to WX
|
||||
│ │
|
||||
Unlock Earn Points
|
||||
Consume (UserAssets)
|
||||
(check hasPoints)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow: Level Completion
|
||||
|
||||
```
|
||||
USER ENTERS ANSWER:
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ PageLevel.onSubmitAnswer() │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
│
|
||||
├─ getAnswer() ──▶ [Retrieve from EditBox]
|
||||
│
|
||||
├─ Compare with _currentConfig.answer
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────────────┐
|
||||
│ CORRECT ANSWER │
|
||||
└────────────────────────────────────────┘
|
||||
│
|
||||
├─ _isTransitioning = true [Prevent double-submit]
|
||||
│
|
||||
├─ stopCountdown()
|
||||
│
|
||||
├─ playSuccessSound()
|
||||
│
|
||||
├─ Calculate: timeSpent = 60 - _countdown
|
||||
│
|
||||
├─┐ Normal Mode:
|
||||
│ │
|
||||
│ └─▶ UserAssetsManager.earnPoint(levelId, timeSpent)
|
||||
│ │
|
||||
│ ▼
|
||||
│ └─ UPDATE SERVER + LOCAL
|
||||
│ └─ Get points amount
|
||||
│ └─ PageLevel.updatePointsLabel()
|
||||
│
|
||||
├─┐ Share Mode:
|
||||
│ │
|
||||
│ └─▶ ShareManager.reportLevelProgress(...)
|
||||
│ │
|
||||
│ ▼
|
||||
│ └─ SEND TO SERVER (fire-and-forget)
|
||||
│
|
||||
├─ _showPassModal()
|
||||
│ │
|
||||
│ ├─ instantiate(passModalPrefab)
|
||||
│ │
|
||||
│ ├─ Set z-index = 999 (topmost)
|
||||
│ │
|
||||
│ ├─ Add to Canvas
|
||||
│ │
|
||||
│ └─ Call passModal.onViewLoad() + onViewShow()
|
||||
│
|
||||
└─ WAIT FOR USER:
|
||||
│
|
||||
├─ [Next Level] ──▶ PassModal closed
|
||||
│ │
|
||||
│ ▼
|
||||
│ nextLevel()
|
||||
│ │
|
||||
│ ┌────────┴────────┐
|
||||
│ │ No More Levels │ Next Level
|
||||
│ ▼ ▼
|
||||
│ BACK HOME Load & Display
|
||||
│ Restart Timer
|
||||
│
|
||||
└─ [Share] ──▶ WxSDK.shareAppMessage()
|
||||
│
|
||||
└─ Modal stays open
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hint Unlocking Flow
|
||||
|
||||
```
|
||||
USER CLICKS UNLOCK BUTTON:
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ PageLevel.onUnlockClue(index: 2 or 3) │
|
||||
└──────────────────────────────────────────────┘
|
||||
│
|
||||
├─ Check: _isUnlocking == true?
|
||||
│ └─ YES: Return immediately (prevent double-click)
|
||||
│ └─ NO: Continue
|
||||
│
|
||||
├─ Check: StorageManager.hasPoints()?
|
||||
│ └─ NO: Show toast "积分不足!"
|
||||
│ └─ YES: Continue
|
||||
│
|
||||
├─ Set: _isUnlocking = true
|
||||
│
|
||||
├─ await UserAssetsManager.consumePoint(levelId, index)
|
||||
│ │
|
||||
│ ├─ ASYNC: Contact server/storage
|
||||
│ │
|
||||
│ └─ Returns: success boolean
|
||||
│
|
||||
├─ If success:
|
||||
│ │
|
||||
│ ├─ updatePointsLabel()
|
||||
│ │
|
||||
│ ├─ playClickSound()
|
||||
│ │
|
||||
│ ├─ hideUnlockButton(index)
|
||||
│ │
|
||||
│ ├─ showClue(index)
|
||||
│ │
|
||||
│ └─ setClue(index, config.clueN)
|
||||
│
|
||||
├─ If failed:
|
||||
│ │
|
||||
│ └─ Show toast "积分不足!"
|
||||
│
|
||||
└─ Finally: _isUnlocking = false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Timer Sequence Diagram
|
||||
|
||||
```
|
||||
Timeline: 1s 2s 3s ... 59s 60s 61s
|
||||
│ │ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼ ▼
|
||||
countdown: 60 59 58 1 0 (ended)
|
||||
│ │ │ │ │
|
||||
display: "60s" "59s" "58s" ......... "1s" "0s"
|
||||
│ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
|
||||
LEVEL LOAD:
|
||||
│
|
||||
└─ startCountdown()
|
||||
│
|
||||
├─ _countdown = 60
|
||||
├─ _isTimeUp = false
|
||||
└─ schedule(onCountdownTick, 1.0) [Repeat every 1 sec]
|
||||
│
|
||||
▼ (Every 1 second)
|
||||
onCountdownTick()
|
||||
│
|
||||
├─ if (_isTimeUp) return
|
||||
│
|
||||
├─ _countdown-- (60→59→58...→0)
|
||||
│
|
||||
├─ updateClockLabel() [Display: "59s"]
|
||||
│
|
||||
└─ if (_countdown <= 0):
|
||||
│
|
||||
├─ _isTimeUp = true
|
||||
│
|
||||
├─ stopCountdown()
|
||||
│ └─ unschedule(onCountdownTick)
|
||||
│
|
||||
└─ onTimeUp()
|
||||
│
|
||||
└─ playFailSound()
|
||||
|
||||
ANSWER SUBMITTED (Correct):
|
||||
│
|
||||
└─ showSuccess()
|
||||
│
|
||||
├─ stopCountdown()
|
||||
│ └─ Timer stops, no more ticks
|
||||
│
|
||||
└─ _showPassModal()
|
||||
|
||||
OR:
|
||||
|
||||
ANSWER SUBMITTED (Wrong):
|
||||
│
|
||||
└─ Timer continues running...
|
||||
│
|
||||
└─ User keeps playing
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Input Box Creation & Management
|
||||
|
||||
```
|
||||
LEVEL LOADS:
|
||||
│
|
||||
└─ _applyLevelConfig(config)
|
||||
│
|
||||
└─ createSingleInput(config.answer.length)
|
||||
│
|
||||
├─ clearInputNodes()
|
||||
│ │
|
||||
│ └─ Destroy old input nodes
|
||||
│ (If level changed)
|
||||
│
|
||||
├─ Hide inputTemplate
|
||||
│
|
||||
├─ instantiate(inputTemplate)
|
||||
│
|
||||
├─ Set properties:
|
||||
│ │
|
||||
│ ├─ active = true
|
||||
│ ├─ name = 'singleInput'
|
||||
│ ├─ position = (0, 0, 0)
|
||||
│ │
|
||||
│ └─ Get EditBox component
|
||||
│ │
|
||||
│ ├─ placeholder = "(Xlength个字)"
|
||||
│ ├─ maxLength = answerLength
|
||||
│ ├─ string = ""
|
||||
│ │
|
||||
│ └─ Listen events:
|
||||
│ ├─ TEXT_CHANGED → onInputTextChanged()
|
||||
│ └─ EDITING_DID_ENDED → onInputEditingEnded()
|
||||
│
|
||||
├─ Calculate width:
|
||||
│ └─ Math.min(600, Math.max(200, length*60+40))
|
||||
│
|
||||
├─ Set UITransform contentSize to width x 100
|
||||
│
|
||||
├─ Adjust underline width to match
|
||||
│
|
||||
├─ Add to inputLayout
|
||||
│
|
||||
└─ Store in _inputNodes[0]
|
||||
|
||||
USER ENTERS TEXT:
|
||||
│
|
||||
├─ EditBox updates string property
|
||||
└─ TEXT_CHANGED event fires
|
||||
|
||||
USER SUBMITS:
|
||||
│
|
||||
├─ getAnswer()
|
||||
│ │
|
||||
│ └─ _inputNodes[0].getComponent(EditBox).string.trim()
|
||||
│
|
||||
└─ Compare with config.answer
|
||||
|
||||
USER NAVIGATES AWAY:
|
||||
│
|
||||
└─ onViewDestroy() → clearInputNodes()
|
||||
│
|
||||
└─ Destroy all input nodes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Share Challenge Mode Flow
|
||||
|
||||
```
|
||||
LAUNCH FROM WeChat LINK:
|
||||
│
|
||||
└─ PageLoading.start()
|
||||
│
|
||||
└─ _startPreload()
|
||||
│
|
||||
├─ Initialize auth + levels (parallel)
|
||||
│
|
||||
├─ WxSDK.getShareCodeFromLaunch()
|
||||
│ │
|
||||
│ └─ Extract from wx.getLaunchOptionsSync().query
|
||||
│
|
||||
├─ if shareCode exists AND loginSuccess:
|
||||
│ │
|
||||
│ └─ ShareManager.instance.joinShare(shareCode)
|
||||
│ │
|
||||
│ ├─ ASYNC: Fetch share session from server
|
||||
│ │
|
||||
│ ├─ Get shared level set
|
||||
│ │
|
||||
│ └─ Return: success boolean
|
||||
│
|
||||
├─ if (joinSuccess):
|
||||
│ │
|
||||
│ ├─ Set progress = 1
|
||||
│ │
|
||||
│ ├─ ViewManager.open('PageLevel', {
|
||||
│ │ params: { shareMode: true }
|
||||
│ │ })
|
||||
│ │
|
||||
│ └─ Destroy self (PageLoading)
|
||||
│
|
||||
└─ else (normal flow)
|
||||
│
|
||||
└─ Preload PageHome → Open PageHome
|
||||
|
||||
IN SHARE MODE (PageLevel):
|
||||
│
|
||||
├─ onViewLoad():
|
||||
│ │
|
||||
│ ├─ params = getParams()
|
||||
│ ├─ _isShareMode = params?.shareMode === true
|
||||
│ │
|
||||
│ ├─ if shareMode:
|
||||
│ │ └─ currentLevelIndex = 0 (start at first)
|
||||
│ │
|
||||
│ └─ initLevel() loads from ShareManager, not LevelDataManager
|
||||
│
|
||||
├─ showSuccess():
|
||||
│ │
|
||||
│ ├─ if normal mode:
|
||||
│ │ └─ earn points
|
||||
│ │
|
||||
│ └─ if share mode:
|
||||
│ │
|
||||
│ └─ ShareManager.reportLevelProgress(levelId, true, timeSpent)
|
||||
│ │
|
||||
│ └─ FIRE-AND-FORGET (no await)
|
||||
│
|
||||
├─ nextLevel():
|
||||
│ │
|
||||
│ ├─ if NOT shareMode:
|
||||
│ │ └─ StorageManager.onLevelCompleted() [Save progress]
|
||||
│ │
|
||||
│ ├─ Check level count:
|
||||
│ │ │
|
||||
│ │ ├─ Share: ShareManager.getShareLevelCount()
|
||||
│ │ └─ Normal: LevelDataManager.getLevelCount()
|
||||
│ │
|
||||
│ ├─ if (allLevelsComplete):
|
||||
│ │ │
|
||||
│ │ ├─ if shareMode:
|
||||
│ │ │ │
|
||||
│ │ │ ├─ ShareManager.clearShareMode()
|
||||
│ │ │ │
|
||||
│ │ │ └─ ViewManager.replace('PageHome')
|
||||
│ │ │
|
||||
│ │ └─ if normal:
|
||||
│ │ └─ ViewManager.back()
|
||||
│ │
|
||||
│ └─ else (more levels):
|
||||
│ └─ Load next level
|
||||
│
|
||||
└─ Back to PageHome (replaces, clears share state)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ViewManager Caching Mechanism
|
||||
|
||||
```
|
||||
OPEN 'PageHome' (first time):
|
||||
│
|
||||
└─ ViewManager.open('PageHome')
|
||||
│
|
||||
├─ Check cache: _viewCache.get('PageHome')
|
||||
│ └─ Cache miss (undefined)
|
||||
│
|
||||
├─ _instantiateView('PageHome', prefab)
|
||||
│ │
|
||||
│ ├─ instantiate(prefab)
|
||||
│ │
|
||||
│ ├─ Get BaseView component
|
||||
│ │
|
||||
│ ├─ Set viewId, config, params
|
||||
│ │
|
||||
│ ├─ Add to container
|
||||
│ │
|
||||
│ ├─ Call view.onViewLoad() ◄─── Called once
|
||||
│ │
|
||||
│ ├─ if (config.cache === true): ◄─── PageHome has cache:true
|
||||
│ │ └─ _viewCache.set('PageHome', view)
|
||||
│ │
|
||||
│ └─ _showView(view)
|
||||
│ │
|
||||
│ └─ view._doShow()
|
||||
│ └─ view.onViewShow() ◄─── Called now
|
||||
│
|
||||
└─ Stack: [PageHome]
|
||||
|
||||
OPEN 'PageLevel':
|
||||
│
|
||||
└─ ViewManager.open('PageLevel')
|
||||
│
|
||||
├─ PageHome._doHide()
|
||||
│ └─ view.onViewHide() ◄─── First hide
|
||||
│
|
||||
└─ (Same as above for PageLevel)
|
||||
│
|
||||
└─ Stack: [PageHome, PageLevel]
|
||||
|
||||
BACK FROM 'PageLevel':
|
||||
│
|
||||
└─ ViewManager.back()
|
||||
│
|
||||
├─ Pop stack: PageLevel
|
||||
│
|
||||
├─ PageLevel._doHide()
|
||||
│ └─ view.onViewHide()
|
||||
│
|
||||
├─ Decide: shouldDestroy?
|
||||
│ │
|
||||
│ └─ PageLevel has cache:true
|
||||
│ └─ shouldDestroy = false (keep cached)
|
||||
│
|
||||
├─ Get current: PageHome
|
||||
│
|
||||
├─ PageHome._doShow()
|
||||
│ └─ view.onViewShow() ◄─── Called again
|
||||
│
|
||||
└─ Stack: [PageHome]
|
||||
Caches: {PageHome, PageLevel}
|
||||
|
||||
OPEN 'PageLevel' AGAIN (from cache):
|
||||
│
|
||||
└─ ViewManager.open('PageLevel')
|
||||
│
|
||||
├─ Check cache: _viewCache.get('PageLevel')
|
||||
│ └─ Cache hit! (PageLevel instance)
|
||||
│
|
||||
├─ _showView(cachedView)
|
||||
│ │
|
||||
│ ├─ PageHome._doHide()
|
||||
│ │
|
||||
│ └─ cachedView._doShow()
|
||||
│ └─ view.onViewShow() ◄─── Called again (2nd time)
|
||||
│ onViewLoad() NOT called again ◄─── Important!
|
||||
│
|
||||
└─ Stack: [PageHome, PageLevel]
|
||||
Same instance reused
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling Paths
|
||||
|
||||
```
|
||||
LEVEL LOADING ERROR:
|
||||
│
|
||||
├─ initLevel()
|
||||
│ │
|
||||
│ └─ await LevelDataManager.ensureLevelReady(index)
|
||||
│ │
|
||||
│ └─ Returns null (error)
|
||||
│
|
||||
└─ Log warning, return early
|
||||
│
|
||||
└─ UI stays as-is (might be blank)
|
||||
|
||||
INSUFFICIENT POINTS:
|
||||
│
|
||||
└─ onUnlockClue()
|
||||
│
|
||||
├─ StorageManager.hasPoints() → false
|
||||
│
|
||||
└─ ToastManager.show("积分不足!")
|
||||
│
|
||||
└─ User sees notification, unlock blocked
|
||||
|
||||
DOUBLE-SUBMIT PREVENTION:
|
||||
│
|
||||
├─ onSubmitAnswer()
|
||||
│ │
|
||||
│ └─ if (_isTransitioning) return ◄─── Blocks multiple calls
|
||||
│
|
||||
└─ showSuccess()
|
||||
│
|
||||
└─ _isTransitioning = true ◄─── Set to block
|
||||
│
|
||||
└─ After modal shown/closed
|
||||
└─ (Would be reset on nextLevel)
|
||||
|
||||
DOUBLE-CLICK UNLOCK:
|
||||
│
|
||||
└─ onUnlockClue()
|
||||
│
|
||||
└─ if (_isUnlocking) return ◄─── Blocks rapid clicks
|
||||
│
|
||||
└─ _isUnlocking = true at start
|
||||
└─ Finally: _isUnlocking = false ◄─── Reset after async
|
||||
```
|
||||
|
||||
288
DOCS_INDEX.md
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
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,347 +0,0 @@
|
||||
# mp-xieyingeng 项目完整探索报告
|
||||
|
||||
## 📋 项目概述
|
||||
**项目名称**: 写英语谐音梗小游戏 (mp-xieyingeng)
|
||||
**引擎**: Cocos Creator 3.x (TypeScript)
|
||||
**平台**: 微信小游戏
|
||||
**架构**: 分布式页面管理系统 + 单例工具类
|
||||
|
||||
---
|
||||
|
||||
## 📁 完整目录结构
|
||||
|
||||
```
|
||||
assets/
|
||||
├── main.ts # 主入口脚本,初始化 ViewManager
|
||||
├── PageLoading.ts # 加载页面,处理登录、资源预加载、分享码检测
|
||||
├── prefabs/ # 页面预制体和组件
|
||||
│ ├── PageHome.ts # 首页
|
||||
│ ├── PageLevel.ts # 关卡页面(核心游戏逻辑)
|
||||
│ ├── PageWriteLevels.ts # 写关卡页面(创建/编辑关卡)
|
||||
│ ├── PagePreviewLevels.ts # 预览关卡页面
|
||||
│ ├── PagePKData.ts # 挑战数据页面
|
||||
│ ├── PagePKDetail.ts # 挑战详情页面
|
||||
│ ├── PassModal.ts # 通关弹窗
|
||||
│ └── Toast.ts # Toast 提示组件
|
||||
├── scripts/
|
||||
│ ├── config/
|
||||
│ │ └── ApiConfig.ts # API 配置(端点、超时时间等)
|
||||
│ ├── core/
|
||||
│ │ ├── BaseView.ts # 页面基类(生命周期管理)
|
||||
│ │ └── ViewManager.ts # 页面管理器(单例,栈管理)
|
||||
│ ├── types/
|
||||
│ │ ├── LevelTypes.ts # 关卡数据类型定义
|
||||
│ │ └── ApiTypes.ts # API 响应类型定义
|
||||
│ └── utils/ # 工具类(单例)
|
||||
│ ├── HttpUtil.ts # HTTP 请求工具(GET/POST + JWT 认证)
|
||||
│ ├── ShareManager.ts # 分享管理器(创建分享、加入分享)
|
||||
│ ├── LevelDataManager.ts # 关卡数据管理器(API 拉取、缓存、图片加载)
|
||||
│ ├── UserAssetsManager.ts # 用户资产管理器(积分同步)
|
||||
│ ├── AuthManager.ts # 认证管理器(微信登录、Token 管理)
|
||||
│ ├── StorageManager.ts # 本地存储管理器(进度、积分、Token)
|
||||
│ ├── WxSDK.ts # 微信 SDK 封装(登录、分享、震动等)
|
||||
│ ├── ToastManager.ts # Toast 管理器
|
||||
│ └── [其他工具类...]
|
||||
└── resources/ # 游戏资源
|
||||
├── audios/ # 音效文件
|
||||
├── images/
|
||||
│ ├── level/ # 关卡图片
|
||||
│ ├── pageHome/ # 首页图片
|
||||
│ ├── pageLevel/ # 关卡页面图片
|
||||
│ └── pageLoading/ # 加载页面图片
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 所有 TypeScript 文件列表
|
||||
|
||||
### 核心入口
|
||||
- `assets/main.ts` - 主脚本,注册所有页面到 ViewManager
|
||||
- `assets/PageLoading.ts` - 加载页面,并行执行登录 + 资源加载
|
||||
|
||||
### 页面组件(每个继承 BaseView)
|
||||
- `assets/prefabs/PageHome.ts` - 首页
|
||||
- `assets/prefabs/PageLevel.ts` - **核心游戏逻辑**
|
||||
- `assets/prefabs/PageWriteLevels.ts` - 写关卡
|
||||
- `assets/prefabs/PagePreviewLevels.ts` - 预览关卡
|
||||
- `assets/prefabs/PagePKData.ts` - PK 数据展示
|
||||
- `assets/prefabs/PagePKDetail.ts` - PK 详情
|
||||
- `assets/prefabs/PassModal.ts` - 通关弹窗
|
||||
- `assets/prefabs/Toast.ts` - Toast 提示
|
||||
|
||||
### 核心框架
|
||||
- `assets/scripts/core/BaseView.ts` - 页面基类(onViewLoad、onViewShow、onViewHide、onViewDestroy)
|
||||
- `assets/scripts/core/ViewManager.ts` - 页面管理器(栈管理、缓存、生命周期调用)
|
||||
|
||||
### 配置
|
||||
- `assets/scripts/config/ApiConfig.ts` - API 端点 + 超时配置
|
||||
|
||||
### 类型定义
|
||||
- `assets/scripts/types/ApiTypes.ts` - API 响应类型
|
||||
- `assets/scripts/types/LevelTypes.ts` - 关卡数据类型
|
||||
|
||||
### 工具类(单例)
|
||||
- `assets/scripts/utils/HttpUtil.ts` - **HTTP 请求**(GET/POST + JWT)
|
||||
- `assets/scripts/utils/ShareManager.ts` - **分享系统**
|
||||
- `assets/scripts/utils/LevelDataManager.ts` - **关卡数据管理**
|
||||
- `assets/scripts/utils/UserAssetsManager.ts` - 积分管理
|
||||
- `assets/scripts/utils/AuthManager.ts` - **认证 + 登录**
|
||||
- `assets/scripts/utils/StorageManager.ts` - 本地存储
|
||||
- `assets/scripts/utils/WxSDK.ts` - 微信 SDK 封装
|
||||
- `assets/scripts/utils/ToastManager.ts` - Toast 管理
|
||||
- 其他:RoundedRectMask、BackgroundScaler 等
|
||||
|
||||
---
|
||||
|
||||
## 💾 关卡通关逻辑核心
|
||||
|
||||
### 1. 通关判定(PageLevel.ts 第 660-673 行)
|
||||
```typescript
|
||||
onSubmitAnswer(): void {
|
||||
const userAnswer = this.getAnswer();
|
||||
if (userAnswer === this._currentConfig.answer) {
|
||||
this.showSuccess();
|
||||
} else {
|
||||
this.showError();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 通关奖励(PageLevel.ts 第 679-701 行)
|
||||
```typescript
|
||||
private async showSuccess(): Promise<void> {
|
||||
// 停止倒计时
|
||||
this.stopCountdown();
|
||||
|
||||
// 非分享模式才增加积分
|
||||
if (!this._isShareMode) {
|
||||
const levelId = this._currentConfig?.id;
|
||||
const timeSpent = 60 - this._countdown;
|
||||
await UserAssetsManager.instance.earnPoint(levelId, timeSpent);
|
||||
}
|
||||
|
||||
// 显示通关弹窗
|
||||
this._showPassModal();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 进度保存(PageLevel.ts 第 785-816 行)
|
||||
```typescript
|
||||
private async nextLevel(): Promise<void> {
|
||||
// 非分享模式才保存进度
|
||||
if (!this._isShareMode) {
|
||||
StorageManager.onLevelCompleted(this.currentLevelIndex);
|
||||
}
|
||||
|
||||
this.currentLevelIndex++;
|
||||
|
||||
// 检查是否全部通关
|
||||
const totalLevels = this._isShareMode
|
||||
? ShareManager.instance.getShareLevelCount()
|
||||
: LevelDataManager.instance.getLevelCount();
|
||||
|
||||
if (this.currentLevelIndex >= totalLevels) {
|
||||
// 全部通关,返回首页
|
||||
ViewManager.instance.back();
|
||||
} else {
|
||||
// 加载下一关
|
||||
await this.initLevel();
|
||||
this.startCountdown();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 已通关关卡同步(PageLoading.ts 第 115-139 行)
|
||||
```typescript
|
||||
private _syncProgressFromServer(): void {
|
||||
// 服务端返回的已通关关卡 ID
|
||||
const completedIds = AuthManager.instance.completedLevelIds;
|
||||
|
||||
// 转换为本地索引
|
||||
const maxCompletedIndex = LevelDataManager.instance.getMaxCompletedIndex(completedIds);
|
||||
|
||||
// 取较大值,防止进度回退
|
||||
if (maxCompletedIndex > localMax) {
|
||||
StorageManager.onLevelCompleted(maxCompletedIndex);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 API 端点一览
|
||||
|
||||
### 已配置的 API(ApiConfig.ts)
|
||||
```
|
||||
API_BASE = 'https://ilookai.cn/api/v1'
|
||||
|
||||
端点:
|
||||
- POST /auth/wx-login # 微信登录
|
||||
- GET /user/assets # 获取用户积分
|
||||
- POST /user/assets/consume # 消耗积分(解锁线索)
|
||||
- POST /user/assets/earn # 获得积分(通关奖励)
|
||||
- GET /user/game-data # 获取用户数据(进度 + 积分)
|
||||
- GET /wechat-game/levels # 获取所有关卡
|
||||
- POST /share # 创建分享
|
||||
- POST /share/{code}/join # 加入分享
|
||||
- GET /user/info # 获取用户信息
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 架构特点
|
||||
|
||||
### 1. 单例模式
|
||||
- `ViewManager` - 页面管理
|
||||
- `LevelDataManager` - 关卡数据
|
||||
- `ShareManager` - 分享管理
|
||||
- `UserAssetsManager` - 积分管理
|
||||
- `AuthManager` - 认证
|
||||
- `StorageManager` - 本地存储(全静态)
|
||||
- `ToastManager` - Toast 管理
|
||||
- `WxSDK` - 微信 SDK(全静态)
|
||||
- `HttpUtil` - HTTP 工具(全静态)
|
||||
|
||||
### 2. 页面栈管理
|
||||
- `ViewManager` 维护页面栈
|
||||
- `open()` - 打开页面,压栈
|
||||
- `back()` - 返回上一页,出栈
|
||||
- `replace()` - 替换当前页,不压栈
|
||||
|
||||
### 3. 生命周期
|
||||
每个页面 4 个阶段:
|
||||
- `onViewLoad()` - 首次创建时调用
|
||||
- `onViewShow()` - 每次显示时调用
|
||||
- `onViewHide()` - 隐藏时调用
|
||||
- `onViewDestroy()` - 销毁时调用
|
||||
|
||||
---
|
||||
|
||||
## 🎯 关键发现
|
||||
|
||||
### ✅ 已有的工具类
|
||||
|
||||
#### HTTP 请求
|
||||
- **HttpUtil.ts** - GET/POST + JWT 认证
|
||||
- 支持自定义超时时间
|
||||
- 自动添加 Authorization 头
|
||||
- 泛型支持
|
||||
|
||||
#### 数据管理
|
||||
- **LevelDataManager.ts** - 关卡数据 + 图片缓存
|
||||
- API 请求重试机制
|
||||
- 图片懒加载(预加载下一关)
|
||||
- URL -> SpriteFrame 缓存
|
||||
|
||||
- **UserAssetsManager.ts** - 积分管理
|
||||
- 消耗积分(解锁线索)
|
||||
- 获得积分(通关奖励)
|
||||
- 自动降级本地处理
|
||||
|
||||
- **AuthManager.ts** - 认证 + 登录
|
||||
- 微信登录流程
|
||||
- Token 恢复与验证
|
||||
- 获取通关进度
|
||||
|
||||
- **StorageManager.ts** - 本地存储
|
||||
- 积分、Token、进度、用户信息
|
||||
- 全静态工具类
|
||||
|
||||
#### 游戏逻辑
|
||||
- **ShareManager.ts** - 分享系统
|
||||
- 创建分享、加入分享
|
||||
- 独立数据管理,不影响正常进度
|
||||
|
||||
- **ViewManager.ts** - 页面管理
|
||||
- 栈管理
|
||||
- 缓存机制
|
||||
- 生命周期管理
|
||||
|
||||
- **WxSDK.ts** - 微信 API 封装
|
||||
- 登录、分享、震动
|
||||
- 隐私授权、用户信息
|
||||
- 非微信环境自动降级
|
||||
|
||||
---
|
||||
|
||||
## 📊 游戏流程图
|
||||
|
||||
### 正常模式
|
||||
```
|
||||
启动 → PageLoading
|
||||
├─ 并行加载:登录 + 关卡数据
|
||||
├─ 检测分享码(无)
|
||||
└─ 打开 PageHome
|
||||
├─ 开始游戏 → PageLevel
|
||||
│ ├─ 加载关卡
|
||||
│ ├─ 倒计时 60s
|
||||
│ ├─ 提交答案
|
||||
│ ├─ 判定成功/失败
|
||||
│ ├─ 通关 → PassModal
|
||||
│ │ ├─ earnPoint()(加积分)
|
||||
│ │ ├─ onLevelCompleted()(保存进度)
|
||||
│ │ └─ nextLevel()
|
||||
│ └─ 重复 2-7
|
||||
└─ PK → PageWriteLevels
|
||||
```
|
||||
|
||||
### 分享模式
|
||||
```
|
||||
微信分享链接(含 shareCode)
|
||||
↓
|
||||
PageLoading
|
||||
├─ 检测到分享码
|
||||
└─ ShareManager.joinShare(code)
|
||||
↓
|
||||
PageLevel(shareMode=true)
|
||||
├─ 从 ShareManager 加载关卡
|
||||
├─ 不增加积分
|
||||
├─ 不保存本地进度
|
||||
└─ 全部通关 → 返回首页
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 核心要点
|
||||
|
||||
1. **HTTP 工具** ✅
|
||||
- HttpUtil.ts 已完整实现
|
||||
- 支持 JWT 认证
|
||||
- 可配置超时
|
||||
|
||||
2. **关卡数据** ✅
|
||||
- LevelDataManager 从 API 拉取
|
||||
- 支持图片缓存 + 懒加载
|
||||
- 支持重试机制
|
||||
|
||||
3. **通关逻辑** ✅
|
||||
- 判定:字符串比对(PageLevel.ts:660)
|
||||
- 奖励:earnPoint()(PageLevel.ts:679)
|
||||
- 进度:StorageManager.onLevelCompleted()(PageLevel.ts:785)
|
||||
- 服务端同步:PageLoading.ts:115
|
||||
|
||||
4. **分享系统** ✅
|
||||
- 创建 + 加入完全独立
|
||||
- 不影响正常游戏进度
|
||||
- 懒加载关卡数据
|
||||
|
||||
5. **页面管理** ✅
|
||||
- ViewManager 栈管理
|
||||
- 4 个生命周期回调
|
||||
- 缓存机制
|
||||
|
||||
6. **认证系统** ✅
|
||||
- 微信登录 + Token 恢复
|
||||
- 自动添加授权头
|
||||
- 获取用户通关记录
|
||||
|
||||
7. **本地存储** ✅
|
||||
- StorageManager 集中管理
|
||||
- 支持进度 + 积分 + Token
|
||||
- 带有默认值和数据校验
|
||||
|
||||
8. **微信 API** ✅
|
||||
- WxSDK 完整封装
|
||||
- 非微信环境自动降级
|
||||
- 支持分享、登录、震动等
|
||||
|
||||
@@ -1,272 +0,0 @@
|
||||
# 快速文件参考指南
|
||||
|
||||
## 🚀 最重要的 5 个文件
|
||||
|
||||
### 1. **PageLevel.ts** - 核心游戏逻辑
|
||||
位置:`assets/prefabs/PageLevel.ts`
|
||||
```
|
||||
关键方法:
|
||||
- onViewLoad() → 初始化关卡
|
||||
- onSubmitAnswer() → 第 660 行,提交答案判定
|
||||
- showSuccess() → 第 679 行,通关逻辑
|
||||
- nextLevel() → 第 785 行,进度保存
|
||||
```
|
||||
|
||||
### 2. **HttpUtil.ts** - HTTP 请求工具
|
||||
位置:`assets/scripts/utils/HttpUtil.ts`
|
||||
```
|
||||
关键方法:
|
||||
- get<T>(url, timeout) → GET 请求
|
||||
- post<T>(url, data, timeout) → POST 请求
|
||||
- setAuthToken(token) → 设置 JWT
|
||||
```
|
||||
|
||||
### 3. **LevelDataManager.ts** - 关卡数据管理
|
||||
位置:`assets/scripts/utils/LevelDataManager.ts`
|
||||
```
|
||||
关键方法:
|
||||
- initialize(onProgress) → API 加载 + 预加载第一关
|
||||
- ensureLevelReady(index) → 按需加载关卡
|
||||
- preloadNextLevel(index) → 静默预加载下一关
|
||||
- getMaxCompletedIndex(ids) → 获取已通关索引
|
||||
```
|
||||
|
||||
### 4. **ShareManager.ts** - 分享系统
|
||||
位置:`assets/scripts/utils/ShareManager.ts`
|
||||
```
|
||||
关键方法:
|
||||
- createShare(title, levelIds) → 创建分享
|
||||
- joinShare(code) → 加入分享
|
||||
- triggerWxShare(title, code) → 触发分享
|
||||
- isShareMode → 判断是否分享模式
|
||||
```
|
||||
|
||||
### 5. **AuthManager.ts** - 认证管理
|
||||
位置:`assets/scripts/utils/AuthManager.ts`
|
||||
```
|
||||
关键方法:
|
||||
- initialize() → 初始化(恢复 token 或微信登录)
|
||||
- wxLogin() → 微信登录
|
||||
- validateToken() → 验证 token 有效性
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 TypeScript 文件快速导航
|
||||
|
||||
### 文件位置速查表
|
||||
|
||||
| 文件名 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| main.ts | assets/ | 主入口,初始化 ViewManager |
|
||||
| PageLoading.ts | assets/ | 加载页面,登录 + 资源加载 |
|
||||
| PageHome.ts | assets/prefabs/ | 首页 |
|
||||
| PageLevel.ts | assets/prefabs/ | 关卡页面 **⭐** |
|
||||
| PageWriteLevels.ts | assets/prefabs/ | 写关卡页面 |
|
||||
| PagePreviewLevels.ts | assets/prefabs/ | 预览关卡 |
|
||||
| PassModal.ts | assets/prefabs/ | 通关弹窗 |
|
||||
| Toast.ts | assets/prefabs/ | Toast 提示 |
|
||||
| BaseView.ts | assets/scripts/core/ | 页面基类 |
|
||||
| ViewManager.ts | assets/scripts/core/ | 页面管理器 |
|
||||
| ApiConfig.ts | assets/scripts/config/ | API 配置 |
|
||||
| ApiTypes.ts | assets/scripts/types/ | API 类型定义 |
|
||||
| LevelTypes.ts | assets/scripts/types/ | 关卡类型定义 |
|
||||
| HttpUtil.ts | assets/scripts/utils/ | HTTP 工具 **⭐** |
|
||||
| ShareManager.ts | assets/scripts/utils/ | 分享管理 **⭐** |
|
||||
| LevelDataManager.ts | assets/scripts/utils/ | 关卡数据 **⭐** |
|
||||
| UserAssetsManager.ts | assets/scripts/utils/ | 积分管理 |
|
||||
| AuthManager.ts | assets/scripts/utils/ | 认证管理 **⭐** |
|
||||
| StorageManager.ts | assets/scripts/utils/ | 本地存储 |
|
||||
| WxSDK.ts | assets/scripts/utils/ | 微信 SDK |
|
||||
| ToastManager.ts | assets/scripts/utils/ | Toast 管理 |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 API 端点速查
|
||||
|
||||
```
|
||||
基础地址:https://ilookai.cn/api/v1
|
||||
|
||||
认证相关:
|
||||
- POST /auth/wx-login 微信登录
|
||||
|
||||
用户资产:
|
||||
- GET /user/assets 获取积分
|
||||
- POST /user/assets/consume 消耗积分(解锁线索)
|
||||
- POST /user/assets/earn 获得积分(通关)
|
||||
- GET /user/game-data 获取用户数据
|
||||
|
||||
关卡相关:
|
||||
- GET /wechat-game/levels 获取所有关卡
|
||||
|
||||
分享相关:
|
||||
- POST /share 创建分享
|
||||
- POST /share/{code}/join 加入分享
|
||||
|
||||
用户相关:
|
||||
- GET /user/info 获取用户信息
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💾 关键数据结构
|
||||
|
||||
### 关卡配置
|
||||
```typescript
|
||||
interface RuntimeLevelConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
spriteFrame: SpriteFrame | null;
|
||||
clue1: string;
|
||||
clue2: string;
|
||||
clue3: string;
|
||||
answer: string;
|
||||
}
|
||||
```
|
||||
|
||||
### API 响应
|
||||
```typescript
|
||||
interface ApiEnvelope<T> {
|
||||
success: boolean;
|
||||
data: T | null;
|
||||
message: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
### 用户进度
|
||||
```typescript
|
||||
interface UserProgress {
|
||||
currentLevelIndex: number; // 当前关卡(0-based)
|
||||
maxUnlockedLevelIndex: number; // 最高已解锁
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎮 游戏流程关键代码位置
|
||||
|
||||
| 步骤 | 文件 | 行数 | 描述 |
|
||||
|-----|------|------|------|
|
||||
| 初始化 | main.ts | 34-90 | 注册页面 |
|
||||
| 加载 | PageLoading.ts | 27-90 | 并行登录 + 加载关卡 |
|
||||
| 分享检测 | PageLoading.ts | 61-77 | 检测分享码 |
|
||||
| 进度同步 | PageLoading.ts | 115-139 | 服务端进度同步 |
|
||||
| 加载关卡 | PageLevel.ts | 175-197 | 初始化关卡 |
|
||||
| 倒计时 | PageLevel.ts | 593-641 | 60 秒计时 |
|
||||
| 提交答案 | PageLevel.ts | 660-673 | 判定答案 |
|
||||
| 通关处理 | PageLevel.ts | 679-701 | 播放音效 + 加积分 + 弹窗 |
|
||||
| 进度保存 | PageLevel.ts | 785-816 | 下一关 + 进度保存 |
|
||||
|
||||
---
|
||||
|
||||
## 🔗 工具类单例调用方式
|
||||
|
||||
```typescript
|
||||
// HTTP 请求
|
||||
HttpUtil.get<T>(url, timeout)
|
||||
HttpUtil.post<T>(url, data, timeout)
|
||||
HttpUtil.setAuthToken(token)
|
||||
|
||||
// 关卡数据
|
||||
LevelDataManager.instance.initialize(onProgress)
|
||||
LevelDataManager.instance.ensureLevelReady(index)
|
||||
LevelDataManager.instance.getLevelCount()
|
||||
|
||||
// 用户资产
|
||||
UserAssetsManager.instance.fetchPoints()
|
||||
UserAssetsManager.instance.consumePoint(levelId, hintIndex)
|
||||
UserAssetsManager.instance.earnPoint(levelId, timeSpent)
|
||||
|
||||
// 认证
|
||||
AuthManager.instance.initialize()
|
||||
AuthManager.instance.isLoggedIn
|
||||
AuthManager.instance.userId
|
||||
|
||||
// 本地存储
|
||||
StorageManager.getPoints()
|
||||
StorageManager.setPoints(points)
|
||||
StorageManager.getCurrentLevelIndex()
|
||||
StorageManager.onLevelCompleted(index)
|
||||
|
||||
// 分享
|
||||
ShareManager.instance.createShare(title, levelIds)
|
||||
ShareManager.instance.joinShare(code)
|
||||
ShareManager.instance.isShareMode
|
||||
|
||||
// 微信 API
|
||||
WxSDK.isWechat()
|
||||
WxSDK.login()
|
||||
WxSDK.shareAppMessage(config)
|
||||
|
||||
// 页面管理
|
||||
ViewManager.instance.open(viewId, options)
|
||||
ViewManager.instance.back()
|
||||
ViewManager.instance.replace(viewId, options)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 优先级指南(修改时参考)
|
||||
|
||||
### 优先级 A(核心,谨慎修改)
|
||||
- `PageLevel.ts` - 游戏逻辑
|
||||
- `HttpUtil.ts` - HTTP 请求
|
||||
- `LevelDataManager.ts` - 数据加载
|
||||
- `ViewManager.ts` - 页面管理
|
||||
|
||||
### 优先级 B(重要)
|
||||
- `ShareManager.ts` - 分享系统
|
||||
- `AuthManager.ts` - 认证系统
|
||||
- `StorageManager.ts` - 本地存储
|
||||
- `UserAssetsManager.ts` - 积分管理
|
||||
|
||||
### 优先级 C(可选)
|
||||
- `WxSDK.ts` - 微信 API
|
||||
- `ToastManager.ts` - 提示管理
|
||||
- 其他 UI 文件
|
||||
|
||||
---
|
||||
|
||||
## 🎯 常见修改清单
|
||||
|
||||
### 修改 API 端点
|
||||
→ `assets/scripts/config/ApiConfig.ts`
|
||||
|
||||
### 修改通关逻辑
|
||||
→ `assets/prefabs/PageLevel.ts`(第 660-816 行)
|
||||
|
||||
### 修改关卡数据加载
|
||||
→ `assets/scripts/utils/LevelDataManager.ts`
|
||||
|
||||
### 修改积分系统
|
||||
→ `assets/scripts/utils/UserAssetsManager.ts`
|
||||
|
||||
### 修改分享流程
|
||||
→ `assets/scripts/utils/ShareManager.ts`
|
||||
|
||||
### 修改页面流转
|
||||
→ `assets/scripts/core/ViewManager.ts`
|
||||
|
||||
### 修改本地存储
|
||||
→ `assets/scripts/utils/StorageManager.ts`
|
||||
|
||||
---
|
||||
|
||||
## 📞 快速查找
|
||||
|
||||
**如果要找 xxx 功能:**
|
||||
|
||||
| 功能 | 查看 |
|
||||
|-----|------|
|
||||
| HTTP 请求 | HttpUtil.ts |
|
||||
| 关卡加载 | LevelDataManager.ts |
|
||||
| 通关判定 | PageLevel.ts:660 |
|
||||
| 通关奖励 | PageLevel.ts:679 |
|
||||
| 进度保存 | PageLevel.ts:785 |
|
||||
| 分享功能 | ShareManager.ts |
|
||||
| 登录流程 | AuthManager.ts |
|
||||
| 本地数据 | StorageManager.ts |
|
||||
| 页面跳转 | ViewManager.ts |
|
||||
| 微信功能 | WxSDK.ts |
|
||||
| Toast 提示 | ToastManager.ts |
|
||||
|
||||
@@ -1,348 +0,0 @@
|
||||
# UI Components - Quick Reference Guide
|
||||
|
||||
## Component Overview
|
||||
|
||||
| Component | Purpose | Extends | Key Responsibilities |
|
||||
|-----------|---------|---------|----------------------|
|
||||
| **main.ts** | App bootstrap | Component | Register pages, init ViewManager & ToastManager |
|
||||
| **PageLoading.ts** | Splash screen | Component | Load data, sync progress, detect share code |
|
||||
| **PageHome.ts** | Landing page | BaseView | Navigation hub (game/PK buttons) |
|
||||
| **PageLevel.ts** | Game level | BaseView | Core gameplay (timer, hints, scoring, input) |
|
||||
| **PagePreviewLevels.ts** | Level preview | BaseView | Scrollable list of selected levels |
|
||||
| **PassModal.ts** | Completion modal | BaseView | Next level & share buttons, success sound |
|
||||
| **Toast.ts** | Notification | Component | Display message with fade animation |
|
||||
| **ToastManager.ts** | Toast system | Singleton | Centralized toast creation & display |
|
||||
| **BaseView.ts** | Page base class | Component | Lifecycle interface for all pages |
|
||||
| **ViewManager.ts** | Page manager | Singleton | Navigation, stacking, caching, lifecycle |
|
||||
|
||||
---
|
||||
|
||||
## Lifecycle Stages
|
||||
|
||||
### Page Lifecycle (BaseView)
|
||||
```
|
||||
onViewLoad() → onViewShow() → onViewHide() → onViewDestroy()
|
||||
(once) (each show) (each hide) (on destroy)
|
||||
```
|
||||
|
||||
### App Startup Flow
|
||||
```
|
||||
main.onLoad()
|
||||
↓ (Initialize ViewManager + register pages)
|
||||
PageLoading.start()
|
||||
↓ (Load auth + levels in parallel, check share code)
|
||||
PageHome (normal) OR PageLevel (share mode)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Data Flows
|
||||
|
||||
### Level Progression
|
||||
```
|
||||
PageLevel loads config → Displays image + clue1 → User enters answer
|
||||
↓ (correct) → Earn points → Show PassModal → Next level
|
||||
↓ (wrong) → Show toast → Continue playing
|
||||
↓ (timeout) → Play fail sound
|
||||
```
|
||||
|
||||
### Hint Unlocking
|
||||
```
|
||||
User clicks unlock button → Check points available
|
||||
↓ (yes) → Consume point from UserAssetsManager
|
||||
↓ → Hide unlock button, show clue
|
||||
↓ (no) → Show "insufficient points" toast
|
||||
```
|
||||
|
||||
### Share Challenge Mode
|
||||
```
|
||||
WeChat link → PageLoading detects share code
|
||||
↓ → ShareManager.joinShare(code)
|
||||
↓ → Play through shared levels (doesn't save local progress)
|
||||
↓ → Report progress to server
|
||||
↓ → Return to PageHome
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Component Properties Summary
|
||||
|
||||
### PageLevel (Most Complex)
|
||||
**UI Elements:**
|
||||
- inputLayout, submitButton, inputTemplate, actionNode
|
||||
- iconSetting (back button)
|
||||
- tipsLayout, tipsItem1/2/3 (clues)
|
||||
- unLockItem2/3 (unlock buttons)
|
||||
- clockLabel (timer), liveLabel (points)
|
||||
- mainImage (level image)
|
||||
|
||||
**Audio:**
|
||||
- clickAudio, successAudio, failAudio
|
||||
|
||||
**Internal State:**
|
||||
- _countdown (60 sec timer)
|
||||
- _isTimeUp (timer expired flag)
|
||||
- _currentConfig (level data)
|
||||
- _isTransitioning (prevent double-submit)
|
||||
- _isUnlocking (prevent double-click unlock)
|
||||
- _passModalNode (modal reference)
|
||||
- _isShareMode (shared vs normal)
|
||||
|
||||
**Key Methods:**
|
||||
- onViewLoad/Show/Hide/Destroy (lifecycle)
|
||||
- initLevel() (async load config)
|
||||
- createSingleInput(length) (input box)
|
||||
- onUnlockClue(index) (consume points for hints)
|
||||
- onSubmitAnswer() (check answer)
|
||||
- showSuccess() (correct: earn points, show modal)
|
||||
- showError() (wrong: toast + vibration)
|
||||
- nextLevel() (progress to next)
|
||||
- startCountdown() / onCountdownTick() (60s timer)
|
||||
|
||||
---
|
||||
|
||||
## Points & Scoring System
|
||||
|
||||
**Earning Points:**
|
||||
- `UserAssetsManager.earnPoint(levelId, timeSpent)`
|
||||
- Called in PageLevel.showSuccess()
|
||||
- Time spent = 60 - countdown
|
||||
|
||||
**Consuming Points:**
|
||||
- `UserAssetsManager.consumePoint(levelId, hintIndex)`
|
||||
- Called in PageLevel.onUnlockClue()
|
||||
- Check `StorageManager.hasPoints()` before consuming
|
||||
|
||||
**Displaying Points:**
|
||||
- `StorageManager.getPoints()` → Display as "x {points}"
|
||||
- Called in PageLevel.updatePointsLabel()
|
||||
|
||||
---
|
||||
|
||||
## Timer System
|
||||
|
||||
**60-Second Countdown:**
|
||||
- Starts when level loads: `startCountdown()`
|
||||
- Ticks every 1 second: `onCountdownTick()`
|
||||
- Displayed as: "60s", "59s", ..., "0s"
|
||||
- On timeout: plays fail sound, doesn't end game
|
||||
|
||||
**Stop Timer:**
|
||||
- `stopCountdown()` called when:
|
||||
- Answer submitted (correct)
|
||||
- Page destroyed
|
||||
- All levels completed
|
||||
|
||||
---
|
||||
|
||||
## Hint/Clue System
|
||||
|
||||
**3 Clues Per Level:**
|
||||
1. **Clue 1** - Always visible (free)
|
||||
2. **Clue 2** - Unlock button, costs points
|
||||
3. **Clue 3** - Unlock button, costs points
|
||||
|
||||
**Display:**
|
||||
- Text in tipsItem1/2/3 nodes
|
||||
- Hidden if locked (tipsItem.active = false)
|
||||
- Unlock button visible if locked
|
||||
|
||||
**Unlock Flow:**
|
||||
1. User clicks unLockItem2 or unLockItem3
|
||||
2. Check points: `StorageManager.hasPoints()`
|
||||
3. Consume: `UserAssetsManager.consumePoint(levelId, index)`
|
||||
4. Hide button, show clue, update UI
|
||||
|
||||
---
|
||||
|
||||
## Navigation Stack
|
||||
|
||||
**Structure:**
|
||||
- LIFO stack managed by ViewManager
|
||||
- Each open() adds to stack
|
||||
- back() pops from stack
|
||||
- replace() swaps top
|
||||
|
||||
**Example Session:**
|
||||
```
|
||||
[PageHome]
|
||||
↓ open PageLevel
|
||||
[PageHome, PageLevel]
|
||||
↓ open PassModal (or inline)
|
||||
[PageHome, PageLevel, PassModal?]
|
||||
↓ close/back
|
||||
[PageHome]
|
||||
```
|
||||
|
||||
**Methods:**
|
||||
- `ViewManager.open(viewId, options?)` - Push to stack
|
||||
- `ViewManager.back()` - Pop from stack, show previous
|
||||
- `ViewManager.replace(viewId, options?)` - Pop current, push new
|
||||
|
||||
---
|
||||
|
||||
## Caching Strategy
|
||||
|
||||
**Cached Views (default):**
|
||||
- Instance reused on re-open
|
||||
- onViewLoad() called once
|
||||
- onViewShow() called each time
|
||||
- Memory persists
|
||||
|
||||
**Non-Cached Views:**
|
||||
- New instance each time
|
||||
- onViewLoad() called each time
|
||||
- Memory released on close
|
||||
|
||||
**Configuration:**
|
||||
```typescript
|
||||
// In main.ts registration
|
||||
ViewManager.instance.register('PageHome', {
|
||||
prefab: pageHomePrefab,
|
||||
cache: true, // ← Reuse instance
|
||||
zIndex: 0 // ← Layer depth
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Toast System
|
||||
|
||||
**Show Toast:**
|
||||
```typescript
|
||||
ToastManager.show("消息内容", 2000); // duration in ms
|
||||
```
|
||||
|
||||
**Initialization (main.ts):**
|
||||
```typescript
|
||||
ToastManager.instance.init(toastPrefab, canvasNode);
|
||||
```
|
||||
|
||||
**Toast Behavior:**
|
||||
- Creates Toast instance from prefab
|
||||
- Displays for duration (default 2000ms)
|
||||
- Fades out over 300ms
|
||||
- Auto-destroys
|
||||
|
||||
---
|
||||
|
||||
## WeChat Integration
|
||||
|
||||
**Share Initialization (PageHome):**
|
||||
```typescript
|
||||
WxSDK.initShare({
|
||||
title: '写英语',
|
||||
imageUrl: '',
|
||||
query: ''
|
||||
});
|
||||
```
|
||||
|
||||
**Share in Challenge (PassModal):**
|
||||
```typescript
|
||||
WxSDK.shareAppMessage({
|
||||
title: '快来一起玩这款游戏吧',
|
||||
query: `level={levelIndex}`
|
||||
});
|
||||
```
|
||||
|
||||
**Share Code Detection (PageLoading):**
|
||||
```typescript
|
||||
const shareCode = WxSDK.getShareCodeFromLaunch();
|
||||
if (shareCode) {
|
||||
const joined = await ShareManager.instance.joinShare(shareCode);
|
||||
// Launch PageLevel in share mode
|
||||
}
|
||||
```
|
||||
|
||||
**Other WeChat Features:**
|
||||
- `WxSDK.vibrateLong()` - Haptic feedback on wrong answer
|
||||
- `WxSDK.isWechat()` - Check if running in WeChat
|
||||
- `checkPrivacySetting()` - Check privacy authorization
|
||||
- `requirePrivacyAuthorize()` - Prompt for privacy consent
|
||||
|
||||
---
|
||||
|
||||
## Error Handling & Edge Cases
|
||||
|
||||
**Level Loading:**
|
||||
- Try cache first, then async load
|
||||
- Preload next level without blocking
|
||||
- Handle missing config gracefully
|
||||
|
||||
**Point Consumption:**
|
||||
- Check availability before consuming
|
||||
- Show toast if insufficient
|
||||
- Prevent double-click with flag
|
||||
|
||||
**Answer Submission:**
|
||||
- Prevent multiple submissions with transition flag
|
||||
- Trim whitespace from answer
|
||||
- Case-sensitive comparison
|
||||
|
||||
**Page Navigation:**
|
||||
- Share mode: clears share state before returning home
|
||||
- Normal mode: simple back() navigation
|
||||
- Modal: stays on top (z-index 999)
|
||||
|
||||
---
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Add Toast
|
||||
```typescript
|
||||
ToastManager.show('提示信息');
|
||||
```
|
||||
|
||||
### Navigate to Page
|
||||
```typescript
|
||||
ViewManager.instance.open('PageLevel'); // Push
|
||||
ViewManager.instance.back(); // Pop
|
||||
ViewManager.instance.replace('PageHome');// Swap
|
||||
```
|
||||
|
||||
### Get Current Level
|
||||
```typescript
|
||||
const index = StorageManager.getCurrentLevelIndex();
|
||||
```
|
||||
|
||||
### Check/Consume Points
|
||||
```typescript
|
||||
if (StorageManager.hasPoints()) {
|
||||
await UserAssetsManager.consumePoint(levelId, hintIndex);
|
||||
}
|
||||
```
|
||||
|
||||
### Start Game
|
||||
```typescript
|
||||
// From PageHome
|
||||
ViewManager.instance.open('PageLevel');
|
||||
```
|
||||
|
||||
### Create & Share Challenge
|
||||
```typescript
|
||||
// User flow:
|
||||
PageHome → [PK Button] → PageWriteLevels [Select 6]
|
||||
→ PagePreviewLevels [Verify]
|
||||
→ PassModal [Share Button]
|
||||
→ WxSDK.shareAppMessage()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Size & Complexity
|
||||
|
||||
| File | Lines | Complexity |
|
||||
|------|-------|-----------|
|
||||
| main.ts | 92 | Simple (init only) |
|
||||
| PageLoading.ts | 141 | Medium (parallel loading, sync) |
|
||||
| PageHome.ts | 119 | Simple (two buttons) |
|
||||
| PageLevel.ts | 823 | **Very High** (core game logic) |
|
||||
| PagePreviewLevels.ts | 247 | Medium (scroll list) |
|
||||
| PassModal.ts | 155 | Simple (two buttons) |
|
||||
| Toast.ts | 50 | Simple (fade animation) |
|
||||
| ToastManager.ts | 59 | Simple (factory pattern) |
|
||||
| BaseView.ts | 132 | Medium (lifecycle) |
|
||||
| ViewManager.ts | 320 | High (stack navigation) |
|
||||
|
||||
**Total: ~2,138 lines** | **Focal Point: PageLevel.ts (38% of code)**
|
||||
|
||||
416
SUMMARY.md
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.
|
||||
|
||||
@@ -1,489 +0,0 @@
|
||||
# UI Components Complete Analysis - Index
|
||||
|
||||
## 📚 Documentation Files Created
|
||||
|
||||
This analysis consists of three comprehensive documents:
|
||||
|
||||
### 1. **UI_COMPONENT_ANALYSIS.md** (Main Reference)
|
||||
**1,424 lines | 45 KB**
|
||||
- Detailed breakdown of all 10 files
|
||||
- Complete method signatures and implementations
|
||||
- Lifecycle method documentation
|
||||
- Data manager interactions
|
||||
- Game flow explanations
|
||||
- Key concepts and patterns
|
||||
|
||||
**Best for:** Deep dives into specific components, understanding implementation details
|
||||
|
||||
### 2. **QUICK_REFERENCE.md** (Developer Cheat Sheet)
|
||||
**~400 lines | 8.6 KB**
|
||||
- Component overview table
|
||||
- Lifecycle stages summary
|
||||
- Key data flows (visual)
|
||||
- Component properties summary
|
||||
- Points & scoring system quick look
|
||||
- Timer system overview
|
||||
- Hint/clue system
|
||||
- Navigation stack examples
|
||||
- Toast system usage
|
||||
- WeChat integration quick reference
|
||||
- Common tasks & code snippets
|
||||
- File complexity metrics
|
||||
|
||||
**Best for:** Quick lookups, copy-paste code patterns, understanding overall architecture
|
||||
|
||||
### 3. **ARCHITECTURE_DIAGRAM.md** (Visual Reference)
|
||||
**~1,000 lines | 26 KB**
|
||||
- System architecture diagram
|
||||
- Page state machine
|
||||
- Page stack visualization with session traces
|
||||
- Component communication diagrams
|
||||
- Data flow diagrams (level completion, hint unlocking)
|
||||
- Timer sequence diagrams
|
||||
- Input box creation flow
|
||||
- Share challenge mode flow
|
||||
- ViewManager caching mechanism
|
||||
- Error handling paths
|
||||
|
||||
**Best for:** Understanding flow, tracing execution, visual learners
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Component Summary
|
||||
|
||||
### Core Infrastructure
|
||||
- **main.ts** (92 lines) - App bootstrap, register pages and managers
|
||||
- **BaseView.ts** (132 lines) - Abstract page lifecycle interface
|
||||
- **ViewManager.ts** (320 lines) - Stack-based page navigation system
|
||||
|
||||
### UI Pages (All extend BaseView)
|
||||
- **PageLoading.ts** (141 lines) - Splash screen, load data, detect share code
|
||||
- **PageHome.ts** (119 lines) - Landing page hub with game/PK buttons
|
||||
- **PageLevel.ts** (823 lines) ⭐ **Most Complex** - Main game with timer, hints, scoring
|
||||
- **PagePreviewLevels.ts** (247 lines) - Scrollable list of selected levels
|
||||
- **PassModal.ts** (155 lines) - Completion modal with next/share buttons
|
||||
|
||||
### Notification System
|
||||
- **Toast.ts** (50 lines) - Individual toast notification with fade animation
|
||||
- **ToastManager.ts** (59 lines) - Singleton manager for toast creation
|
||||
|
||||
**Total: ~2,138 lines across 10 files**
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Key Topics Quick Index
|
||||
|
||||
### Game Mechanics
|
||||
| Topic | Location | Key Method |
|
||||
|-------|----------|-----------|
|
||||
| 60-second countdown | PageLevel | startCountdown() / onCountdownTick() |
|
||||
| Hint/clue system (3 levels) | PageLevel | onUnlockClue(index) |
|
||||
| Answer verification | PageLevel | onSubmitAnswer() / getAnswer() |
|
||||
| Level progression | PageLevel | nextLevel() |
|
||||
| Points earning | PageLevel | showSuccess() + UserAssetsManager.earnPoint() |
|
||||
| Points spending | PageLevel | onUnlockClue() + UserAssetsManager.consumePoint() |
|
||||
|
||||
### UI Management
|
||||
| Topic | Location | Key Method |
|
||||
|-------|----------|-----------|
|
||||
| Page navigation | ViewManager | open() / back() / replace() |
|
||||
| Page lifecycle | BaseView | onViewLoad/Show/Hide/Destroy |
|
||||
| Page caching | ViewManager | _viewCache Map |
|
||||
| Page stacking | ViewManager | _viewStack array (LIFO) |
|
||||
| Toast notifications | ToastManager | show(content, duration) |
|
||||
|
||||
### Special Features
|
||||
| Topic | Location | Key Method |
|
||||
|-------|----------|-----------|
|
||||
| Share challenge mode | PageLevel + ShareManager | _isShareMode flag |
|
||||
| WeChat integration | PageHome, PassModal, WxSDK | initShare() / shareAppMessage() |
|
||||
| Server progress sync | PageLoading | _syncProgressFromServer() |
|
||||
| Level preloading | PageLevel | preloadNextLevel() |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Complexity Breakdown
|
||||
|
||||
```
|
||||
PageLevel.ts (823 lines - 38% of total code)
|
||||
├─ Input management
|
||||
├─ Timer system
|
||||
├─ Hint unlocking
|
||||
├─ Answer validation
|
||||
├─ Point interactions
|
||||
├─ Audio effects
|
||||
├─ Modal handling
|
||||
└─ Share mode support
|
||||
|
||||
ViewManager.ts (320 lines - 15% of total code)
|
||||
├─ Page registration
|
||||
├─ Stack management
|
||||
├─ Instance caching
|
||||
├─ Lifecycle coordination
|
||||
└─ Error handling
|
||||
|
||||
All Other Components (995 lines - 47% of total code)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎮 Game Flow Overview
|
||||
|
||||
```
|
||||
User Launches App
|
||||
↓
|
||||
main.ts registers pages & managers
|
||||
↓
|
||||
PageLoading loads auth + levels (parallel)
|
||||
↓
|
||||
┌─ Detect Share Code ──→ Enter Share Mode (PageLevel)
|
||||
│ ↓
|
||||
│ Play Levels
|
||||
│ ↓
|
||||
│ Return Home
|
||||
│
|
||||
└─ Normal Path ──→ Open PageHome
|
||||
↓
|
||||
┌──────┴──────┐
|
||||
↓ ↓
|
||||
Play Game Create Challenge
|
||||
(PageLevel) (PageWriteLevels)
|
||||
↓ ↓
|
||||
Win Level PagePreviewLevels
|
||||
↓ ↓
|
||||
PassModal PassModal/Share
|
||||
↓ ↓
|
||||
Next/Back Share to WeChat
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💾 Data Manager Interactions
|
||||
|
||||
### By Page
|
||||
|
||||
**PageLoading**
|
||||
- AuthManager.initialize()
|
||||
- LevelDataManager.initialize()
|
||||
- StorageManager.getMaxUnlockedLevelIndex()
|
||||
- StorageManager.onLevelCompleted()
|
||||
- ShareManager.joinShare()
|
||||
- WxSDK.getShareCodeFromLaunch()
|
||||
|
||||
**PageHome**
|
||||
- WxSDK.initShare()
|
||||
- checkPrivacySetting()
|
||||
- requirePrivacyAuthorize()
|
||||
|
||||
**PageLevel** (Most interactions)
|
||||
- LevelDataManager (load, preload, get count)
|
||||
- StorageManager (get/set progress, get points)
|
||||
- UserAssetsManager (earn/consume points)
|
||||
- ShareManager (share mode, report progress)
|
||||
- WxSDK (vibration, sharing)
|
||||
- ToastManager (notifications)
|
||||
- ViewManager (navigation)
|
||||
|
||||
**PagePreviewLevels**
|
||||
- LevelDataManager.ensureLevelReady()
|
||||
|
||||
**PassModal**
|
||||
- WxSDK.shareAppMessage()
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Important Flags & Preventing Issues
|
||||
|
||||
### Double-Submission Prevention
|
||||
```typescript
|
||||
// In PageLevel.onSubmitAnswer()
|
||||
if (this._isTransitioning) return; // Blocks rapid re-submission
|
||||
```
|
||||
|
||||
### Double-Click Unlock Prevention
|
||||
```typescript
|
||||
// In PageLevel.onUnlockClue()
|
||||
if (this._isUnlocking) return; // Blocks rapid hint unlocking
|
||||
```
|
||||
|
||||
### Share Mode Detection
|
||||
```typescript
|
||||
// In PageLevel.onViewLoad()
|
||||
this._isShareMode = params?.shareMode === true;
|
||||
```
|
||||
|
||||
### Timer Running Flag
|
||||
```typescript
|
||||
// In PageLevel.onCountdownTick()
|
||||
if (this._isTimeUp) return; // Prevents countdown after timeout
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Page Lifecycle Details
|
||||
|
||||
### First-Time Open
|
||||
1. ViewManager.open() called
|
||||
2. Prefab instantiated
|
||||
3. onViewLoad() called (do heavy init here)
|
||||
4. Page added to stack
|
||||
5. onViewShow() called
|
||||
|
||||
### Re-open (if cached)
|
||||
1. ViewManager.open() called
|
||||
2. Cache hit found
|
||||
3. Previous page onViewHide() called
|
||||
4. This page onViewShow() called (not onViewLoad!)
|
||||
5. Page already in stack (or re-added)
|
||||
|
||||
### Close/Back
|
||||
1. ViewManager.back() called
|
||||
2. Current page onViewHide() called
|
||||
3. Current page destroyed (if not cached)
|
||||
4. Previous page onViewShow() called
|
||||
|
||||
### Destroy
|
||||
1. onViewDestroy() called
|
||||
2. All listeners removed
|
||||
3. Resources cleaned up
|
||||
4. Node destroyed
|
||||
|
||||
---
|
||||
|
||||
## 📝 Common Code Patterns
|
||||
|
||||
### Open Page with Parameters
|
||||
```typescript
|
||||
ViewManager.instance.open('PageLevel', {
|
||||
params: { shareMode: true },
|
||||
onComplete: (view) => {
|
||||
console.log('PageLevel opened');
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error('Failed to open:', err);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Get Page Parameters
|
||||
```typescript
|
||||
onViewLoad(): void {
|
||||
const params = this.getParams();
|
||||
if (params?.shareMode) {
|
||||
// Handle share mode
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Show Toast Notification
|
||||
```typescript
|
||||
ToastManager.show('提示信息', 2000); // 2 second display
|
||||
```
|
||||
|
||||
### Check & Consume Points
|
||||
```typescript
|
||||
if (StorageManager.hasPoints()) {
|
||||
const success = await UserAssetsManager.consumePoint(levelId, hintIndex);
|
||||
if (success) {
|
||||
this.updatePointsLabel();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Schedule & Unschedule
|
||||
```typescript
|
||||
startCountdown(): void {
|
||||
this.schedule(this.onCountdownTick, 1); // Every 1 second
|
||||
}
|
||||
|
||||
stopCountdown(): void {
|
||||
this.unschedule(this.onCountdownTick); // Stop callback
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Known Patterns to Watch
|
||||
|
||||
### Caching Implications
|
||||
- Pages with cache:true keep their onViewLoad() state
|
||||
- onViewShow() is called each time, even if cached
|
||||
- If you modify state in onViewLoad(), it persists!
|
||||
- Solution: Reset state in onViewShow() if needed
|
||||
|
||||
### Share Mode Edge Cases
|
||||
- Share mode doesn't save local progress
|
||||
- Share mode uses ShareManager instead of LevelDataManager
|
||||
- Share mode clears state on return to home
|
||||
- Must check _isShareMode before saving
|
||||
|
||||
### Modal Positioning
|
||||
- PassModal instantiated with z-index 999 (topmost)
|
||||
- Added to Canvas root node (not PageLevel child)
|
||||
- This allows full-screen coverage with proper Widget alignment
|
||||
|
||||
### Timer Edge Cases
|
||||
- Timer continues even if page is hidden
|
||||
- Must stop timer on destroy or completion
|
||||
- onTimeUp() plays sound but doesn't end game automatically
|
||||
- Wrong answer doesn't stop timer
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Tips for Modifications
|
||||
|
||||
### Adding New Hint Types
|
||||
1. Add hint4 config to RuntimeLevelConfig
|
||||
2. Add unLockItem4 property to PageLevel
|
||||
3. Add tipsItem4 property to PageLevel
|
||||
4. Call showUnlockButton(4) in _applyLevelConfig()
|
||||
5. Handle in onUnlockClue() switch/case
|
||||
|
||||
### Adding Page Analytics
|
||||
1. Add tracking in onViewLoad() (first visit)
|
||||
2. Add tracking in onViewShow() (each visit)
|
||||
3. Use page viewId for identification
|
||||
4. Track user actions in event handlers
|
||||
|
||||
### Changing Point System
|
||||
1. Modify UserAssetsManager (not shown)
|
||||
2. Update updatePointsLabel() display format
|
||||
3. Adjust hasPoints() check if needed
|
||||
4. Test unlock flow with new values
|
||||
|
||||
### Adjusting Timer
|
||||
1. Change `_countdown = 60` to desired seconds
|
||||
2. Update display frequency if needed
|
||||
3. Adjust point calculation if time-based
|
||||
4. Test timeout behavior
|
||||
|
||||
---
|
||||
|
||||
## 📖 How to Use This Documentation
|
||||
|
||||
**For a new developer:**
|
||||
1. Start with QUICK_REFERENCE.md for overview
|
||||
2. Read UI_COMPONENT_ANALYSIS.md sections for specific pages
|
||||
3. Reference ARCHITECTURE_DIAGRAM.md for flow understanding
|
||||
|
||||
**For debugging:**
|
||||
1. Find error in component name
|
||||
2. Look up methods in UI_COMPONENT_ANALYSIS.md
|
||||
3. Check flow in ARCHITECTURE_DIAGRAM.md
|
||||
4. Use QUICK_REFERENCE.md for code patterns
|
||||
|
||||
**For adding features:**
|
||||
1. Understand game flow in QUICK_REFERENCE.md
|
||||
2. Find where to hook in UI_COMPONENT_ANALYSIS.md
|
||||
3. Check data flows in ARCHITECTURE_DIAGRAM.md
|
||||
4. Copy patterns from QUICK_REFERENCE.md
|
||||
|
||||
**For optimization:**
|
||||
1. Note complexity metrics in QUICK_REFERENCE.md
|
||||
2. Identify bottlenecks in PageLevel.ts
|
||||
3. Check async operations in PageLoading.ts
|
||||
4. Review caching in ViewManager.ts
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Cross-References
|
||||
|
||||
### Frequently Referenced Files
|
||||
- **PageLevel.ts** - Most complex, used from PageHome and PageLoading
|
||||
- **ViewManager.ts** - Used by all pages for navigation
|
||||
- **StorageManager** - Used by PageLoading and PageLevel
|
||||
- **UserAssetsManager** - Used by PageLevel for points
|
||||
- **LevelDataManager** - Used by PageLoading and PageLevel
|
||||
|
||||
### Integration Points
|
||||
```
|
||||
main.ts (startup)
|
||||
↓
|
||||
PageLoading (data loading)
|
||||
├─ AuthManager
|
||||
├─ LevelDataManager
|
||||
└─ ShareManager
|
||||
↓
|
||||
PageHome (navigation hub)
|
||||
├─ PageLevel (game)
|
||||
│ ├─ StorageManager
|
||||
│ ├─ UserAssetsManager
|
||||
│ ├─ WxSDK
|
||||
│ └─ PassModal (modal)
|
||||
│ └─ WxSDK
|
||||
│
|
||||
└─ PageWriteLevels (not analyzed)
|
||||
└─ PagePreviewLevels
|
||||
└─ LevelDataManager
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 File Statistics
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total Lines | 2,138 |
|
||||
| Total Files Analyzed | 10 |
|
||||
| Most Complex File | PageLevel.ts (823 lines, 38%) |
|
||||
| Most Reused Manager | ViewManager |
|
||||
| Total Data Managers Used | 7+ |
|
||||
| UI Components | 5 pages + 2 utilities |
|
||||
| Lifecycle Methods | 4 per BaseView |
|
||||
| Key Patterns | Stack navigation, caching, events |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Next Steps for Development
|
||||
|
||||
1. **Run the game** and trace through the flows documented here
|
||||
2. **Add logging** to key methods to understand real execution order
|
||||
3. **Modify a page** to get familiar with lifecycle
|
||||
4. **Create new page** following BaseView pattern
|
||||
5. **Add new feature** using documented patterns
|
||||
|
||||
---
|
||||
|
||||
## 📞 Quick Troubleshooting
|
||||
|
||||
**Page not showing?**
|
||||
- Check ViewManager.open() called
|
||||
- Verify prefab has BaseView component
|
||||
- Check registration in main.ts
|
||||
|
||||
**Points not updating?**
|
||||
- Verify UserAssetsManager call succeeds
|
||||
- Check updatePointsLabel() is called
|
||||
- Test StorageManager.getPoints() returns value
|
||||
|
||||
**Timer not stopping?**
|
||||
- Check stopCountdown() called on completion
|
||||
- Verify unschedule() works in Cocos
|
||||
- Test onDestroy calls stopCountdown()
|
||||
|
||||
**Modal not appearing?**
|
||||
- Check z-index set to 999
|
||||
- Verify added to Canvas root
|
||||
- Test instantiate() succeeds
|
||||
- Check onViewLoad/Show called manually
|
||||
|
||||
**Share mode broken?**
|
||||
- Verify share code detected in PageLoading
|
||||
- Check _isShareMode set properly
|
||||
- Test ShareManager.joinShare() succeeds
|
||||
- Verify clearShareMode() called on exit
|
||||
|
||||
---
|
||||
|
||||
## ✅ Analysis Complete
|
||||
|
||||
All 10 UI component files have been thoroughly analyzed and documented.
|
||||
|
||||
**Total Documentation: 3 comprehensive guides**
|
||||
- **UI_COMPONENT_ANALYSIS.md** - Deep technical reference (1,424 lines)
|
||||
- **QUICK_REFERENCE.md** - Developer cheat sheet (~400 lines)
|
||||
- **ARCHITECTURE_DIAGRAM.md** - Visual flow diagrams (~1,000 lines)
|
||||
- **This file** - Navigation & index (this document)
|
||||
|
||||
**Ready for:** Development, debugging, feature implementation, onboarding
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user