Files
mp-xieyingeng/assets/scripts/utils/StorageManager.ts
2026-03-16 21:49:55 +08:00

240 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { sys } from 'cc';
/**
* 用户进度数据结构
*/
interface UserProgress {
/** 当前关卡索引0-based */
currentLevelIndex: number;
/** 已通关的最高关卡索引 */
maxUnlockedLevelIndex: number;
}
/**
* 本地存储管理器
* 统一管理用户数据的本地持久化存储
*/
export class StorageManager {
/** 生命值存储键 */
private static readonly KEY_LIVES = 'game_lives';
/** 用户进度存储键 */
private static readonly KEY_PROGRESS = 'game_progress';
/** 默认生命值 */
private static readonly DEFAULT_LIVES = 10;
/** 最小生命值 */
private static readonly MIN_LIVES = 0;
/** 默认进度 */
private static readonly DEFAULT_PROGRESS: UserProgress = {
currentLevelIndex: 0,
maxUnlockedLevelIndex: 0
};
/** 进度缓存(避免重复读取 localStorage */
private static _progressCache: UserProgress | null = null;
// ==================== 生命值管理 ====================
/**
* 获取当前生命值
* @returns 当前生命值,新用户返回默认值 10
*/
static getLives(): number {
const stored = sys.localStorage.getItem(StorageManager.KEY_LIVES);
if (stored === null || stored === '') {
// 新用户,设置默认值
StorageManager.setLives(StorageManager.DEFAULT_LIVES);
return StorageManager.DEFAULT_LIVES;
}
const lives = parseInt(stored, 10);
// 防止异常数据
if (isNaN(lives) || lives < 0) {
StorageManager.setLives(StorageManager.DEFAULT_LIVES);
return StorageManager.DEFAULT_LIVES;
}
return lives;
}
/**
* 设置生命值
* @param lives 生命值
*/
static setLives(lives: number): void {
const validLives = Math.max(StorageManager.MIN_LIVES, lives);
sys.localStorage.setItem(StorageManager.KEY_LIVES, validLives.toString());
console.log(`[StorageManager] 生命值已更新: ${validLives}`);
}
/**
* 消耗一颗生命
* @returns 是否消耗成功(生命值不足时返回 false
*/
static consumeLife(): boolean {
const currentLives = StorageManager.getLives();
if (currentLives <= 0) {
console.warn('[StorageManager] 生命值不足,无法消耗');
return false;
}
StorageManager.setLives(currentLives - 1);
return true;
}
/**
* 增加一颗生命
*/
static addLife(): void {
const currentLives = StorageManager.getLives();
StorageManager.setLives(currentLives + 1);
console.log(`[StorageManager] 获得一颗生命,当前生命值: ${currentLives + 1}`);
}
/**
* 检查是否有足够的生命值
* @returns 是否有生命值
*/
static hasLives(): boolean {
return StorageManager.getLives() > 0;
}
/**
* 重置生命值为默认值
*/
static resetLives(): void {
StorageManager.setLives(StorageManager.DEFAULT_LIVES);
console.log('[StorageManager] 生命值已重置为默认值');
}
// ==================== 关卡进度管理 ====================
/**
* 获取用户进度数据(带缓存)
* @returns 用户进度对象的副本
*/
private static _getProgress(): UserProgress {
// 返回缓存副本
if (StorageManager._progressCache !== null) {
return { ...StorageManager._progressCache };
}
const stored = sys.localStorage.getItem(StorageManager.KEY_PROGRESS);
if (stored === null || stored === '') {
// 新用户,返回默认进度
StorageManager._progressCache = { ...StorageManager.DEFAULT_PROGRESS };
return { ...StorageManager._progressCache };
}
try {
const progress = JSON.parse(stored) as UserProgress;
// 验证数据有效性
if (typeof progress.currentLevelIndex !== 'number' ||
typeof progress.maxUnlockedLevelIndex !== 'number' ||
progress.currentLevelIndex < 0 ||
progress.maxUnlockedLevelIndex < 0) {
console.warn('[StorageManager] 进度数据无效,使用默认值');
StorageManager._progressCache = { ...StorageManager.DEFAULT_PROGRESS };
} else {
StorageManager._progressCache = progress;
}
return { ...StorageManager._progressCache };
} catch (e) {
console.warn('[StorageManager] 解析进度数据失败,使用默认值');
StorageManager._progressCache = { ...StorageManager.DEFAULT_PROGRESS };
return { ...StorageManager._progressCache };
}
}
/**
* 保存用户进度数据
* @param progress 进度对象
*/
private static _saveProgress(progress: UserProgress): void {
StorageManager._progressCache = progress;
sys.localStorage.setItem(StorageManager.KEY_PROGRESS, JSON.stringify(progress));
}
/**
* 获取当前关卡索引
* @returns 当前关卡索引0-based
*/
static getCurrentLevelIndex(): number {
return StorageManager._getProgress().currentLevelIndex;
}
/**
* 设置当前关卡索引
* @param index 关卡索引
*/
static setCurrentLevelIndex(index: number): void {
if (index < 0) {
console.warn('[StorageManager] 关卡索引不能为负数');
return;
}
const progress = StorageManager._getProgress();
progress.currentLevelIndex = index;
StorageManager._saveProgress(progress);
console.log(`[StorageManager] 当前关卡已更新: ${progress.currentLevelIndex}`);
}
/**
* 获取已解锁的最高关卡索引
* @returns 最高关卡索引0-based
*/
static getMaxUnlockedLevelIndex(): number {
return StorageManager._getProgress().maxUnlockedLevelIndex;
}
/**
* 通关后更新进度
* 当玩家通关第 N 关后,设置当前关卡为 N+1解锁关卡更新为 max(N, 已解锁)
* @param completedLevelIndex 刚通关的关卡索引
*/
static onLevelCompleted(completedLevelIndex: number): void {
if (completedLevelIndex < 0) {
console.warn('[StorageManager] 通关关卡索引不能为负数');
return;
}
const progress = StorageManager._getProgress();
const nextLevelIndex = completedLevelIndex + 1;
// 更新当前关卡为下一关
progress.currentLevelIndex = nextLevelIndex;
// 更新最高解锁关卡
progress.maxUnlockedLevelIndex = Math.max(progress.maxUnlockedLevelIndex, completedLevelIndex);
StorageManager._saveProgress(progress);
console.log(`[StorageManager] 通关第 ${completedLevelIndex + 1} 关,下一关: ${nextLevelIndex + 1}`);
}
/**
* 检查指定关卡是否已解锁
* @param levelIndex 关卡索引
* @returns 是否已解锁
*/
static isLevelUnlocked(levelIndex: number): boolean {
const progress = StorageManager._getProgress();
return levelIndex <= progress.maxUnlockedLevelIndex;
}
/**
* 重置所有进度
*/
static resetProgress(): void {
StorageManager._progressCache = null;
sys.localStorage.removeItem(StorageManager.KEY_PROGRESS);
console.log('[StorageManager] 进度已重置');
}
/**
* 重置所有数据(生命值 + 进度)
*/
static resetAll(): void {
StorageManager.resetLives();
StorageManager.resetProgress();
console.log('[StorageManager] 所有数据已重置');
}
}