# 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`) - 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=` ### 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(url: string, timeout: number = 10000): Promise // POST request HttpUtil.post(url: string, data: object, timeout: number = 10000): Promise ``` ### 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