"use client"; // 回响星核 / Echo Nexus — 成就解锁通知(v0.9 全屏特效增强) // 工单 Issue #2 反馈"成就系统没看出来有什么用",改为居中全息弹窗 + 奖励数字弹出 import { useEffect, useState } from "react"; import { AnimatePresence, motion } from "framer-motion"; import { useGameStore } from "@/store/gameStore"; import { useToast } from "@/hooks/use-toast"; import { sfx } from "@/hooks/useAudio"; import type { Achievement } from "@/lib/game/achievements"; interface NotificationItem { achievement: Achievement; id: number; } export function AchievementNotifier() { const queue = useGameStore((s) => s._achievementQueue); const consume = useGameStore((s) => s.consumeAchievementQueue); const { toast } = useToast(); const [notifications, setNotifications] = useState([]); useEffect(() => { if (queue.length === 0) return; const items = consume(); for (const a of items) { sfx("achievement"); // v0.9:全屏居中特效通知 const id = Date.now() + Math.random(); // eslint-disable-next-line react-hooks/set-state-in-effect setNotifications((prev) => [...prev, { achievement: a, id }]); // 4 秒后自动移除 setTimeout(() => { setNotifications((prev) => prev.filter((n) => n.id !== id)); }, 4000); // 同时保留底部 toast 作为日志 toast({ title: `成就解锁:${a.name}`, description: `${a.desc} 奖励:${a.rewardText}`, }); } }, [queue, consume, toast]); if (notifications.length === 0) return null; return (
{notifications.map((n, idx) => { const a = n.achievement; // 多个同时出现时垂直堆叠偏移 const offset = (idx - (notifications.length - 1) / 2) * 140; return (
{/* 背景径向辉光 */}
{/* 旋转光线 */}
{/* 图标徽章 */} {a.icon} {/* 文本 */}
✦ Achievement Unlocked {a.name} {a.desc} {/* 奖励条 */} ▸ {a.rewardText}
{/* 进度条(倒计时) */}
); })}
); }