← Вернуться к урокам

✨ Достижения и финальная полировка

Урок 5 из 5

🎯 Цель урока

В финальном уроке мы добавим систему достижений, красивые визуальные эффекты, анимации и сделаем последние штрихи для создания профессионального математического приложения. Превратим наш калькулятор в полноценную игру!

💡 Что вы узнаете:

• Систему достижений и наград
• Создание анимаций и спецэффектов
• Работу с массивами для хранения достижений
• Создание всплывающих уведомлений
• Финальную оптимизацию и полировку

📚 Продвинутые концепции

Array.includes()

Проверка наличия элемента в массиве для предотвращения дублирования достижений

setTimeout() и setInterval()

Управление временем для анимаций и отложенных действий

document.createElement()

Динамическое создание HTML элементов для эффектов и уведомлений

CSS animations в JavaScript

Управление CSS анимациями из JavaScript кода

localStorage (бонус)

Сохранение прогресса игрока между сессиями (продвинутый уровень)

🏆 Система достижений

Создаём мотивирующую систему наград для игроков:

// Массив для хранения полученных достижений
let achievements = [];

// Список всех возможных достижений
const achievementsList = [
    { 
        id: 'first_step', 
        name: '🌟 Первый шаг', 
        description: 'Решить первый пример',
        condition: () => totalSolved >= 1 
    },
    { 
        id: 'hot_streak', 
        name: '🔥 Горячая серия', 
        description: 'Решить 5 примеров подряд',
        condition: () => streak >= 5 
    },
    { 
        id: 'century', 
        name: '💯 Сотка!', 
        description: 'Набрать 100 очков',
        condition: () => score >= 100 
    },
    { 
        id: 'level_master', 
        name: '📈 Мастер уровней', 
        description: 'Достичь 5 уровня',
        condition: () => level >= 5 
    },
    { 
        id: 'math_genius', 
        name: '👑 Математический гений', 
        description: 'Решить 50 примеров',
        condition: () => totalSolved >= 50 
    },
    { 
        id: 'speed_demon', 
        name: '⚡ Скоростной демон', 
        description: 'Решить 10 примеров за 2 минуты',
        condition: () => speedSolved >= 10 
    }
];

// Переменная для скоростного достижения
let speedSolved = 0;
let speedTimer = null;

✅ Проверка достижений

Функция для автоматической проверки и вручения наград:

function checkAchievements() {
    achievementsList.forEach(achievement => {
        // Проверяем, что достижение ещё не получено
        if (!achievements.includes(achievement.id) && achievement.condition()) {
            // Добавляем достижение в список полученных
            achievements.push(achievement.id);
            
            // Показываем уведомление
            showAchievementNotification(achievement);
            
            // Создаём спецэффекты
            createSparkles();
            
            // Обновляем отображение достижений
            updateAchievements();
        }
    });
}

function showAchievementNotification(achievement) {
    // Создаём всплывающее уведомление
    const notification = document.createElement('div');
    notification.style.cssText = `
        position: fixed;
        top: 20px;
        right: 20px;
        background: linear-gradient(135deg, #fdcb6e, #e17055);
        color: white;
        padding: 15px 20px;
        border-radius: 10px;
        box-shadow: 0 10px 25px rgba(253, 203, 110, 0.5);
        z-index: 1000;
        font-weight: bold;
        animation: slideIn 0.5s ease-out, slideOut 0.5s ease-out 3s forwards;
        max-width: 300px;
    `;
    
    notification.innerHTML = `
        
🎉 Новое достижение!
${achievement.name}
${achievement.description}
`; document.body.appendChild(notification); // Удаляем уведомление через 4 секунды setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 4000); }

✨ Визуальные эффекты

Добавляем красивые анимации для создания wow-эффекта:

function createSparkles() {
    const sparkleEmojis = ['✨', '⭐', '🌟', '💫', '🎉', '🎊'];
    
    for (let i = 0; i < 8; i++) {
        const sparkle = document.createElement('div');
        sparkle.className = 'sparkle';
        sparkle.textContent = sparkleEmojis[Math.floor(Math.random() * sparkleEmojis.length)];
        
        // Случайная позиция на экране
        sparkle.style.left = Math.random() * window.innerWidth + 'px';
        sparkle.style.top = Math.random() * window.innerHeight + 'px';
        
        document.body.appendChild(sparkle);
        
        // Удаляем элемент после завершения анимации
        setTimeout(() => {
            if (sparkle.parentNode) {
                sparkle.parentNode.removeChild(sparkle);
            }
        }, 1500);
    }
}

function createCorrectAnswerEffect() {
    // Эффект для правильного ответа
    const questArea = document.querySelector('.quest-area');
    if (questArea) {
        questArea.style.animation = 'pulse 0.5s ease-out';
        
        setTimeout(() => {
            questArea.style.animation = '';
        }, 500);
    }
    
    // Добавляем немного блёсток
    for (let i = 0; i < 3; i++) {
        setTimeout(() => createSingleSparkle(), i * 100);
    }
}

function createSingleSparkle() {
    const sparkle = document.createElement('div');
    sparkle.style.cssText = `
        position: fixed;
        font-size: 1.5rem;
        pointer-events: none;
        z-index: 1000;
        left: ${Math.random() * window.innerWidth}px;
        top: ${Math.random() * window.innerHeight}px;
        animation: sparkle 1s ease-out forwards;
    `;
    sparkle.textContent = '✨';
    
    document.body.appendChild(sparkle);
    
    setTimeout(() => {
        if (sparkle.parentNode) {
            sparkle.parentNode.removeChild(sparkle);
        }
    }, 1000);
}

📊 Обновление интерфейса

Функция для отображения полученных достижений:

function updateAchievements() {
    const achievementsList = document.getElementById('achievementsList');
    
    if (achievements.length === 0) {
        achievementsList.innerHTML = 'Решай примеры, чтобы получить достижения!';
        return;
    }
    
    // Создаём HTML для каждого достижения
    const achievementsHTML = achievements
        .map(achievementId => {
            const achievement = achievementsList.find(a => a.id === achievementId);
            return `<span class="achievement">${achievement.name}</span>`;
        })
        .join('');
    
    achievementsList.innerHTML = achievementsHTML;
}

// CSS стили для достижений
const achievementStyles = `
    .achievement {
        background: linear-gradient(135deg, #fdcb6e, #e17055);
        color: white;
        padding: 8px 15px;
        border-radius: 15px;
        margin: 5px;
        display: inline-block;
        font-size: 0.9rem;
        font-weight: bold;
        box-shadow: 0 2px 5px rgba(253, 203, 110, 0.3);
        animation: achievementGlow 2s ease-in-out infinite alternate;
    }
    
    @keyframes achievementGlow {
        0% { box-shadow: 0 2px 5px rgba(253, 203, 110, 0.3); }
        100% { box-shadow: 0 4px 15px rgba(253, 203, 110, 0.6); }
    }
`;

⚡ Интеграция с игрой

Обновляем функцию проверки ответов для включения новых эффектов:

// Обновленная функция проверки ответа
function checkAnswer() {
    const userAnswer = parseFloat(document.getElementById('answerInput').value);
    const feedback = document.getElementById('feedback');
    
    if (isNaN(userAnswer)) {
        feedback.textContent = '❌ Введи число!';
        feedback.className = 'feedback wrong';
        return;
    }
    
    if (Math.abs(userAnswer - currentProblem.answer) < 0.01) {
        // Правильный ответ!
        streak++;
        totalSolved++;
        
        // Учитываем скоростное решение
        if (speedTimer === null) {
            speedTimer = Date.now();
            speedSolved = 1;
        } else if (Date.now() - speedTimer < 120000) { // 2 минуты
            speedSolved++;
        } else {
            speedTimer = Date.now();
            speedSolved = 1;
        }
        
        const basePoints = { easy: 10, medium: 25, hard: 50 };
        const points = basePoints[difficulty] + (streak * 5);
        score += points;
        
        feedback.textContent = `🎉 Правильно! +${points} очков!`;
        feedback.className = 'feedback correct';
        
        // Новые эффекты!
        createCorrectAnswerEffect();
        checkLevelUp();
        checkAchievements(); // Проверяем достижения
        
        setTimeout(() => generateProblem(), 1500);
        
    } else {
        // Неправильный ответ
        streak = 0;
        speedTimer = null; // Сбрасываем скоростной таймер
        speedSolved = 0;
        
        feedback.textContent = `❌ Неверно! Правильный ответ: ${currentProblem.answer}`;
        feedback.className = 'feedback wrong';
    }
    
    updateStats();
}

💾 Сохранение прогресса (Бонус)

Дополнительная функция для сохранения данных между сессиями:

// Сохранение в localStorage
function saveProgress() {
    const gameData = {
        level,
        score,
        totalSolved,
        achievements,
        difficulty,
        bestStreak: Math.max(streak, getBestStreak())
    };
    
    localStorage.setItem('mathAppProgress', JSON.stringify(gameData));
}

// Загрузка из localStorage
function loadProgress() {
    const saved = localStorage.getItem('mathAppProgress');
    
    if (saved) {
        const gameData = JSON.parse(saved);
        
        level = gameData.level || 1;
        score = gameData.score || 0;
        totalSolved = gameData.totalSolved || 0;
        achievements = gameData.achievements || [];
        difficulty = gameData.difficulty || 'easy';
        
        // Обновляем интерфейс
        updateStats();
        updateAchievements();
        setDifficulty(difficulty);
        
        console.log('Прогресс загружен! 💾');
    }
}

function getBestStreak() {
    const saved = localStorage.getItem('mathAppProgress');
    if (saved) {
        const data = JSON.parse(saved);
        return data.bestStreak || 0;
    }
    return 0;
}

// Автосохранение каждые 30 секунд
setInterval(saveProgress, 30000);
localStorage

Встроенное API браузера для хранения данных. Данные сохраняются между сессиями и не удаляются при закрытии браузера

🎨 CSS анимации

Добавляем стили для всех анимаций:

/* CSS для анимаций уведомлений */
@keyframes slideIn {
    from {
        transform: translateX(100%);
        opacity: 0;
    }
    to {
        transform: translateX(0);
        opacity: 1;
    }
}

@keyframes slideOut {
    from {
        transform: translateX(0);
        opacity: 1;
    }
    to {
        transform: translateX(100%);
        opacity: 0;
    }
}

/* Анимация пульсации для правильных ответов */
@keyframes pulse {
    0% { transform: scale(1); }
    50% { transform: scale(1.05); background: rgba(0, 184, 148, 0.1); }
    100% { transform: scale(1); }
}

/* Анимация для блёсток */
@keyframes sparkle {
    0% { 
        opacity: 1; 
        transform: scale(0) rotate(0deg); 
    }
    100% { 
        opacity: 0; 
        transform: scale(2) rotate(180deg); 
    }
}

✨ Демонстрация эффектов

Попробуй все эффекты которые мы создали:

🏆 Система достижений

Доступные эффекты:

📋 Примеры достижений:

🌟 Первый шаг
🔥 Горячая серия
💯 Сотка!
👑 Математический гений

Система мотивирует игроков решать больше примеров и достигать новых целей! 🎯

🔧 Инициализация приложения

Финальный код инициализации со всеми функциями:

// Полная инициализация приложения
document.addEventListener('DOMContentLoaded', function() {
    // Загружаем сохранённый прогресс
    loadProgress();
    
    // Устанавливаем начальный режим
    setMode('quest');
    
    // Генерируем первую задачу
    generateProblem();
    
    // Обновляем все интерфейсы
    updateStats();
    updateCalcDisplay();
    updateAchievements();
    
    // Добавляем CSS стили для анимаций
    const styleSheet = document.createElement('style');
    styleSheet.textContent = achievementStyles;
    document.head.appendChild(styleSheet);
    
    // Автосохранение при закрытии страницы
    window.addEventListener('beforeunload', saveProgress);
    
    // Приветственное сообщение
    setTimeout(() => {
        console.log('🧮 Математическое приложение полностью готово!');
        
        if (totalSolved === 0) {
            const feedback = document.getElementById('feedback');
            feedback.textContent = '🎮 Добро пожаловать! Реши свой первый пример!';
            feedback.style.color = '#667eea';
        }
    }, 1000);
});

🎊 Поздравляем с завершением курса!

Вы создали полноценное математическое приложение-игру!

Ваши достижения:

  • ✅ Освоили HTML структуры и формы
  • ✅ Изучили продвинутый CSS с Grid и анимациями
  • ✅ Создали сложную JavaScript логику
  • ✅ Реализовали систему игровых механик
  • ✅ Добавили систему достижений
  • ✅ Создали визуальные эффекты и анимации
  • ✅ Научились работать с localStorage
  • ✅ Построили полноценное веб-приложение

🎓 Итоги всего курса

  • HTML: Семантическая разметка, формы, доступность
  • CSS: Grid Layout, градиенты, анимации, адаптивность
  • JavaScript: DOM манипуляции, события, состояние, объекты
  • Геймификация: Очки, уровни, достижения, прогрессия
  • UX/UI: Обратная связь, эффекты, уведомления
  • Архитектура: Модульный код, управление данными
  • Оптимизация: Производительность, сохранение состояния

🚀 Куда двигаться дальше?

• Изучите React/Vue для больших приложений
• Добавьте серверную часть с Node.js
• Создайте мобильную версию с PWA
• Изучите TypeScript для типизации
• Добавьте мультиплеер с WebSocket
• Создайте свои уникальные игры и приложения!