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

✨ Урок 5a: Анимационные эффекты

Оживляем игру с помощью CSS анимаций и JavaScript эффектов

🎯 Цель урока

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

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

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

Дрожание при поражении

😵

Прыжок при победе

🎉

Пульсация ожидания

Вращение загрузки

⚙️

Свечение выбора

Парение в воздухе

☁️

🎨 CSS Keyframes анимации

CSS @keyframes позволяют создавать сложные анимации. Определяем ключевые точки и браузер плавно интерполирует между ними.

🎨 Базовые анимации
/* Дрожание при ошибке */
@keyframes shake {
    0% { transform: translateX(-5px); }
    25% { transform: translateX(5px); }
    50% { transform: translateX(-5px); }
    75% { transform: translateX(5px); }
    100% { transform: translateX(0); }
}

/* Пульсация при ожидании */
@keyframes pulse {
    0%, 100% { 
        transform: scale(1); 
        opacity: 1; 
    }
    50% { 
        transform: scale(1.1); 
        opacity: 0.7; 
    }
}

/* Свечение для выделения */
@keyframes glow {
    0% { box-shadow: 0 0 10px #667eea; }
    100% { box-shadow: 0 0 30px #667eea, 0 0 40px #667eea; }
}

/* Применение анимаций */
.choice-button.shake {
    animation: shake 0.5s ease-out;
}

.choice-button.waiting {
    animation: pulse 1.5s infinite;
}

.choice-button.selected {
    animation: glow 2s infinite alternate;
}

🎪 Эффекты для результатов игры

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

🎪 Анимации результатов
/* Анимация победы - увеличение и зелёный цвет */
@keyframes winPulse {
    0% { 
        transform: scale(1); 
        background: linear-gradient(135deg, #667eea, #764ba2); 
    }
    50% { 
        transform: scale(1.2); 
        background: linear-gradient(135deg, #2ecc71, #27ae60); 
    }
    100% { 
        transform: scale(1); 
        background: linear-gradient(135deg, #667eea, #764ba2); 
    }
}

/* Анимация поражения - уменьшение и красный цвет */
@keyframes loseFade {
    0% { 
        transform: scale(1); 
        background: linear-gradient(135deg, #667eea, #764ba2); 
        opacity: 1; 
    }
    50% { 
        transform: scale(0.9); 
        background: linear-gradient(135deg, #e74c3c, #c0392b); 
        opacity: 0.7; 
    }
    100% { 
        transform: scale(1); 
        background: linear-gradient(135deg, #667eea, #764ba2); 
        opacity: 1; 
    }
}

/* Встряхивание всего экрана при критическом поражении */
@keyframes screenShake {
    0%, 100% { transform: translateX(0); }
    10% { transform: translateX(-10px); }
    20% { transform: translateX(10px); }
    30% { transform: translateX(-10px); }
    40% { transform: translateX(10px); }
}

⭐ JavaScript анимации и эффекты

Используем JavaScript для создания динамических эффектов: частиц, конфетти, плавных переходов и интерактивных анимаций.

⭐ Система анимаций
// Система управления анимациями
const AnimationSystem = {
    // Применить анимацию к элементу
    applyAnimation(element, animationClass, duration = 1000) {
        element.classList.add(animationClass);
        
        setTimeout(() => {
            element.classList.remove(animationClass);
        }, duration);
    },
    
    // Эффект победы для кнопки
    winEffect(buttonElement) {
        this.applyAnimation(buttonElement, 'animate-win', 1000);
        this.createConfetti(buttonElement);
    },
    
    // Эффект поражения
    loseEffect(buttonElement) {
        this.applyAnimation(buttonElement, 'animate-lose', 1000);
        this.shakeScreen();
    },
    
    // Встряхивание экрана
    shakeScreen() {
        const gameContainer = document.querySelector('.game-container');
        this.applyAnimation(gameContainer, 'screen-shake', 500);
    },
    
    // Создание конфетти
    createConfetti(centerElement) {
        const colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff', '#00ffff'];
        const container = document.body;
        
        for (let i = 0; i < 20; i++) {
            const confetti = document.createElement('div');
            confetti.className = 'confetti';
            confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
            confetti.style.left = Math.random() * 100 + 'vw';
            confetti.style.animationDelay = Math.random() * 2 + 's';
            
            container.appendChild(confetti);
            
            // Удаляем элемент после анимации
            setTimeout(() => {
                container.removeChild(confetti);
            }, 3000);
        }
    }
};

Интерактивная демонстрация

Нажми на кнопки, чтобы увидеть анимации в действии:

Левая кнопка - победа, средняя - поражение, правая - ничья

🌟 Эффекты частиц

Частицы добавляют профессионализм игре. Создадим систему для генерации искр, дыма, звёзд и других визуальных эффектов.

🌟 Система частиц
// Система частиц
const ParticleSystem = {
    particles: [],
    
    // Создать частицу
    createParticle(x, y, type = 'spark') {
        const particle = {
            x: x,
            y: y,
            vx: (Math.random() - 0.5) * 10, // Скорость по X
            vy: (Math.random() - 0.5) * 10, // Скорость по Y
            life: 1.0,                      // Жизнь частицы (0-1)
            decay: Math.random() * 0.02 + 0.01, // Скорость затухания
            type: type,
            size: Math.random() * 5 + 2,    // Размер
            color: this.getParticleColor(type)
        };
        
        this.particles.push(particle);
    },
    
    // Цвета для разных типов частиц
    getParticleColor(type) {
        const colors = {
            spark: '#ffd700',    // Золотые искры
            smoke: '#888888',    // Серый дым
            magic: '#9b59b6',    // Фиолетовая магия
            fire: '#ff4500'      // Оранжевый огонь
        };
        return colors[type] || colors.spark;
    },
    
    // Обновление всех частиц
    update() {
        for (let i = this.particles.length - 1; i >= 0; i--) {
            const p = this.particles[i];
            
            // Обновляем позицию
            p.x += p.vx;
            p.y += p.vy;
            
            // Гравитация
            p.vy += 0.3;
            
            // Затухание
            p.life -= p.decay;
            
            // Удаляем "мёртвые" частицы
            if (p.life <= 0) {
                this.particles.splice(i, 1);
            }
        }
    },
    
    // Эффект взрыва искр
    sparkExplosion(x, y, count = 15) {
        for (let i = 0; i < count; i++) {
            this.createParticle(x, y, 'spark');
        }
    }
};

📝 Текстовые эффекты

Анимированный текст делает интерфейс более живым:

Печатающийся текст

Твоя очередь!

Радужный текст

ПОБЕДА!

Глитч эффект

ERROR

🎭 Интеграция анимаций в игру

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

🎭 Интеграция в игровую логику
// Обновлённая функция игры с анимациями
function makeChoiceAnimated(playerChoice) {
    const playerButton = document.querySelector(`[data-choice="${playerChoice}"]`);
    const resultElement = document.getElementById('gameResult');
    
    // 1. Анимация выбора игрока
    AnimationSystem.applyAnimation(playerButton, 'selected', 500);
    
    // 2. Показываем индикатор загрузки
    resultElement.textContent = 'Компьютер думает...';
    AnimationSystem.applyAnimation(resultElement, 'pulse', 1500);
    
    // 3. Задержка для драматизма
    setTimeout(() => {
        const computerChoice = AISystem.getChoice();
        const result = determineWinner(playerChoice, computerChoice);
        
        // 4. Показываем результат с анимацией
        displayResult(result, playerChoice, computerChoice);
        
        // 5. Применяем соответствующую анимацию
        switch (result) {
            case 'win':
                AnimationSystem.winEffect(playerButton);
                ParticleSystem.sparkExplosion(
                    playerButton.offsetLeft + playerButton.offsetWidth / 2,
                    playerButton.offsetTop + playerButton.offsetHeight / 2
                );
                break;
                
            case 'lose':
                AnimationSystem.loseEffect(playerButton);
                break;
                
            case 'draw':
                AnimationSystem.applyAnimation(playerButton, 'pulse', 1000);
                break;
        }
        
        // 6. Обновляем статистику с анимацией
        updateStatsAnimated(result);
        
    }, 1000);
}

// Анимированное обновление статистики
function updateStatsAnimated(result) {
    updateStats(result); // Обычное обновление
    
    // Анимация изменившихся счётчиков
    const statElements = {
        wins: document.getElementById('wins'),
        losses: document.getElementById('losses'),
        draws: document.getElementById('draws'),
        streak: document.getElementById('streak')
    };
    
    switch (result) {
        case 'win':
            AnimationSystem.applyAnimation(statElements.wins, 'bounce', 600);
            AnimationSystem.applyAnimation(statElements.streak, 'glow', 1000);
            break;
        case 'lose':
            AnimationSystem.applyAnimation(statElements.losses, 'shake', 500);
            break;
        case 'draw':
            AnimationSystem.applyAnimation(statElements.draws, 'pulse', 800);
            break;
    }
}

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

Добавь анимационные эффекты в свою игру:

  1. Создай CSS @keyframes для основных анимаций (shake, pulse, glow, bounce)
  2. Реализуй систему управления анимациями через JavaScript
  3. Добавь анимации для каждого результата игры (победа, поражение, ничья)
  4. Создай эффект частиц для особых моментов
  5. Интегрируй анимации в основную логику игры
  6. Добавь анимированное обновление статистики
  7. Создай текстовые эффекты для результатов
  8. Протестируй все анимации на разных устройствах

💡 Не переборщи с анимациями - они должны улучшать, а не отвлекать!

Следующий урок: Силы-апы и полировка →