Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>TAP IT OR DIE!</title> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
font-family: 'Press Start 2P', cursive; | |
background-color: #121212; | |
color: #00ff00; | |
text-align: center; | |
overflow: hidden; | |
height: 100vh; | |
-webkit-tap-highlight-color: transparent; | |
} | |
#game-container { | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
height: 100vh; | |
position: relative; | |
padding: 20px; | |
} | |
#start-screen { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: rgba(0, 0, 0, 0.9); | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
z-index: 100; | |
gap: 30px; | |
text-shadow: 0 0 10px #00ff00; | |
} | |
#game-title { | |
font-size: 3rem; | |
margin-bottom: 20px; | |
color: #ff0; | |
text-shadow: 0 0 10px #ff0, 0 0 20px #ff0; | |
animation: pulse 1.5s infinite alternate; | |
} | |
#game-over-screen { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: rgba(0, 0, 0, 0.9); | |
display: none; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
z-index: 100; | |
gap: 30px; | |
} | |
#game-over-content { | |
position: relative; | |
z-index: 101; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
gap: 30px; | |
} | |
button { | |
background: #00ff00; | |
color: #000; | |
border: none; | |
padding: 15px 30px; | |
font-family: 'Press Start 2P', cursive; | |
font-size: 1.2rem; | |
cursor: pointer; | |
border-radius: 5px; | |
transition: all 0.3s; | |
box-shadow: 0 0 10px #00ff00; | |
position: relative; | |
z-index: 101; | |
} | |
button:hover { | |
background: #ff0; | |
transform: scale(1.05); | |
box-shadow: 0 0 20px #ff0; | |
} | |
.game-info { | |
display: flex; | |
justify-content: space-between; | |
width: 100%; | |
max-width: 600px; | |
margin-bottom: 20px; | |
font-size: 1rem; | |
position: relative; | |
z-index: 10; | |
} | |
#game-board { | |
width: 100%; | |
max-width: 600px; | |
height: 400px; | |
border: 8px solid #333; | |
position: relative; | |
background-color: #000; | |
overflow: hidden; | |
box-shadow: inset 0 0 20px #000, 0 0 30px #00ff00; | |
} | |
.explosion { | |
position: absolute; | |
width: 60px; | |
height: 60px; | |
background-image: radial-gradient(circle, #ff0, #f80, #f00); | |
border-radius: 50%; | |
pointer-events: none; | |
transform: scale(0); | |
animation: explode 0.5s forwards; | |
z-index: 10; | |
} | |
.bomb { | |
position: absolute; | |
width: 40px; | |
height: 40px; | |
background-color: #333; | |
border-radius: 50%; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
cursor: pointer; | |
transition: transform 0.2s; | |
box-shadow: inset 0 0 10px #111, 0 0 10px #f00; | |
animation: bomb-pulse 1s infinite alternate; | |
z-index: 5; | |
} | |
.bomb::before { | |
content: ""; | |
position: absolute; | |
width: 10px; | |
height: 10px; | |
background-color: #f00; | |
border-radius: 50%; | |
box-shadow: 0 0 10px #f00; | |
} | |
.bomb:hover { | |
transform: scale(1.1); | |
} | |
.bomb.ready { | |
background-color: #f00; | |
animation: danger-pulse 0.5s infinite alternate; | |
} | |
.bomb.ready::before { | |
background-color: #ff0; | |
} | |
.bomb-bonus { | |
background-color: #0af; | |
box-shadow: inset 0 0 10px #111, 0 0 10px #0af; | |
} | |
.bomb-bonus::before { | |
background-color: #fff; | |
} | |
#countdown { | |
font-size: 2rem; | |
margin: 20px 0; | |
text-shadow: 0 0 10px #00ff00; | |
position: relative; | |
z-index: 10; | |
} | |
#difficulty-selector { | |
margin: 20px 0; | |
display: flex; | |
gap: 10px; | |
position: relative; | |
z-index: 10; | |
flex-wrap: wrap; | |
justify-content: center; | |
} | |
#difficulty-selector button { | |
font-size: 0.8rem; | |
padding: 10px 15px; | |
} | |
#difficulty-selector button.active { | |
background: #ff0; | |
box-shadow: 0 0 15px #ff0; | |
} | |
#game-over-difficulty { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
gap: 15px; | |
margin-top: 20px; | |
} | |
#game-over-difficulty h3 { | |
color: #ff0; | |
margin-bottom: 10px; | |
font-size: 1rem; | |
} | |
.scanlines { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: linear-gradient( | |
rgba(18, 16, 16, 0) 50%, | |
rgba(0, 0, 0, 0.25) 50% | |
); | |
background-size: 100% 4px; | |
pointer-events: none; | |
z-index: 5; | |
} | |
@keyframes pulse { | |
0% { transform: scale(1); } | |
100% { transform: scale(1.05); } | |
} | |
@keyframes bomb-pulse { | |
0% { box-shadow: inset 0 0 10px #111, 0 0 5px #f00; } | |
100% { box-shadow: inset 0 0 10px #111, 0 0 15px #f00; } | |
} | |
@keyframes danger-pulse { | |
0% { box-shadow: inset 0 0 10px #111, 0 0 5px #f00; transform: scale(1); } | |
100% { box-shadow: inset 0 0 10px #111, 0 0 20px #f00; transform: scale(1.1); } | |
} | |
@keyframes explode { | |
0% { transform: scale(0); opacity: 1; } | |
100% { transform: scale(4); opacity: 0; } | |
} | |
.leaderboard { | |
position: absolute; | |
right: 20px; | |
top: 20px; | |
background: rgba(0, 0, 0, 0.8); | |
border: 2px solid #00ff00; | |
padding: 10px; | |
max-height: 200px; | |
overflow-y: auto; | |
display: none; | |
z-index: 10; | |
} | |
.leaderboard h3 { | |
margin-bottom: 10px; | |
color: #ff0; | |
} | |
.leaderboard-entry { | |
display: flex; | |
justify-content: space-between; | |
margin-bottom: 5px; | |
font-size: 0.8rem; | |
} | |
.danger { | |
animation: danger-flash 0.2s infinite; | |
} | |
@keyframes danger-flash { | |
0%, 100% { background-color: #121212; } | |
50% { background-color: #330000; } | |
} | |
.game-over-explosion { | |
position: absolute; | |
width: 120px; | |
height: 120px; | |
background-image: radial-gradient(circle, #ff0, #f80, #f00); | |
border-radius: 50%; | |
pointer-events: none; | |
transform: scale(0); | |
animation: final-explode 1s forwards; | |
z-index: 100; | |
} | |
@keyframes final-explode { | |
0% { transform: scale(0); opacity: 1; } | |
100% { transform: scale(10); opacity: 0; } | |
} | |
.shake { | |
animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; | |
} | |
@keyframes shake { | |
10%, 90% { transform: translate3d(-1px, 0, 0); } | |
20%, 80% { transform: translate3d(2px, 0, 0); } | |
30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } | |
40%, 60% { transform: translate3d(4px, 0, 0); } | |
} | |
@media (max-width: 600px) { | |
#game-title { | |
font-size: 1.8rem; | |
} | |
button { | |
padding: 10px 20px; | |
font-size: 0.9rem; | |
} | |
.game-info { | |
font-size: 0.7rem; | |
} | |
#game-board { | |
height: 300px; | |
} | |
.bomb { | |
width: 30px; | |
height: 30px; | |
} | |
.leaderboard { | |
position: static; | |
margin-top: 20px; | |
width: 100%; | |
max-height: 100px; | |
} | |
#difficulty-selector button { | |
font-size: 0.7rem; | |
padding: 8px 12px; | |
} | |
#game-over-content { | |
gap: 20px; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div id="game-container"> | |
<div id="start-screen"> | |
<h1 id="game-title">TAP IT OR DIE!</h1> | |
<p>Defuse the bombs before they explode!</p> | |
<p id="high-score-display">HIGH SCORE: 0</p> | |
<div id="difficulty-selector"> | |
<button class="active" data-difficulty="easy">EASY</button> | |
<button data-difficulty="medium">MEDIUM</button> | |
<button data-difficulty="hard">HARD</button> | |
<button data-difficulty="insane">INSANE</button> | |
</div> | |
<button id="start-button"> | |
<i class="fas fa-bomb"></i> START GAME <i class="fas fa-bomb"></i> | |
</button> | |
</div> | |
<div id="game-over-screen"> | |
<div id="game-over-content"> | |
<h1>GAME OVER!</h1> | |
<p>BOOM! You got exploded.</p> | |
<p id="final-score">SCORE: 0</p> | |
<div id="game-over-difficulty"> | |
<h3>SELECT DIFFICULTY</h3> | |
<div id="difficulty-selector-game-over"> | |
<button class="active" data-difficulty="easy">EASY</button> | |
<button data-difficulty="medium">MEDIUM</button> | |
<button data-difficulty="hard">HARD</button> | |
<button data-difficulty="insane">INSANE</button> | |
</div> | |
</div> | |
<button id="restart-button">TRY AGAIN</button> | |
</div> | |
</div> | |
<div class="game-info"> | |
<div>SCORE: <span id="score">0</span></div> | |
<div>LIVES: <span id="lives">3</span></div> | |
</div> | |
<div id="countdown">GET READY!</div> | |
<div id="game-board"> | |
<div class="scanlines"></div> | |
</div> | |
<div class="leaderboard"> | |
<h3>TOP SCORES</h3> | |
<div id="leaderboard-entries"></div> | |
</div> | |
</div> | |
<script> | |
// Game variables | |
let score = 0; | |
let lives = 3; | |
let gameActive = false; | |
let gameTimer; | |
let bombCount = 0; | |
let difficulty = 'medium'; | |
let highScore = localStorage.getItem('highScore') || 0; | |
let leaderboard = JSON.parse(localStorage.getItem('leaderboard')) || []; | |
// DOM elements | |
const gameContainer = document.getElementById('game-container'); | |
const gameBoard = document.getElementById('game-board'); | |
const scoreDisplay = document.getElementById('score'); | |
const livesDisplay = document.getElementById('lives'); | |
const startScreen = document.getElementById('start-screen'); | |
const gameOverScreen = document.getElementById('game-over-screen'); | |
const gameOverContent = document.getElementById('game-over-content'); | |
const startButton = document.getElementById('start-button'); | |
const restartButton = document.getElementById('restart-button'); | |
const difficultyButtons = document.querySelectorAll('[data-difficulty]'); | |
const difficultyButtonsGameOver = document.querySelectorAll('#difficulty-selector-game-over [data-difficulty]'); | |
const countdownDisplay = document.getElementById('countdown'); | |
const highScoreDisplay = document.getElementById('high-score-display'); | |
const finalScoreDisplay = document.getElementById('final-score'); | |
const leaderboardElement = document.querySelector('.leaderboard'); | |
const leaderboardEntries = document.getElementById('leaderboard-entries'); | |
// Initialize game | |
window.onload = function() { | |
updateHighScoreDisplay(); | |
updateLeaderboardDisplay(); | |
// Event listeners | |
startButton.addEventListener('click', startGame); | |
restartButton.addEventListener('click', restartGame); | |
// Main difficulty selector | |
difficultyButtons.forEach(button => { | |
button.addEventListener('click', function() { | |
setDifficulty(this.dataset.difficulty); | |
difficultyButtons.forEach(btn => btn.classList.remove('active')); | |
this.classList.add('active'); | |
}); | |
}); | |
// Game over screen difficulty selector | |
difficultyButtonsGameOver.forEach(button => { | |
button.addEventListener('click', function() { | |
setDifficulty(this.dataset.difficulty); | |
difficultyButtonsGameOver.forEach(btn => btn.classList.remove('active')); | |
this.classList.add('active'); | |
}); | |
}); | |
// Show leaderboard on hover of high score | |
highScoreDisplay.addEventListener('mouseenter', () => { | |
leaderboardElement.style.display = 'block'; | |
}); | |
highScoreDisplay.addEventListener('mouseleave', () => { | |
leaderboardElement.style.display = 'none'; | |
}); | |
}; | |
function setDifficulty(newDifficulty) { | |
difficulty = newDifficulty; | |
// Update both selectors to show current difficulty | |
difficultyButtons.forEach(btn => { | |
btn.classList.remove('active'); | |
if(btn.dataset.difficulty === difficulty) btn.classList.add('active'); | |
}); | |
difficultyButtonsGameOver.forEach(btn => { | |
btn.classList.remove('active'); | |
if(btn.dataset.difficulty === difficulty) btn.classList.add('active'); | |
}); | |
} | |
function startGame() { | |
startScreen.style.display = 'none'; | |
gameActive = true; | |
score = 0; | |
lives = 3; | |
bombCount = 0; | |
// Reset UI | |
scoreDisplay.textContent = score; | |
livesDisplay.textContent = lives; | |
document.body.classList.remove('danger'); | |
gameOverScreen.style.display = 'none'; | |
// Clear any existing bombs | |
gameBoard.querySelectorAll('.bomb').forEach(bomb => bomb.remove()); | |
// Start countdown | |
let countdown = 3; | |
countdownDisplay.style.display = 'block'; | |
const countdownInterval = setInterval(() => { | |
countdownDisplay.textContent = countdown > 0 ? countdown : 'GO!'; | |
if (countdown <= 0) { | |
clearInterval(countdownInterval); | |
countdownDisplay.style.display = 'none'; | |
startBombTimer(); | |
} | |
countdown--; | |
}, 1000); | |
} | |
function startBombTimer() { | |
// Set bomb spawn interval based on difficulty | |
let spawnInterval; | |
let bombLifeTime; | |
switch(difficulty) { | |
case 'easy': | |
spawnInterval = 1500; | |
bombLifeTime = 4000; | |
break; | |
case 'medium': | |
spawnInterval = 1000; | |
bombLifeTime = 3000; | |
break; | |
case 'hard': | |
spawnInterval = 650; | |
bombLifeTime = 2000; | |
break; | |
case 'insane': | |
spawnInterval = 400; | |
bombLifeTime = 1500; | |
break; | |
} | |
gameTimer = setInterval(() => { | |
if (!gameActive) return; | |
createBomb(bombLifeTime); | |
bombCount++; | |
// Increase difficulty over time | |
if (bombCount % 10 === 0 && spawnInterval > 300) { | |
spawnInterval -= 100; | |
bombLifeTime = Math.max(bombLifeTime - 200, 1000); | |
clearInterval(gameTimer); | |
gameTimer = setInterval(arguments.callee, spawnInterval); | |
} | |
}, spawnInterval); | |
} | |
function createBomb(lifetime) { | |
const bomb = document.createElement('div'); | |
bomb.className = 'bomb'; | |
// 5% chance for a bonus bomb | |
if (Math.random() < 0.05) { | |
bomb.classList.add('bomb-bonus'); | |
} | |
// Size variation | |
const size = 30 + Math.floor(Math.random() * 30); | |
bomb.style.width = `${size}px`; | |
bomb.style.height = `${size}px`; | |
// Position randomly on the game board | |
const maxX = gameBoard.offsetWidth - size; | |
const maxY = gameBoard.offsetHeight - size; | |
const x = Math.floor(Math.random() * maxX); | |
const y = Math.floor(Math.random() * maxY); | |
bomb.style.left = `${x}px`; | |
bomb.style.top = `${y}px`; | |
// Add click event to defuse the bomb | |
bomb.addEventListener('click', function() { | |
defuseBomb(this); | |
}); | |
gameBoard.appendChild(bomb); | |
// Bomb becomes ready after short delay | |
setTimeout(() => { | |
bomb.classList.add('ready'); | |
}, Math.random() * 1000); | |
// Bomb explodes after lifetime | |
const explodeTimer = setTimeout(() => { | |
if (bomb.parentNode === gameBoard) { | |
explodeBomb(bomb); | |
} | |
}, lifetime); | |
// Store timer on bomb for cleanup | |
bomb.dataset.timer = explodeTimer; | |
} | |
function defuseBomb(bomb) { | |
if (!bomb.classList.contains('ready')) return; | |
clearTimeout(bomb.dataset.timer); | |
// Check if it's a bonus bomb | |
const isBonus = bomb.classList.contains('bomb-bonus'); | |
// Calculate points based on how quickly it was tapped | |
let points = isBonus ? 50 : 10; | |
// Add extra points for quick defuse | |
if (isBonus) { | |
points += Math.floor(Math.random() * 50); | |
} else { | |
points += Math.floor(Math.random() * 20); | |
} | |
score += points; | |
scoreDisplay.textContent = score; | |
createExplosion(bomb, isBonus ? '#0af' : '#00ff00'); | |
bomb.remove(); | |
} | |
function explodeBomb(bomb) { | |
if (!gameActive) return; | |
lives--; | |
livesDisplay.textContent = lives; | |
// Visual feedback when low on lives | |
if (lives === 1) { | |
document.body.classList.add('danger'); | |
} | |
// Screen shake effect | |
gameContainer.classList.add('shake'); | |
setTimeout(() => { | |
gameContainer.classList.remove('shake'); | |
}, 500); | |
createExplosion(bomb, '#ff0000'); | |
bomb.remove(); | |
if (lives <= 0) { | |
endGame(); | |
} | |
} | |
function createExplosion(element, color) { | |
const rect = element.getBoundingClientRect(); | |
const gameRect = gameBoard.getBoundingClientRect(); | |
const x = rect.left - gameRect.left + rect.width / 2; | |
const y = rect.top - gameRect.top + rect.height / 2; | |
const explosion = document.createElement('div'); | |
explosion.className = 'explosion'; | |
explosion.style.left = `${x - 30}px`; | |
explosion.style.top = `${y - 30}px`; | |
explosion.style.background = color; | |
gameBoard.appendChild(explosion); | |
// Remove explosion after animation | |
setTimeout(() => { | |
explosion.remove(); | |
}, 500); | |
} | |
function createFinalExplosion() { | |
const gameRect = gameBoard.getBoundingClientRect(); | |
const x = gameRect.width / 2; | |
const y = gameRect.height / 2; | |
const explosion = document.createElement('div'); | |
explosion.className = 'game-over-explosion'; | |
explosion.style.left = `${x - 60}px`; | |
explosion.style.top = `${y - 60}px`; | |
gameBoard.appendChild(explosion); | |
// Remove explosion after animation | |
setTimeout(() => { | |
explosion.remove(); | |
}, 1000); | |
} | |
function endGame() { | |
gameActive = false; | |
clearInterval(gameTimer); | |
// Clear all bombs | |
gameBoard.querySelectorAll('.bomb').forEach(bomb => { | |
clearTimeout(bomb.dataset.timer); | |
bomb.remove(); | |
}); | |
// Big final explosion | |
createFinalExplosion(); | |
// Update high score if needed | |
if (score > highScore) { | |
highScore = score; | |
localStorage.setItem('highScore', highScore); | |
updateHighScoreDisplay(); | |
} | |
// Update leaderboard | |
updateLeaderboard(score); | |
// Show game over screen after explosion | |
setTimeout(() => { | |
finalScoreDisplay.textContent = `SCORE: ${score}`; | |
gameOverScreen.style.display = 'flex'; | |
document.body.classList.remove('danger'); | |
}, 1000); | |
} | |
function restartGame() { | |
gameOverScreen.style.display = 'none'; | |
gameBoard.innerHTML = '<div class="scanlines"></div>'; | |
startGame(); | |
} | |
function updateHighScoreDisplay() { | |
highScoreDisplay.textContent = `HIGH SCORE: ${highScore}`; | |
} | |
function updateLeaderboard(newScore) { | |
// Add new score to leaderboard | |
leaderboard.push(newScore); | |
// Sort in descending order and keep top 5 | |
leaderboard.sort((a, b) => b - a); | |
leaderboard = leaderboard.slice(0, 5); | |
// Save to localStorage | |
localStorage.setItem('leaderboard', JSON.stringify(leaderboard)); | |
updateLeaderboardDisplay(); | |
} | |
function updateLeaderboardDisplay() { | |
leaderboardEntries.innerHTML = ''; | |
leaderboard.forEach((score, index) => { | |
const entry = document.createElement('div'); | |
entry.className = 'leaderboard-entry'; | |
entry.innerHTML = `<span>${index + 1}.</span> <span>${score}</span>`; | |
leaderboardEntries.appendChild(entry); | |
}); | |
} | |
</script> | |
</body> | |
</html> |