113 lines
3.2 KiB
JavaScript
113 lines
3.2 KiB
JavaScript
/**
|
|
* 游戏进度持久化:关卡、星级、连胜、每日打卡
|
|
*/
|
|
import { ref } from 'vue'
|
|
import { calcLevelStars } from '../data/gameLevels.js'
|
|
|
|
const STORAGE_KEY = 'tongji_game_progress_v1'
|
|
|
|
const DEFAULT = {
|
|
currentLevel: 1,
|
|
maxUnlocked: 1,
|
|
stars: {},
|
|
winStreak: 0,
|
|
dailyStreak: 0,
|
|
lastPlayDate: '',
|
|
totalWins: 0,
|
|
bestCombo: 0,
|
|
totalStars: 0
|
|
}
|
|
|
|
function todayStr() {
|
|
const d = new Date()
|
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
|
|
}
|
|
|
|
function sumStars(starsMap) {
|
|
return Object.values(starsMap || {}).reduce((s, n) => s + (Number(n) || 0), 0)
|
|
}
|
|
|
|
function loadRaw() {
|
|
try {
|
|
const raw = uni.getStorageSync(STORAGE_KEY)
|
|
if (raw && typeof raw === 'object') return { ...DEFAULT, ...raw }
|
|
} catch (_) {}
|
|
return { ...DEFAULT }
|
|
}
|
|
|
|
function saveRaw(data) {
|
|
try {
|
|
uni.setStorageSync(STORAGE_KEY, data)
|
|
} catch (_) {}
|
|
}
|
|
|
|
export function useGameProgress() {
|
|
const progress = ref(loadRaw())
|
|
|
|
function persist() {
|
|
progress.value.totalStars = sumStars(progress.value.stars)
|
|
saveRaw(progress.value)
|
|
}
|
|
|
|
/** 进入游戏时更新每日打卡 */
|
|
function touchDailyPlay() {
|
|
const today = todayStr()
|
|
const last = progress.value.lastPlayDate
|
|
if (last === today) return progress.value.dailyStreak
|
|
|
|
const yesterday = new Date()
|
|
yesterday.setDate(yesterday.getDate() - 1)
|
|
const yStr = `${yesterday.getFullYear()}-${String(yesterday.getMonth() + 1).padStart(2, '0')}-${String(yesterday.getDate()).padStart(2, '0')}`
|
|
|
|
if (last === yStr) {
|
|
progress.value.dailyStreak = (progress.value.dailyStreak || 0) + 1
|
|
} else {
|
|
progress.value.dailyStreak = 1
|
|
}
|
|
progress.value.lastPlayDate = today
|
|
persist()
|
|
return progress.value.dailyStreak
|
|
}
|
|
|
|
function getStars(levelId) {
|
|
return progress.value.stars[String(levelId)] || 0
|
|
}
|
|
|
|
function recordWin({ levelId, movesLeft, glucoseLevel, score, levelConfig, maxCombo }) {
|
|
const stars = calcLevelStars({ movesLeft, glucoseLevel, score, levelConfig })
|
|
const key = String(levelId)
|
|
const prev = progress.value.stars[key] || 0
|
|
if (stars > prev) progress.value.stars[key] = stars
|
|
|
|
progress.value.winStreak = (progress.value.winStreak || 0) + 1
|
|
progress.value.totalWins = (progress.value.totalWins || 0) + 1
|
|
if (maxCombo > (progress.value.bestCombo || 0)) progress.value.bestCombo = maxCombo
|
|
|
|
const next = levelId + 1
|
|
if (next > progress.value.maxUnlocked) progress.value.maxUnlocked = next
|
|
progress.value.currentLevel = next
|
|
persist()
|
|
return { stars, newBest: stars > prev }
|
|
}
|
|
|
|
function recordLoss() {
|
|
progress.value.winStreak = 0
|
|
persist()
|
|
}
|
|
|
|
function setCurrentLevel(levelId) {
|
|
progress.value.currentLevel = Math.max(1, Math.min(progress.value.maxUnlocked, levelId))
|
|
persist()
|
|
}
|
|
|
|
return {
|
|
progress,
|
|
touchDailyPlay,
|
|
getStars,
|
|
recordWin,
|
|
recordLoss,
|
|
setCurrentLevel,
|
|
persist
|
|
}
|
|
}
|