/
vitish
/
game
Обзор
Документация
Войти
/
vitish
/
game
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
dev
game.js
998 строк
29 KB
vitish
update game.js
23 дек 2025, 15:55
23 дек 2025, 15:55
193a0b9
Код
Авторство
О чём код?
// ==================== НАСТРОЙКИ ИГРЫ ==================== const GAME_SETTINGS = { // Основные настройки initialTime: 30, initialLives: 3, // Настройки босса bossSpawnInterval: 5000, // 5 секунд bossHealth: 5, bossPoints: 200, bossSpeed: 3, bossSize: 100, // Очки points: { bug: 10, feature: -1, // минус жизнь bonus: 50 }, // Интервалы создания spawnIntervals: { bug: 800, // мс feature: 1500, bonus: 3000 // бонус раз в 3 секунды }, // Уровни levels: [ { bugs: 5, features: 2, speed: 1.0 }, { bugs: 7, features: 3, speed: 1.2 }, { bugs: 10, features: 4, speed: 1.5 }, { bugs: 12, features: 5, speed: 1.8 }, { bugs: 15, features: 6, speed: 2.0 } ] }; // ==================== ЗВУКОВОЙ МЕНЕДЖЕР ==================== class SoundManager { constructor() { this.audioContext = null; this.enabled = true; this.init(); } init() { try { this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); } catch (e) { this.enabled = false; console.log("Звук недоступен"); } } playTone(frequency, duration, type = 'sine', volume = 0.3) { if (!this.enabled || !this.audioContext) return; try { // Возобновляем контекст если нужно if (this.audioContext.state === 'suspended') { this.audioContext.resume(); } const oscillator = this.audioContext.createOscillator(); const gainNode = this.audioContext.createGain(); oscillator.connect(gainNode); gainNode.connect(this.audioContext.destination); oscillator.frequency.value = frequency; oscillator.type = type; // Плавное появление и исчезновение звука const now = this.audioContext.currentTime; gainNode.gain.setValueAtTime(0, now); gainNode.gain.linearRampToValueAtTime(volume, now + 0.01); gainNode.gain.exponentialRampToValueAtTime(0.001, now + duration); oscillator.start(now); oscillator.stop(now + duration); } catch (e) { // Игнорируем ошибки звука } } // Звуки для разных событий playClick() { this.playTone(800, 0.1, 'square'); } playError() { this.playTone(300, 0.3, 'sawtooth'); setTimeout(() => this.playTone(200, 0.2, 'sawtooth'), 100); } playBonus() { for(let i = 0; i < 5; i++) { setTimeout(() => this.playTone(300 + i * 100, 0.1), i * 50); } } playBossSpawn() { this.playTone(150, 0.8, 'sawtooth'); setTimeout(() => this.playTone(250, 0.6, 'sawtooth'), 200); setTimeout(() => this.playTone(350, 0.4, 'sawtooth'), 400); } playBossHit() { this.playTone(100, 0.2, 'square', 0.5); setTimeout(() => this.playTone(50, 0.1, 'square', 0.3), 50); } playBossDefeat() { for(let i = 0; i < 8; i++) { setTimeout(() => { this.playTone(100 + i * 50, 0.2); }, i * 100); } } playLevelUp() { const notes = [262, 330, 392, 523]; // C, E, G, C notes.forEach((note, i) => { setTimeout(() => this.playTone(note, 0.3), i * 150); }); } playGameOver() { const notes = [523, 392, 330, 262]; // C, G, E, C (в обратном порядке) notes.forEach((note, i) => { setTimeout(() => this.playTone(note, 0.5), i * 200); }); } } // ==================== СОСТОЯНИЕ ИГРЫ ==================== let gameState = { // Основные параметры score: 0, level: 1, lives: 3, timeLeft: 30, gameActive: false, // Статистика bugsKilled: 0, featuresAvoided: 0, bossesDefeated: 0, combos: 0, // Босс bossActive: false, bossHealth: 0, bossElement: null, bossDirection: 1, bossTimer: null, bossSpawnTimer: null, timeToBoss: 5, // Таймеры timers: [], // Звук sounds: new SoundManager() }; // ==================== ЭЛЕМЕНТЫ DOM ==================== const startScreen = document.getElementById('start-screen'); const gameScreen = document.getElementById('game-screen'); const endScreen = document.getElementById('end-screen'); const startBtn = document.getElementById('start-btn'); const restartBtn = document.getElementById('restart-btn'); const pauseBtn = document.getElementById('pause-btn'); const soundToggle = document.getElementById('sound-toggle'); const helpBtn = document.getElementById('help-btn'); const shareBtn = document.getElementById('share-btn'); const gameArea = document.getElementById('game-area'); const scoreEl = document.getElementById('score'); const livesEl = document.getElementById('lives'); const timeEl = document.getElementById('time'); const levelEl = document.getElementById('level'); const bossTimerEl = document.getElementById('boss-timer'); const bossProgressEl = document.getElementById('boss-progress'); const bossStatusEl = document.getElementById('boss-status'); const bossHealthEl = document.getElementById('boss-health'); const bossHealthFillEl = document.getElementById('boss-health-fill'); const finalScoreEl = document.getElementById('final-score'); const finalBugsEl = document.getElementById('final-bugs'); const finalBossesEl = document.getElementById('final-bosses'); const achievementIconEl = document.getElementById('achievement-icon'); const achievementTitleEl = document.getElementById('achievement-title'); const achievementDescEl = document.getElementById('achievement-desc'); const endMessageEl = document.getElementById('end-message'); const highScoreEl = document.getElementById('high-score'); const messageContainer = document.getElementById('message-container'); // ==================== ИНИЦИАЛИЗАЦИЯ ==================== document.addEventListener('DOMContentLoaded', () => { // Загружаем лучший результат loadHighScore(); // Показываем стартовый экран startScreen.classList.add('active'); // Анимация при загрузке setTimeout(() => { showMessage('Готовы к охоте на баги? 🐛', 'info'); }, 1000); }); // ==================== ОСНОВНЫЕ ФУНКЦИИ ИГРЫ ==================== // Начало игры startBtn.addEventListener('click', startGame); restartBtn.addEventListener('click', startGame); function startGame() { // Сброс состояния gameState = { score: 0, level: 1, lives: GAME_SETTINGS.initialLives, timeLeft: GAME_SETTINGS.initialTime, gameActive: true, bugsKilled: 0, featuresAvoided: 0, bossesDefeated: 0, combos: 0, bossActive: false, bossHealth: 0, bossElement: null, bossDirection: 1, bossTimer: null, bossSpawnTimer: null, timeToBoss: 5, timers: [], sounds: new SoundManager() }; // Очистка экрана clearAllTimers(); gameArea.innerHTML = ''; hideAllMessages(); // Обновление интерфейса updateUI(); updateBossTimer(); // Переключение экранов startScreen.classList.remove('active'); endScreen.classList.remove('active'); gameScreen.classList.add('active'); // Запуск игровых процессов startLevel(); startBossSpawnTimer(); // Звук начала игры gameState.sounds.playLevelUp(); // Сообщение showMessage('Удачи! Уничтожай баги! 🎯', 'success'); } // Запуск уровня function startLevel() { const levelSettings = GAME_SETTINGS.levels[gameState.level - 1] || GAME_SETTINGS.levels[0]; // Запуск таймера игры const gameTimer = setInterval(() => { if (!gameState.gameActive) return; gameState.timeLeft--; timeEl.textContent = gameState.timeLeft + 'с'; if (gameState.timeLeft <= 0) { endGame(); } }, 1000); gameState.timers.push(gameTimer); // Создание багов const bugTimer = setInterval(() => { if (gameState.gameActive) { createBug(); } }, GAME_SETTINGS.spawnIntervals.bug / levelSettings.speed); gameState.timers.push(bugTimer); // Создание фич const featureTimer = setInterval(() => { if (gameState.gameActive) { createFeature(); } }, GAME_SETTINGS.spawnIntervals.feature / levelSettings.speed); gameState.timers.push(featureTimer); // Создание бонусов const bonusTimer = setInterval(() => { if (gameState.gameActive && Math.random() > 0.7) { createBonus(); } }, GAME_SETTINGS.spawnIntervals.bonus); gameState.timers.push(bonusTimer); } // Обновление интерфейса function updateUI() { scoreEl.textContent = gameState.score; livesEl.textContent = gameState.lives; timeEl.textContent = gameState.timeLeft + 'с'; levelEl.textContent = gameState.level; // Обновление цвета жизней if (gameState.lives <= 1) { livesEl.style.color = '#ff416c'; } else if (gameState.lives <= 2) { livesEl.style.color = '#ffcc00'; } else { livesEl.style.color = '#00ff9d'; } } // Обновление таймера босса function updateBossTimer() { bossTimerEl.textContent = gameState.timeToBoss; const percent = (gameState.timeToBoss / 5) * 100; bossProgressEl.style.width = percent + '%'; } // ==================== СОЗДАНИЕ ОБЪЕКТОВ ==================== // Создание бага function createBug() { if (!gameState.gameActive || gameArea.children.length > 20) return; const bug = document.createElement('div'); bug.className = 'bug'; bug.innerHTML = '🐛'; // Случайная позиция const x = Math.random() * (gameArea.offsetWidth - 80); const y = Math.random() * (gameArea.offsetHeight - 80); bug.style.left = x + 'px'; bug.style.top = y + 'px'; // Обработчик клика bug.addEventListener('click', handleBugClick); // Добавление в игру gameArea.appendChild(bug); // Автоудаление через 5 секунд const timer = setTimeout(() => { if (bug.parentNode) { bug.remove(); gameState.combos = 0; } }, 5000); gameState.timers.push(timer); } // Создание фичи function createFeature() { if (!gameState.gameActive) return; const feature = document.createElement('div'); feature.className = 'feature'; feature.innerHTML = '✨'; const x = Math.random() * (gameArea.offsetWidth - 80); const y = Math.random() * (gameArea.offsetHeight - 80); feature.style.left = x + 'px'; feature.style.top = y + 'px'; feature.addEventListener('click', handleFeatureClick); gameArea.appendChild(feature); const timer = setTimeout(() => { if (feature.parentNode) { feature.remove(); gameState.featuresAvoided++; } }, 4000); gameState.timers.push(timer); } // Создание бонуса function createBonus() { if (!gameState.gameActive) return; const bonus = document.createElement('div'); bonus.className = 'bonus'; bonus.innerHTML = '🎯'; const x = Math.random() * (gameArea.offsetWidth - 80); const y = Math.random() * (gameArea.offsetHeight - 80); bonus.style.left = x + 'px'; bonus.style.top = y + 'px'; bonus.addEventListener('click', handleBonusClick); gameArea.appendChild(bonus); const timer = setTimeout(() => { if (bonus.parentNode) { bonus.remove(); } }, 3000); gameState.timers.push(timer); } // ==================== ОБРАБОТЧИКИ КЛИКОВ ==================== // Клик по багу function handleBugClick(e) { if (!gameState.gameActive) return; const bug = e.target; // Обновление статистики gameState.score += GAME_SETTINGS.points.bug; gameState.bugsKilled++; gameState.combos++; // Звук gameState.sounds.playClick(); // Анимация bug.style.transition = 'all 0.3s'; bug.style.transform = 'scale(1.5) rotate(45deg)'; bug.style.opacity = '0'; // Эффект частиц createParticles(bug, '#ff416c'); // Обновление UI updateUI(); // Удаление setTimeout(() => { if (bug.parentNode) { bug.remove(); } }, 300); // Проверка комбо if (gameState.combos >= 5) { showMessage(`КОМБО x${gameState.combos}! 🔥`, 'warning'); gameState.score += gameState.combos * 5; updateUI(); } } // Клик по фиче function handleFeatureClick(e) { if (!gameState.gameActive) return; const feature = e.target; // Штраф gameState.lives--; gameState.combos = 0; // Звук gameState.sounds.playError(); // Анимация feature.style.transition = 'all 0.3s'; feature.innerHTML = '💥'; feature.style.transform = 'scale(1.5)'; feature.style.backgroundColor = '#ff416c'; createParticles(feature, '#ff416c'); // Обновление UI updateUI(); // Проверка жизней if (gameState.lives <= 0) { endGame(); } // Удаление setTimeout(() => { if (feature.parentNode) { feature.remove(); } }, 500); showMessage('Осторожно! Это фича! ⚠️', 'error'); } // Клик по бонусу function handleBonusClick(e) { if (!gameState.gameActive) return; const bonus = e.target; // Бонус gameState.score += GAME_SETTINGS.points.bonus; // Звук gameState.sounds.playBonus(); // Анимация bonus.style.transition = 'all 0.3s'; bonus.style.transform = 'scale(2)'; bonus.style.opacity = '0'; createParticles(bonus, '#ffcc00'); // Обновление UI updateUI(); // Удаление setTimeout(() => { if (bonus.parentNode) { bonus.remove(); } }, 300); showMessage(`БОНУС +${GAME_SETTINGS.points.bonus}! 🎁`, 'success'); } // ==================== СИСТЕМА БОССА ==================== // Таймер появления босса function startBossSpawnTimer() { gameState.bossSpawnTimer = setInterval(() => { if (!gameState.gameActive || gameState.bossActive) return; gameState.timeToBoss--; updateBossTimer(); if (gameState.timeToBoss <= 0) { spawnBoss(); gameState.timeToBoss = 5; } }, 1000); } // Появление босса function spawnBoss() { if (gameState.bossActive) return; gameState.bossActive = true; gameState.bossHealth = GAME_SETTINGS.bossHealth; // Создание элемента босса const boss = document.createElement('div'); boss.className = 'boss'; boss.innerHTML = '👾'; // Позиция boss.style.left = (gameArea.offsetWidth - GAME_SETTINGS.bossSize) / 2 + 'px'; boss.style.top = '20px'; boss.style.width = GAME_SETTINGS.bossSize + 'px'; boss.style.height = GAME_SETTINGS.bossSize + 'px'; // Обработчик клика boss.addEventListener('click', handleBossClick); // Добавление в игру gameArea.appendChild(boss); gameState.bossElement = boss; // Обновление UI босса updateBossUI(); bossStatusEl.classList.remove('hidden'); // Звук gameState.sounds.playBossSpawn(); // Сообщение showMessage('ПОЯВИЛСЯ БОСС! АТАКУЙ! 👾', 'error'); // Движение босса moveBoss(); } // Движение босса function moveBoss() { if (!gameState.gameActive || !gameState.bossActive || !gameState.bossElement) return; const boss = gameState.bossElement; let currentX = parseInt(boss.style.left) || 0; // Движение currentX += GAME_SETTINGS.bossSpeed * gameState.bossDirection; // Проверка границ if (currentX <= 0) { currentX = 0; gameState.bossDirection = 1; } else if (currentX >= gameArea.offsetWidth - GAME_SETTINGS.bossSize) { currentX = gameArea.offsetWidth - GAME_SETTINGS.bossSize; gameState.bossDirection = -1; } boss.style.left = currentX + 'px'; // Продолжение движения if (gameState.bossActive) { requestAnimationFrame(moveBoss); } } // Клик по боссу function handleBossClick(e) { if (!gameState.gameActive || !gameState.bossActive) return; e.stopPropagation(); gameState.bossHealth--; updateBossUI(); // Звук попадания gameState.sounds.playBossHit(); // Анимация попадания const boss = gameState.bossElement; boss.style.transform = 'scale(1.2)'; setTimeout(() => { boss.style.transform = 'scale(1)'; }, 100); // Создание частиц createParticles(boss, '#8e2de2'); // Проверка здоровья босса if (gameState.bossHealth <= 0) { defeatBoss(); } } // Обновление UI босса function updateBossUI() { bossHealthEl.textContent = gameState.bossHealth; const healthPercent = (gameState.bossHealth / GAME_SETTINGS.bossHealth) * 100; bossHealthFillEl.style.width = healthPercent + '%'; } // Победа над боссом function defeatBoss() { if (!gameState.bossElement) return; // Награда gameState.score += GAME_SETTINGS.bossPoints; gameState.bossesDefeated++; gameState.bossActive = false; // Звук победы gameState.sounds.playBossDefeat(); // Анимация const boss = gameState.bossElement; boss.style.transition = 'all 1s'; boss.style.transform = 'scale(0) rotate(720deg)'; boss.style.opacity = '0'; // Создание множества частиц for (let i = 0; i < 20; i++) { setTimeout(() => { createParticles(boss, '#ffcc00'); }, i * 50); } // Обновление UI updateUI(); bossStatusEl.classList.add('hidden'); // Сообщение showMessage(`БОСС ПОБЕЖДЕН! +${GAME_SETTINGS.bossPoints} 🏆`, 'success'); // Удаление босса setTimeout(() => { if (boss.parentNode) { boss.remove(); gameState.bossElement = null; } }, 1000); // Сброс таймера босса gameState.timeToBoss = 5; updateBossTimer(); } // ==================== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ==================== // Создание частиц function createParticles(element, color) { const rect = element.getBoundingClientRect(); const x = rect.left + rect.width / 2; const y = rect.top + rect.height / 2; for (let i = 0; i < 8; i++) { const particle = document.createElement('div'); particle.style.position = 'fixed'; particle.style.width = '10px'; particle.style.height = '10px'; particle.style.backgroundColor = color; particle.style.borderRadius = '50%'; particle.style.left = x + 'px'; particle.style.top = y + 'px'; particle.style.pointerEvents = 'none'; particle.style.zIndex = '1000'; document.body.appendChild(particle); // Анимация разлета частиц const angle = Math.random() * Math.PI * 2; const speed = 2 + Math.random() * 3; const vx = Math.cos(angle) * speed; const vy = Math.sin(angle) * speed; let posX = 0; let posY = 0; let opacity = 1; function animate() { posX += vx; posY += vy; opacity -= 0.02; particle.style.transform = `translate(${posX}px, ${posY}px)`; particle.style.opacity = opacity; if (opacity > 0) { requestAnimationFrame(animate); } else { particle.remove(); } } animate(); } } // Показ сообщений function showMessage(text, type = 'info') { const message = document.createElement('div'); message.className = `message ${type}`; let icon = '💡'; switch(type) { case 'success': icon = '✅'; break; case 'error': icon = '❌'; break; case 'warning': icon = '⚠️'; break; case 'info': icon = '💡'; break; } message.innerHTML = ` <span class="message-icon">${icon}</span> <span class="message-text">${text}</span> `; messageContainer.appendChild(message); // Автоудаление через 3 секунды setTimeout(() => { if (message.parentNode) { message.style.transition = 'all 0.5s'; message.style.opacity = '0'; message.style.transform = 'translateX(100%)'; setTimeout(() => { if (message.parentNode) { message.remove(); } }, 500); } }, 3000); } // Скрытие всех сообщений function hideAllMessages() { messageContainer.innerHTML = ''; } // Очистка всех таймеров function clearAllTimers() { gameState.timers.forEach(timer => { clearTimeout(timer); clearInterval(timer); }); gameState.timers = []; if (gameState.bossSpawnTimer) { clearInterval(gameState.bossSpawnTimer); } } // Конец игры function endGame() { gameState.gameActive = false; // Очистка таймеров clearAllTimers(); // Удаление всех объектов gameArea.innerHTML = ''; // Звук окончания игры gameState.sounds.playGameOver(); // Обновление финального экрана updateEndScreen(); // Сохранение лучшего результата saveHighScore(); // Переключение экранов gameScreen.classList.remove('active'); endScreen.classList.add('active'); } // Обновление экрана окончания function updateEndScreen() { finalScoreEl.textContent = gameState.score; finalBugsEl.textContent = gameState.bugsKilled; finalBossesEl.textContent = gameState.bossesDefeated; // Определение достижения let achievement = { icon: '🥉', title: 'Новичок', desc: 'Неплохо для начала!', message: 'Попробуйте еще раз!' }; if (gameState.score >= 1000) { achievement = { icon: '🏆', title: 'ГРОССМЕЙСТЕР', desc: 'Вы легенда охоты на багов!', message: 'Невероятный результат!' }; } else if (gameState.score >= 500) { achievement = { icon: '🥇', title: 'ЭКСПЕРТ', desc: 'Отличная работа!', message: 'Вы настоящий профессионал!' }; } else if (gameState.score >= 200) { achievement = { icon: '🥈', title: 'ПРОДВИНУТЫЙ', desc: 'Хороший результат!', message: 'Продолжайте в том же духе!' }; } // Обновление достижения achievementIconEl.textContent = achievement.icon; achievementTitleEl.textContent = achievement.title; achievementDescEl.textContent = achievement.desc; endMessageEl.textContent = achievement.message; } // ==================== СИСТЕМА РЕКОРДОВ ==================== // Загрузка лучшего результата function loadHighScore() { const highScore = localStorage.getItem('bugHunterHighScore') || 0; highScoreEl.textContent = highScore; } // Сохранение лучшего результата function saveHighScore() { const currentHighScore = parseInt(localStorage.getItem('bugHunterHighScore') || 0); if (gameState.score > currentHighScore) { localStorage.setItem('bugHunterHighScore', gameState.score); highScoreEl.textContent = gameState.score; showMessage('НОВЫЙ РЕКОРД! 🎉', 'success'); } } // ==================== УПРАВЛЕНИЕ ИГРОЙ ==================== // Кнопка звука soundToggle.addEventListener('click', () => { gameState.sounds.enabled = !gameState.sounds.enabled; const icon = soundToggle.querySelector('i'); if (gameState.sounds.enabled) { icon.className = 'fas fa-volume-up'; soundToggle.title = 'Выключить звук'; showMessage('Звук включен 🔊', 'success'); } else { icon.className = 'fas fa-volume-mute'; soundToggle.title = 'Включить звук'; showMessage('Звук выключен 🔇', 'warning'); } }); // Кнопка паузы pauseBtn.addEventListener('click', () => { if (!gameState.gameActive) return; gameState.gameActive = !gameState.gameActive; const icon = pauseBtn.querySelector('i'); if (gameState.gameActive) { icon.className = 'fas fa-pause'; pauseBtn.title = 'Пауза'; showMessage('Игра продолжается ▶️', 'success'); // Возобновление таймеров startLevel(); startBossSpawnTimer(); } else { icon.className = 'fas fa-play'; pauseBtn.title = 'Продолжить'; showMessage('Игра на паузе ⏸️', 'warning'); // Остановка таймеров clearAllTimers(); } }); // Кнопка помощи helpBtn.addEventListener('click', () => { showMessage('Кликай по 🐛 для очков, избегай ✨, побеждай 👾!', 'info'); }); // Кнопка поделиться shareBtn.addEventListener('click', () => { const text = `Я набрал ${gameState.score} очков в игре "Баго-ловец"! 🐛 Попробуй побить мой рекорд!`; if (navigator.share) { navigator.share({ title: 'Баго-ловец', text: text, url: window.location.href }); } else { navigator.clipboard.writeText(text + '\n' + window.location.href); showMessage('Ссылка скопирована в буфер обмена! 📋', 'success'); } }); // ==================== ДОПОЛНИТЕЛЬНЫЕ ФУНКЦИИ ==================== // Захват экрана при нажатии PrintScreen document.addEventListener('keydown', (e) => { if (e.key === 'PrintScreen') { e.preventDefault(); showMessage('Скриншот сохранен! 📸', 'info'); } }); // Предотвращение выделения текста во время игры document.addEventListener('selectstart', (e) => { if (gameState.gameActive) { e.preventDefault(); } }); // Анимация при наведении на элементы document.addEventListener('mouseover', (e) => { if (e.target.classList.contains('bug') || e.target.classList.contains('feature') || e.target.classList.contains('bonus') || e.target.classList.contains('boss')) { e.target.style.cursor = 'pointer'; } }); // ==================== ЭКСПОРТ ДЛЯ ДЕБАГГИНГА ==================== window.debugGame = { getState: () => gameState, addScore: (points) => { if (gameState.gameActive) { gameState.score += points; updateUI(); } }, spawnBoss: () => { if (gameState.gameActive && !gameState.bossActive) { spawnBoss(); } }, reset: () => { startGame(); } }; console.log('Игра "Баго-ловец" загружена! 🐛'); console.log('Для отладки используйте window.debugGame');