import { _decorator, sys } from 'cc'; const { ccclass, property } = _decorator; /** * 玩家数据结构 */ export interface PlayerData { // 基本信息 playerId: string; playerName: string; createTime: number; lastPlayTime: number; totalPlayTime: number; // 等级和经验 playerLevel: number; experience: number; experienceToNext: number; // 货币系统 coins: number; // 金币 diamonds: number; // 钻石 gems: number; // 宝石 // 关卡进度 currentLevel: number; maxUnlockedLevel: number; levelProgress: { [levelId: number]: LevelProgress }; // 道具和装备 inventory: InventoryData; // 统计数据 statistics: GameStatistics; // 设置 settings: PlayerSettings; } /** * 关卡进度数据 */ export interface LevelProgress { levelId: number; completed: boolean; bestScore: number; bestTime: number; stars: number; attempts: number; firstClearTime: number; lastPlayTime: number; rewards: RewardData[]; } /** * 背包数据 */ export interface InventoryData { weapons: { [weaponId: string]: WeaponData }; items: { [itemId: string]: ItemData }; materials: { [materialId: string]: number }; capacity: number; usedSlots: number; } /** * 武器数据 */ export interface WeaponData { weaponId: string; level: number; experience: number; rarity: string; obtainTime: number; upgradeCount: number; isEquipped: boolean; } /** * 道具数据 */ export interface ItemData { itemId: string; count: number; obtainTime: number; lastUsedTime: number; } /** * 奖励数据 */ export interface RewardData { type: 'coins' | 'diamonds' | 'gems' | 'weapon' | 'item' | 'experience'; id?: string; amount: number; obtainTime: number; source: string; // 获得来源:level_complete, daily_reward, shop_purchase等 } /** * 游戏统计数据 */ export interface GameStatistics { totalGamesPlayed: number; totalWins: number; totalLosses: number; totalScore: number; totalEnemiesDefeated: number; totalShotsfired: number; totalDamageDealt: number; totalTimePlayed: number; highestLevel: number; consecutiveWins: number; bestWinStreak: number; favoriteWeapon: string; weaponsUnlocked: number; itemsCollected: number; } /** * 玩家设置 */ export interface PlayerSettings { soundEnabled: boolean; musicEnabled: boolean; soundVolume: number; musicVolume: number; vibrationEnabled: boolean; autoSaveEnabled: boolean; language: string; graphics: 'low' | 'medium' | 'high'; } /** * 存档管理器 * 负责玩家数据的保存、加载和管理 */ @ccclass('SaveDataManager') export class SaveDataManager { private static instance: SaveDataManager = null; private playerData: PlayerData = null; private initialized: boolean = false; private autoSaveInterval: number = 30; // 自动保存间隔(秒) private lastSaveTime: number = 0; // 存档文件键名 private readonly SAVE_KEY = 'pong_game_save_data'; private readonly BACKUP_KEY = 'pong_game_save_data_backup'; private readonly SETTINGS_KEY = 'pong_game_settings'; private constructor() { // 私有构造函数,确保单例模式 } public static getInstance(): SaveDataManager { if (SaveDataManager.instance === null) { SaveDataManager.instance = new SaveDataManager(); } return SaveDataManager.instance; } /** * 初始化存档管理器 */ public initialize(): void { if (this.initialized) return; this.loadPlayerData(); this.initialized = true; } /** * 加载玩家数据 */ private loadPlayerData(): void { try { const savedData = sys.localStorage.getItem(this.SAVE_KEY); if (savedData) { const data = JSON.parse(savedData); this.playerData = this.validateAndMigrateData(data); this.playerData.lastPlayTime = Date.now(); } else { this.createNewPlayerData(); } } catch (error) { console.error('❌ 存档数据加载失败,尝试加载备份:', error); this.loadBackupData(); } } /** * 加载备份数据 */ private loadBackupData(): void { try { const backupData = sys.localStorage.getItem(this.BACKUP_KEY); if (backupData) { const data = JSON.parse(backupData); this.playerData = this.validateAndMigrateData(data); this.playerData.lastPlayTime = Date.now(); } else { this.createNewPlayerData(); } } catch (error) { console.error('❌ 备份数据加载失败,创建新存档:', error); this.createNewPlayerData(); } } /** * 创建新的玩家数据 */ private createNewPlayerData(): void { this.playerData = { playerId: this.generatePlayerId(), playerName: 'Player', createTime: Date.now(), lastPlayTime: Date.now(), totalPlayTime: 0, playerLevel: 1, experience: 0, experienceToNext: 100, coins: 1000, // 初始金币 diamonds: 50, // 初始钻石 gems: 0, currentLevel: 1, maxUnlockedLevel: 1, levelProgress: {}, inventory: { weapons: {}, items: {}, materials: {}, capacity: 50, usedSlots: 0 }, statistics: { totalGamesPlayed: 0, totalWins: 0, totalLosses: 0, totalScore: 0, totalEnemiesDefeated: 0, totalShotsfired: 0, totalDamageDealt: 0, totalTimePlayed: 0, highestLevel: 1, consecutiveWins: 0, bestWinStreak: 0, favoriteWeapon: '', weaponsUnlocked: 0, itemsCollected: 0 }, settings: { soundEnabled: true, musicEnabled: true, soundVolume: 0.8, musicVolume: 0.6, vibrationEnabled: true, autoSaveEnabled: true, language: 'zh-CN', graphics: 'medium' } }; this.savePlayerData(); } /** * 验证和迁移数据(用于版本兼容) */ private validateAndMigrateData(data: any): PlayerData { // 确保所有必要字段存在 const defaultData = this.createDefaultPlayerData(); return { ...defaultData, ...data, // 确保嵌套对象也被正确合并 inventory: { ...defaultData.inventory, ...data.inventory }, statistics: { ...defaultData.statistics, ...data.statistics }, settings: { ...defaultData.settings, ...data.settings } }; } /** * 创建默认玩家数据模板 */ private createDefaultPlayerData(): PlayerData { return { playerId: this.generatePlayerId(), playerName: 'Player', createTime: Date.now(), lastPlayTime: Date.now(), totalPlayTime: 0, playerLevel: 1, experience: 0, experienceToNext: 100, coins: 1000, diamonds: 50, gems: 0, currentLevel: 1, maxUnlockedLevel: 1, levelProgress: {}, inventory: { weapons: {}, items: {}, materials: {}, capacity: 50, usedSlots: 0 }, statistics: { totalGamesPlayed: 0, totalWins: 0, totalLosses: 0, totalScore: 0, totalEnemiesDefeated: 0, totalShotsfired: 0, totalDamageDealt: 0, totalTimePlayed: 0, highestLevel: 1, consecutiveWins: 0, bestWinStreak: 0, favoriteWeapon: '', weaponsUnlocked: 0, itemsCollected: 0 }, settings: { soundEnabled: true, musicEnabled: true, soundVolume: 0.8, musicVolume: 0.6, vibrationEnabled: true, autoSaveEnabled: true, language: 'zh-CN', graphics: 'medium' } }; } /** * 保存玩家数据 */ public savePlayerData(force: boolean = false): void { if (!this.playerData) return; const currentTime = Date.now(); // 检查是否需要保存(避免频繁保存) if (!force && currentTime - this.lastSaveTime < 5000) { return; } try { // 更新最后保存时间 this.playerData.lastPlayTime = currentTime; // 创建备份 const currentData = sys.localStorage.getItem(this.SAVE_KEY); if (currentData) { sys.localStorage.setItem(this.BACKUP_KEY, currentData); } // 保存当前数据 const dataToSave = JSON.stringify(this.playerData); sys.localStorage.setItem(this.SAVE_KEY, dataToSave); this.lastSaveTime = currentTime; } catch (error) { console.error('❌ 玩家数据保存失败:', error); } } /** * 自动保存检查 */ public checkAutoSave(): void { if (!this.playerData || !this.playerData.settings.autoSaveEnabled) return; const currentTime = Date.now(); if (currentTime - this.lastSaveTime > this.autoSaveInterval * 1000) { this.savePlayerData(); } } // === 玩家基本信息管理 === public getPlayerData(): PlayerData { return this.playerData; } public getPlayerLevel(): number { return this.playerData?.playerLevel || 1; } public getCurrentLevel(): number { return this.playerData?.currentLevel || 1; } public getMaxUnlockedLevel(): number { return this.playerData?.maxUnlockedLevel || 1; } public getCoins(): number { return this.playerData?.coins || 0; } public getDiamonds(): number { return this.playerData?.diamonds || 0; } public getGems(): number { return this.playerData?.gems || 0; } // === 关卡进度管理 === /** * 完成关卡 */ public completeLevel(levelId: number, score: number, time: number, stars: number): void { if (!this.playerData) return; // 更新关卡进度 if (!this.playerData.levelProgress[levelId]) { this.playerData.levelProgress[levelId] = { levelId: levelId, completed: false, bestScore: 0, bestTime: 0, stars: 0, attempts: 0, firstClearTime: 0, lastPlayTime: 0, rewards: [] }; } const progress = this.playerData.levelProgress[levelId]; progress.attempts += 1; progress.lastPlayTime = Date.now(); // 首次完成 if (!progress.completed) { progress.completed = true; progress.firstClearTime = Date.now(); // 解锁下一关 if (levelId === this.playerData.maxUnlockedLevel) { this.playerData.maxUnlockedLevel = levelId + 1; } } // 更新最佳记录 if (score > progress.bestScore) { progress.bestScore = score; } if (time > 0 && (progress.bestTime === 0 || time < progress.bestTime)) { progress.bestTime = time; } if (stars > progress.stars) { progress.stars = stars; } // 更新统计数据 this.playerData.statistics.totalGamesPlayed += 1; this.playerData.statistics.totalWins += 1; this.playerData.statistics.totalScore += score; this.playerData.statistics.consecutiveWins += 1; if (this.playerData.statistics.consecutiveWins > this.playerData.statistics.bestWinStreak) { this.playerData.statistics.bestWinStreak = this.playerData.statistics.consecutiveWins; } if (levelId > this.playerData.statistics.highestLevel) { this.playerData.statistics.highestLevel = levelId; } // 给予经验值 this.addExperience(score / 10 + stars * 20); // 计算并给予奖励 this.giveCompletionRewards(levelId, stars); this.savePlayerData(); } /** * 关卡失败 */ public failLevel(levelId: number): void { if (!this.playerData) return; // 更新关卡进度 if (!this.playerData.levelProgress[levelId]) { this.playerData.levelProgress[levelId] = { levelId: levelId, completed: false, bestScore: 0, bestTime: 0, stars: 0, attempts: 0, firstClearTime: 0, lastPlayTime: 0, rewards: [] }; } const progress = this.playerData.levelProgress[levelId]; progress.attempts += 1; progress.lastPlayTime = Date.now(); // 更新统计数据 this.playerData.statistics.totalGamesPlayed += 1; this.playerData.statistics.totalLosses += 1; this.playerData.statistics.consecutiveWins = 0; this.savePlayerData(); } /** * 获取关卡进度 */ public getLevelProgress(levelId: number): LevelProgress | null { return this.playerData?.levelProgress[levelId] || null; } /** * 检查关卡是否已解锁 */ public isLevelUnlocked(levelId: number): boolean { return levelId <= (this.playerData?.maxUnlockedLevel || 1); } /** * 检查关卡是否已完成 */ public isLevelCompleted(levelId: number): boolean { const progress = this.getLevelProgress(levelId); return progress?.completed || false; } // === 货币管理 === /** * 添加金币 */ public addCoins(amount: number, source: string = 'unknown'): boolean { if (!this.playerData || amount <= 0) return false; this.playerData.coins += amount; this.addReward('coins', '', amount, source); return true; } /** * 消费金币 */ public spendCoins(amount: number): boolean { if (!this.playerData || amount <= 0 || this.playerData.coins < amount) { return false; } this.playerData.coins -= amount; return true; } /** * 添加钻石 */ public addDiamonds(amount: number, source: string = 'unknown'): boolean { if (!this.playerData || amount <= 0) return false; this.playerData.diamonds += amount; this.addReward('diamonds', '', amount, source); return true; } /** * 消费钻石 */ public spendDiamonds(amount: number): boolean { if (!this.playerData || amount <= 0 || this.playerData.diamonds < amount) { return false; } this.playerData.diamonds -= amount; return true; } /** * 添加宝石 */ public addGems(amount: number, source: string = 'unknown'): boolean { if (!this.playerData || amount <= 0) return false; this.playerData.gems += amount; this.addReward('gems', '', amount, source); return true; } // === 经验和等级管理 === /** * 添加经验值 */ public addExperience(amount: number): boolean { if (!this.playerData || amount <= 0) return false; this.playerData.experience += amount; // 检查是否升级 while (this.playerData.experience >= this.playerData.experienceToNext) { this.levelUp(); } return true; } /** * 玩家升级 */ private levelUp(): void { this.playerData.experience -= this.playerData.experienceToNext; this.playerData.playerLevel += 1; // 计算下一级所需经验值 this.playerData.experienceToNext = this.calculateExperienceToNext(this.playerData.playerLevel); // 升级奖励 const coinReward = this.playerData.playerLevel * 100; const diamondReward = Math.floor(this.playerData.playerLevel / 5); this.addCoins(coinReward, 'level_up'); if (diamondReward > 0) { this.addDiamonds(diamondReward, 'level_up'); } } /** * 计算升级所需经验值 */ private calculateExperienceToNext(level: number): number { return 100 + (level - 1) * 50; } // === 道具和武器管理 === /** * 添加武器 */ public addWeapon(weaponId: string, rarity: string = 'common'): boolean { if (!this.playerData) return false; if (!this.playerData.inventory.weapons[weaponId]) { this.playerData.inventory.weapons[weaponId] = { weaponId: weaponId, level: 1, experience: 0, rarity: rarity, obtainTime: Date.now(), upgradeCount: 0, isEquipped: false }; this.playerData.statistics.weaponsUnlocked += 1; this.addReward('weapon', weaponId, 1, 'drop'); return true; } return false; } /** * 添加道具 */ public addItem(itemId: string, count: number = 1): boolean { if (!this.playerData || count <= 0) return false; if (!this.playerData.inventory.items[itemId]) { this.playerData.inventory.items[itemId] = { itemId: itemId, count: 0, obtainTime: Date.now(), lastUsedTime: 0 }; } this.playerData.inventory.items[itemId].count += count; this.playerData.statistics.itemsCollected += count; this.addReward('item', itemId, count, 'drop'); return true; } /** * 使用道具 */ public useItem(itemId: string, count: number = 1): boolean { if (!this.playerData || count <= 0) return false; const item = this.playerData.inventory.items[itemId]; if (!item || item.count < count) { return false; } item.count -= count; item.lastUsedTime = Date.now(); if (item.count === 0) { delete this.playerData.inventory.items[itemId]; } return true; } // === 奖励管理 === /** * 添加奖励记录 */ private addReward(type: RewardData['type'], id: string, amount: number, source: string): void { if (!this.playerData) return; const reward: RewardData = { type: type, id: id, amount: amount, obtainTime: Date.now(), source: source }; // 这里可以添加到全局奖励历史记录中 // 暂时不实现,避免数据过大 } /** * 给予关卡完成奖励 */ private giveCompletionRewards(levelId: number, stars: number): void { // 基础金币奖励 const baseCoins = levelId * 50; const starBonus = stars * 25; const totalCoins = baseCoins + starBonus; this.addCoins(totalCoins, `level_${levelId}_complete`); // 钻石奖励(3星才给) if (stars >= 3) { const diamonds = Math.max(1, Math.floor(levelId / 3)); this.addDiamonds(diamonds, `level_${levelId}_perfect`); } // 特殊关卡额外奖励 if (levelId % 10 === 0) { this.addGems(1, `level_${levelId}_milestone`); } } // === 统计数据更新 === public updateStatistic(key: keyof GameStatistics, value: number): void { if (!this.playerData) return; if (typeof this.playerData.statistics[key] === 'number') { (this.playerData.statistics[key] as number) += value; } } // === 设置管理 === public updateSetting(key: K, value: PlayerSettings[K]): void { if (!this.playerData) return; this.playerData.settings[key] = value; this.savePlayerData(); } public getSetting(key: K): PlayerSettings[K] { return this.playerData?.settings[key]; } // === 工具方法 === /** * 生成唯一玩家ID */ private generatePlayerId(): string { return `player_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * 重置所有数据 */ public resetAllData(): void { sys.localStorage.removeItem(this.SAVE_KEY); sys.localStorage.removeItem(this.BACKUP_KEY); this.createNewPlayerData(); } /** * 导出存档数据(用于调试) */ public exportSaveData(): string { return JSON.stringify(this.playerData, null, 2); } /** * 导入存档数据(用于调试) */ public importSaveData(dataString: string): boolean { try { const data = JSON.parse(dataString); this.playerData = this.validateAndMigrateData(data); this.savePlayerData(true); return true; } catch (error) { console.error('❌ 存档数据导入失败:', error); return false; } } /** * 获取存档摘要信息 */ public getSaveSummary(): string { if (!this.playerData) return '无存档数据'; return `玩家等级: ${this.playerData.playerLevel} | ` + `当前关卡: ${this.playerData.currentLevel} | ` + `最高关卡: ${this.playerData.maxUnlockedLevel} | ` + `金币: ${this.playerData.coins} | ` + `钻石: ${this.playerData.diamonds} | ` + `游戏次数: ${this.playerData.statistics.totalGamesPlayed}`; } }