Щит для игры
Criado em: 10 de janeiro de 2025
Criado em: 10 de janeiro de 2025
Randomizing shield deployment
I'm mapping out a method to deploy the shield randomly within a one-minute game, removing the fixed interval and incorporating two setTimeout events at random spots, possibly using HTML/CSS for animation effects.
Thought about shield mechanics and improvements for a couple of seconds
Чтобы обеспечить появление щита на поле два раза за игру в случайные моменты и активировать его при попадании пули, внесём следующие изменения в ваш код:
Вместо текущего циклического создания щитов каждые 30 секунд изменим логику так, чтобы щит появлялся ровно два раза в случайные моменты в течение игры. Для этого в функции startGame()
будем генерировать два случайных момента в пределах продолжительности игры (60 секунд) и использовать setTimeout
для вызова createShield()
в эти моменты.
Найдём секцию кода в startGame()
и заменим планирование щита:
function startGame() { gameStarted = true; setInterval(createBullet, 500); setInterval(createMeteor, 1000); // Запланировать два падения щита в случайные моменты в течение 60 секунд const firstShieldTime = Math.random() * 60000; // время в мс до первого появления const secondShieldTime = Math.random() * 60000; // время в мс до второго появления setTimeout(createShield, firstShieldTime); setTimeout(createShield, secondShieldTime); }
В вашем коде уже реализована функция createShield()
и moveShield(shield)
. Они создают щит, заставляют его падать, и проверяют столкновение с пулей. Данный функционал оставляем без изменений, поскольку он соответствует требованиям.
В коде функция activateShield()
уже включает отображение эффекта щита на корабле:
function activateShield() { shieldActive = true; shieldEffect.style.display = 'block'; shieldEffect.style.left = `${shipX - 30}px`; shieldEffect.style.top = `${gameContainer.clientHeight - 100}px`; // Деактивация щита через 10 секунд shieldTimeout = setTimeout(() => { shieldActive = false; shieldEffect.style.display = 'none'; }, shieldDuration); }
Чтобы придать эффекту неоновый вид (неоновая анимация), добавьте соответствующие CSS-стили для элемента #shield-effect
(или любого другого выбранного селектора). Например:
#shield-effect { width: 100px; height: 100px; border-radius: 50%; border: 2px solid cyan; box-shadow: 0 0 10px cyan, 0 0 20px cyan, 0 0 30px cyan; pointer-events: none; /* чтобы щит не мешал кликам */ display: none; position: absolute; }
Анимация может быть добавлена с помощью CSS @keyframes или других эффектов по вашему усмотрению.
function startGame() { gameStarted = true; setInterval(createBullet, 500); setInterval(createMeteor, 1000); // Запланировать два падения щита в случайные моменты в течение 60 секунд const firstShieldTime = Math.random() * 60000; // время в мс до первого появления const secondShieldTime = Math.random() * 60000; // время в мс до второго появления setTimeout(createShield, firstShieldTime); setTimeout(createShield, secondShieldTime); }
При этом остальная логика падения, активации и деактивации щита, а также отображение эффекта остаются без изменений. Не забудьте добавить стили для неонового щита в вашем CSS, чтобы эффект стал более заметным.
Таким образом, щит будет появляться два раза за игру в случайные моменты, активироваться при попадании пули и отображать неоновую анимацию на корабле на 10 секунд.
Thought about shield system in JS code for a second
Ниже приведён полный код вашего JavaScript с внесёнными изменениями для системы щита, включая планирование двух появлений щита в случайные моменты игры:
const gameContainer = document.getElementById('game-container'); const ship = document.getElementById('ship'); const scoreElement = document.getElementById('score'); const countdownElement = document.getElementById('countdown'); const soundOnButton = document.getElementById('sound-on'); const soundOffButton = document.getElementById('sound-off'); const shield = document.getElementById('shield'); // Элемент щита const shieldEffect = document.getElementById('shield-effect'); // Элемент эффекта щита let score = 0; let shipX = gameContainer.clientWidth / 2 - 25; let shipSpeed = 10; let meteorSpeed = 5; let bulletSpeed = 10; let soundEnabled = true; let shieldActive = false; // Статус щита let shieldTimeout; // Таймер для щита let shieldDuration = 10000; // Длительность щита 10 секунд const shipWidth = ship.clientWidth; const shipHeight = ship.clientHeight; let touchStartX = 0; let bullets = []; let gameStarted = false; // Звуки const shotSound = new Audio('shot.mp3'); const reloadSound = new Audio('reload.mp3'); // Управление движением корабля gameContainer.addEventListener('touchstart', handleTouchStart); gameContainer.addEventListener('touchmove', handleTouchMove); document.addEventListener('keydown', moveShip); // Обработчик для начала касания function handleTouchStart(event) { if (!gameStarted) return; // Игнорировать до старта игры touchStartX = event.touches[0].clientX; createBullet(); } // Обработчик для перемещения пальца function handleTouchMove(event) { const touchCurrentX = event.touches[0].clientX; const deltaX = touchCurrentX - touchStartX; shipX = Math.max(0, Math.min(gameContainer.clientWidth - shipWidth, shipX + deltaX)); touchStartX = touchCurrentX; ship.style.left = `${shipX}px`; } // Управление с клавиатуры function moveShip(event) { if (!gameStarted) return; // Игнорировать до старта игры if (event.key === 'ArrowLeft' && shipX > 0) { shipX -= shipSpeed; } if (event.key === 'ArrowRight' && shipX < gameContainer.clientWidth - shipWidth) { shipX += shipSpeed; } ship.style.left = `${shipX}px`; } // Функция для создания пули function createBullet() { const bullet = document.createElement('div'); bullet.classList.add('bullet'); bullet.style.left = `${shipX + ship.offsetWidth / 2 - bullet.offsetWidth / 2}px`; bullet.style.top = `${gameContainer.clientHeight - 60}px`; gameContainer.appendChild(bullet); if (soundEnabled) shotSound.play(); moveBullet(bullet); } // Движение пули function moveBullet(bullet) { let bulletY = parseInt(bullet.style.top); const bulletInterval = setInterval(() => { bulletY -= bulletSpeed; bullet.style.top = `${bulletY}px`; if (bulletY <= 0) { clearInterval(bulletInterval); gameContainer.removeChild(bullet); } document.querySelectorAll('.meteor').forEach((meteor) => { const meteorX = parseInt(meteor.style.left); const meteorY = parseInt(meteor.style.top); if ( bulletY <= meteorY + 40 && bulletY >= meteorY && parseInt(bullet.style.left) >= meteorX && parseInt(bullet.style.left) <= meteorX + 40 ) { clearInterval(bulletInterval); gameContainer.removeChild(bullet); gameContainer.removeChild(meteor); score++; scoreElement.textContent = `Score: ${score}`; reloadSound.play(); } }); }, 20); } // Функция для создания метеоритов function createMeteor() { const meteor = document.createElement('div'); meteor.classList.add('meteor'); const meteorX = Math.random() * (gameContainer.clientWidth - 40); meteor.style.left = `${meteorX}px`; meteor.style.top = `-40px`; gameContainer.appendChild(meteor); moveMeteor(meteor); } // Движение метеорита function moveMeteor(meteor) { let meteorY = -40; const meteorInterval = setInterval(() => { meteorY += meteorSpeed; meteor.style.top = `${meteorY}px`; if (meteorY >= gameContainer.clientHeight) { clearInterval(meteorInterval); gameContainer.removeChild(meteor); } // Проверка на столкновение с кораблем if (checkCollision(ship, meteor)) { handleCollision(meteor); clearInterval(meteorInterval); gameContainer.removeChild(meteor); } }, 20); } // Функция проверки столкновения function checkCollision(ship, meteor) { const meteorRect = meteor.getBoundingClientRect(); const shipRect = ship.getBoundingClientRect(); return !( meteorRect.top > shipRect.bottom || meteorRect.bottom < shipRect.top || meteorRect.right < shipRect.left || meteorRect.left > shipRect.right ); } // Функция для обработки столкновения function handleCollision(meteor) { if (shieldActive) { // Если щит активен, игнорируем столкновение return; } // Уменьшаем счёт на 10% const scoreChange = Math.round(score * 0.1); score -= scoreChange; // Обновляем отображение счёта score = Math.max(score, 0); // Чтобы счёт не стал отрицательным scoreElement.textContent = `Score: ${score}`; // Добавляем анимацию на корабль ship.classList.add('shake'); setTimeout(() => { ship.classList.remove('shake'); }, 500); // Отображаем анимацию числа, которое исчезает showScoreChange(scoreChange, meteor); } // Анимация изменения счёта function showScoreChange(amount, meteor) { const scoreChange = document.createElement('div'); scoreChange.classList.add('score-change'); scoreChange.textContent = `${amount > 0 ? '-' : '+'}${amount}`; // Позиционируем анимацию рядом с метеоритом const meteorRect = meteor.getBoundingClientRect(); scoreChange.style.left = `${meteorRect.left + meteorRect.width / 2 - 20}px`; scoreChange.style.top = `${meteorRect.top}px`; gameContainer.appendChild(scoreChange); setTimeout(() => { scoreChange.remove(); }, 1000); } // Функция для отсчета перед началом игры function startCountdown() { const colors = ["red", "orange", "green"]; let counter = 3; countdownElement.textContent = counter; countdownElement.classList.add(colors[counter - 1]); const countdownInterval = setInterval(() => { counter--; countdownElement.textContent = counter; countdownElement.className = colors[counter - 1]; if (counter === 0) { clearInterval(countdownInterval); countdownElement.style.display = 'none'; startGame(); startTimer(); // Запуск таймера после отсчета } }, 1000); } // Запуск игры function startGame() { gameStarted = true; setInterval(createBullet, 500); setInterval(createMeteor, 1000); // Запланировать два падения щита в случайные моменты в течение 60 секунд const firstShieldTime = Math.random() * 60000; // время в мс до первого появления const secondShieldTime = Math.random() * 60000; // время в мс до второго появления setTimeout(createShield, firstShieldTime); setTimeout(createShield, secondShieldTime); } // Функция для создания щита function createShield() { const shieldX = Math.random() * (gameContainer.clientWidth - 40); shield.style.left = `${shieldX}px`; shield.style.top = `-40px`; shield.style.display = 'block'; moveShield(shield); } // Движение щита function moveShield(shield) { let shieldY = -40; const shieldInterval = setInterval(() => { shieldY += meteorSpeed; shield.style.top = `${shieldY}px`; if (shieldY >= gameContainer.clientHeight) { clearInterval(shieldInterval); shield.style.display = 'none'; } // Проверка на столкновение с пулей document.querySelectorAll('.bullet').forEach((bullet) => { const bulletX = parseInt(bullet.style.left); const bulletY = parseInt(bullet.style.top); if ( bulletY <= shieldY + 40 && bulletY >= shieldY && bulletX >= parseInt(shield.style.left) && bulletX <= parseInt(shield.style.left) + 40 ) { clearInterval(shieldInterval); shield.style.display = 'none'; activateShield(); } }); }, 20); } // Активация щита function activateShield() { shieldActive = true; shieldEffect.style.display = 'block'; shieldEffect.style.left = `${shipX - 30}px`; shieldEffect.style.top = `${gameContainer.clientHeight - 100}px`; // Деактивация щита через 10 секунд shieldTimeout = setTimeout(() => { shieldActive = false; shieldEffect.style.display = 'none'; }, shieldDuration); } // Переключение звука function toggleSound(isEnabled) { soundEnabled = isEnabled; soundOnButton.style.display = isEnabled ? 'none' : 'block'; soundOffButton.style.display = isEnabled ? 'block' : 'none'; if (isEnabled) { // Включаем звук shotSound.play(); } else { // Останавливаем звук, если звук выключен shotSound.pause(); shotSound.currentTime = 0; // Сбросить воспроизведение звука } } // Таймер на 1 минуту let countdownTime = 60; // Таймер на 1 минуту let countdownInterval; const timerElement = document.getElementById('timer'); // Функция для запуска таймера function startTimer() { countdownInterval = setInterval(function () { countdownTime--; let minutes = Math.floor(countdownTime / 60); let seconds = countdownTime % 60; timerElement.textContent = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`; if (countdownTime <= 0) { clearInterval(countdownInterval); // Останавливаем таймер endGame(); // Заканчиваем игру } }, 1000); // обновляем каждую секунду } let totalScore = localStorage.getItem('totalScore') || 0; // Получаем общую сумму очков из localStorage // Добавляем текущий результат к общим очкам totalScore += score; // Сохраняем общую сумму очков в localStorage localStorage.setItem('totalScore', totalScore); // Функция для завершения игры function endGame() { alert('Время вышло!'); // Оповещаем игрока stopGameSound(); // Останавливаем звуки игры window.location.href = "index.html"; // Возвращаем в главное меню } // Загрузка общих очков при загрузке страницы document.addEventListener("DOMContentLoaded", function() { const totalScoreElement = document.getElementById('total-score'); totalScoreElement.textContent = totalScore; // Показываем общие очки на странице }); // Функция для остановки звуков игры (включая shotSound и reloadSound) function stopGameSound() { if (soundEnabled) { shotSound.pause(); shotSound.currentTime = 0; // Сбрасываем время reloadSound.pause(); reloadSound.currentTime = 0; // Сбрасываем время } } // Запуск отсчета перед игрой startCountdown(); // Сохраняем score в localStorage let highScore = localStorage.getItem('highScore') || 0; if (score > highScore) { localStorage.setItem('highScore', score); }
Примечания:
#shield
и #shield-effect
для отображения щита и его эффекта.#shield-effect { width: 100px; height: 100px; border-radius: 50%; border: 2px solid cyan; box-shadow: 0 0 10px cyan, 0 0 20px cyan, 0 0 30px cyan; pointer-events: none; display: none; position: absolute; }
Таким образом, щит будет появляться дважды за игру в случайные моменты, активироваться при попадании пули и отображать неоновый эффект на корабле в течение 10 секунд.