← Назад к курсу

💾 Урок 5: Сохранение и полировка

Завершаем проект - добавляем сохранения и финальные штрихи

🎯 Цель урока

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

Ты освоишь localStorage для сохранения данных, научишься создавать полноценные веб-приложения с персистентным состоянием и профессиональной полировкой.

Демонстрация localStorage

Попробуй сохранить и загрузить данные прямо сейчас!

Нажми на кнопки, чтобы увидеть, как работает localStorage!

💾 Основы localStorage

localStorage позволяет сохранять данные в браузере пользователя. Данные остаются даже после закрытия браузера и перезагрузки компьютера.

💾 Основные функции localStorage
// Сохраняем данные
localStorage.setItem('ключ', 'значение');

// Получаем данные
const data = localStorage.getItem('ключ');

// Удаляем данные
localStorage.removeItem('ключ');

// Очищаем весь localStorage
localStorage.clear();

// Проверяем, есть ли данные
if (localStorage.getItem('ключ') !== null) {
  // Данные существуют
}

// Сохранение объектов (нужно преобразовать в JSON)
const myObject = { name: "Питомец", level: 5 };
localStorage.setItem('pet', JSON.stringify(myObject));

// Загрузка объектов
const savedPet = JSON.parse(localStorage.getItem('pet'));

JSON.stringify() превращает объект в строку, а JSON.parse() обратно в объект.

💾 Функции сохранения питомца

Создадим функции для сохранения всего состояния нашего тамагочи: статистики, уровень, достижения, возраст и стадию развития.

💾 Система сохранения
// Ключ для сохранения данных
const SAVE_KEY = 'tamagochi_save_data';

// Функция сохранения всех данных
function saveGame() {
  try {
    // Создаём объект с данными для сохранения
    const saveData = {
      pet: {
        name: pet.name,
        level: pet.level,
        age: pet.age,
        stage: pet.stage,
        emoji: pet.emoji,
        stats: { ...pet.stats }, // Копируем статистики
        status: pet.status,
        lastFed: pet.lastFed,
        isAlive: pet.isAlive,
        intelligence: pet.intelligence || 0,
        experience: pet.experience || 0
      },
      achievements: { ...achievements }, // Копируем достижения
      gameStats: {
        totalActions: gameStats.totalActions || 0,
        gamesPlayed: gameStats.gamesPlayed || 0,
        evolutionsCount: gameStats.evolutionsCount || 0
      },
      saveDate: new Date().toISOString(),
      version: "1.0" // На случай будущих обновлений
    };

    // Сохраняем в localStorage
    localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
    
    showMessage("💾 Игра сохранена успешно!");
    showSaveAnimation();
    
    return true;
  } catch (error) {
    console.error("Ошибка сохранения:", error);
    showMessage("❌ Ошибка при сохранении!");
    return false;
  }
}

// Функция загрузки данных
function loadGame() {
  try {
    const savedData = localStorage.getItem(SAVE_KEY);
    
    if (!savedData) {
      showMessage("📁 Сохранённых данных не найдено");
      return false;
    }

    const saveData = JSON.parse(savedData);
    
    // Проверяем версию сохранения
    if (!saveData.version) {
      showMessage("⚠️ Старая версия сохранения!");
    }

    // Загружаем данные питомца
    pet.name = saveData.pet.name;
    pet.level = saveData.pet.level;
    pet.age = saveData.pet.age;
    pet.stage = saveData.pet.stage;
    pet.emoji = saveData.pet.emoji;
    pet.stats = { ...saveData.pet.stats };
    pet.status = saveData.pet.status;
    pet.lastFed = saveData.pet.lastFed;
    pet.isAlive = saveData.pet.isAlive;
    pet.intelligence = saveData.pet.intelligence || 0;
    pet.experience = saveData.pet.experience || 0;

    // Загружаем достижения
    Object.assign(achievements, saveData.achievements);

    // Загружаем игровую статистику
    if (saveData.gameStats) {
      gameStats = { ...saveData.gameStats };
    }

    // Обновляем интерфейс
    updateDisplay();
    updateAchievementsDisplay();
    
    const saveDate = new Date(saveData.saveDate).toLocaleString();
    showMessage(`📁 Игра загружена! Сохранено: ${saveDate}`);
    
    return true;
  } catch (error) {
    console.error("Ошибка загрузки:", error);
    showMessage("❌ Ошибка при загрузке!");
    return false;
  }
}

⚙️ Автосохранение

Добавим автоматическое сохранение каждые несколько минут, чтобы игрок не потерял прогресс, если забудет сохраниться вручную.

⚙️ Система автосохранения
// Настройки автосохранения
const AUTOSAVE_INTERVAL = 3 * 60 * 1000; // 3 минуты в миллисекундах
let autosaveTimer = null;
let gameModified = false; // Флаг изменений

// Запуск автосохранения
function startAutosave() {
  if (autosaveTimer) {
    clearInterval(autosaveTimer);
  }
  
  autosaveTimer = setInterval(() => {
    if (gameModified && pet.isAlive) {
      saveGame();
      gameModified = false;
      console.log("Автосохранение выполнено");
    }
  }, AUTOSAVE_INTERVAL);
}

// Остановка автосохранения
function stopAutosave() {
  if (autosaveTimer) {
    clearInterval(autosaveTimer);
    autosaveTimer = null;
  }
}

// Функция для отметки изменений
function markGameModified() {
  gameModified = true;
}

// Автозагрузка при старте игры
function initializeGame() {
  // Пытаемся загрузить сохранённые данные
  if (localStorage.getItem(SAVE_KEY)) {
    const userWantsLoad = confirm("Найдено сохранение! Загрузить игру?");
    if (userWantsLoad) {
      loadGame();
    }
  }
  
  // Запускаем автосохранение
  startAutosave();
  
  // Запускаем главный игровой цикл
  startGameLoop();
}

// Сохранение при закрытии страницы
window.addEventListener('beforeunload', (event) => {
  if (gameModified && pet.isAlive) {
    saveGame();
  }
});

🔄 Функция сброса игры

Иногда игроку может понадобиться начать заново. Создадим безопасную функцию сброса с подтверждением действия.

🔄 Система сброса
function resetGame() {
  // Двойное подтверждение для безопасности
  const firstConfirm = confirm(
    "⚠️ Вы уверены, что хотите начать заново?\nВесь прогресс будет потерян!"
  );
  
  if (!firstConfirm) return;
  
  const secondConfirm = confirm(
    "🚨 ПОСЛЕДНЕЕ ПРЕДУПРЕЖДЕНИЕ!\nЭто действие нельзя отменить. Продолжить?"
  );
  
  if (!secondConfirm) return;
  
  // Останавливаем все процессы
  stopAutosave();
  stopGameLoop();
  
  // Очищаем localStorage
  localStorage.removeItem(SAVE_KEY);
  
  // Сбрасываем объект питомца к начальным значениям
  pet = {
    name: "Малыш",
    level: 1,
    age: 0,
    stage: "egg",
    emoji: "🥚",
    stats: {
      hunger: 100,
      happiness: 100,
      energy: 100,
      cleanliness: 100
    },
    status: "Спокоен",
    lastFed: Date.now(),
    isAlive: true,
    intelligence: 0,
    experience: 0
  };
  
  // Сбрасываем достижения
  Object.keys(achievements).forEach(key => {
    achievements[key].unlocked = false;
    if (achievements[key].current !== undefined) {
      achievements[key].current = 0;
    }
  });
  
  // Сбрасываем игровую статистику
  gameStats = {
    totalActions: 0,
    gamesPlayed: 0,
    evolutionsCount: 0
  };
  
  // Обновляем интерфейс
  updateDisplay();
  updateAchievementsDisplay();
  
  // Перезапускаем игру
  initializeGame();
  
  showMessage("🔄 Игра сброшена! Добро пожаловать снова!");
}
🔊

Звуковые эффекты

Добавь звуки кормления, игр и эволюции для большей погружённости

📱

Мобильная адаптация

Оптимизируй интерфейс для телефонов и планшетов

🎨

Темы оформления

Создай разные цветовые темы на выбор игрока

📊

Статистика игры

Покажи статистику: время игры, количество действий, рекорды

🏆

Дополнительные достижения

Добавь больше достижений для долгосрочной мотивации

🎁

Система подарков

Случайные подарки за хороший уход повышают интерес

✨ Финальные улучшения

Небольшие детали делают игру профессиональной. Добавим уведомления, улучшенную анимацию и обработку ошибок.

✨ Полировка интерфейса
// Красивые уведомления
function showNotification(message, type = 'info') {
  const notification = document.createElement('div');
  notification.className = `notification ${type}`;
  notification.textContent = message;
  
  document.body.appendChild(notification);
  
  // Анимация появления
  setTimeout(() => {
    notification.classList.add('show');
  }, 100);
  
  // Автоматическое исчезновение
  setTimeout(() => {
    notification.classList.add('hide');
    setTimeout(() => {
      notification.remove();
    }, 300);
  }, 3000);
}

// Анимация сохранения
function showSaveAnimation() {
  const saveIcon = document.createElement('div');
  saveIcon.className = 'save-animation';
  saveIcon.textContent = '💾';
  
  document.body.appendChild(saveIcon);
  
  setTimeout(() => {
    saveIcon.remove();
  }, 2000);
}

// Обработка ошибок
window.addEventListener('error', (event) => {
  console.error('Ошибка игры:', event.error);
  showNotification('Произошла ошибка! Попробуйте перезагрузить страницу.', 'error');
});

// Проверка поддержки localStorage
function checkLocalStorageSupport() {
  try {
    const test = 'test';
    localStorage.setItem(test, test);
    localStorage.removeItem(test);
    return true;
  } catch (e) {
    showNotification('Ваш браузер не поддерживает сохранения!', 'warning');
    return false;
  }
}

💾 Твоё задание

Добавь систему сохранения и финальную полировку:

  1. Функции saveGame() и loadGame() с обработкой ошибок
  2. Автосохранение каждые 3 минуты
  3. Автозагрузку при запуске игры с подтверждением
  4. Безопасную функцию сброса игры
  5. Сохранение при закрытии браузера
  6. Красивые уведомления для важных событий
  7. Проверку поддержки localStorage
  8. CSS анимации для улучшения UX

💡 Тестируй сохранения в разных браузерах и устройствах!

🎉 Поздравляем!

Ты создал полнофункционального виртуального питомца!

Твой тамагочи умеет:

  • 🍎 Есть и поддерживать здоровье
  • 🎮 Играть и развивать интеллект
  • 🌱 Эволюционировать через 5 стадий
  • 🧠 Играть в мини-игры на память
  • 🏆 Зарабатывать достижения
  • 💾 Сохранять прогресс навсегда
  • ✨ Реагировать на твою заботу
🎮 Играть с питомцем!

💡 Советы для дальнейшего развития

Расширяй функциональность: Добавь новые мини-игры, больше эволюций, систему друзей или возможность менять имя питомца.
Улучшай графику: Замени эмодзи на собственные спрайты, добавь анимированные GIF или даже 3D модели.
Социальные функции: Добавь возможность делиться достижениями в соцсетях или сравнивать питомцев с друзьями.
Мобильная версия: Сделай PWA (Progressive Web App) для установки на телефон как настоящее приложение.
Изучай дальше: Освоив этот проект, ты готов к изучению фреймворков как React, Vue.js или созданию игр на Canvas!
🏠 Вернуться на главную →