🎯 Цель урока
В финальном уроке мы добавим систему достижений, красивые визуальные эффекты, анимации и сделаем последние штрихи для создания профессионального математического приложения. Превратим наш калькулятор в полноценную игру!
💡 Что вы узнаете:
• Систему достижений и наград
• Создание анимаций и спецэффектов
• Работу с массивами для хранения достижений
• Создание всплывающих уведомлений
• Финальную оптимизацию и полировку
📚 Продвинутые концепции
Проверка наличия элемента в массиве для предотвращения дублирования достижений
Управление временем для анимаций и отложенных действий
Динамическое создание HTML элементов для эффектов и уведомлений
Управление CSS анимациями из JavaScript кода
Сохранение прогресса игрока между сессиями (продвинутый уровень)
🏆 Система достижений
Создаём мотивирующую систему наград для игроков:
// Массив для хранения полученных достижений
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);
Встроенное 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
• Создайте свои уникальные игры и приложения!