| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>T-Rex Runner Game</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| @keyframes run { |
| 0% { background-position: 0px; } |
| 100% { background-position: -176px; } |
| } |
| |
| @keyframes jump { |
| 0% { transform: translateY(0); } |
| 50% { transform: translateY(-70px); } |
| 100% { transform: translateY(0); } |
| } |
| |
| @keyframes duck { |
| 0% { height: 60px; } |
| 100% { height: 30px; } |
| } |
| |
| @keyframes moveGround { |
| to { background-position: -800px 0; } |
| } |
| |
| @keyframes moveCloud { |
| to { transform: translateX(-100vw); } |
| } |
| |
| .dino-running { |
| animation: run 0.5s steps(2) infinite; |
| } |
| |
| .dino-jumping { |
| animation: jump 800ms ease-out; |
| } |
| |
| .dino-ducking { |
| animation: duck 0.2s forwards; |
| } |
| |
| .ground-moving { |
| animation: moveGround 1.5s linear infinite; |
| } |
| |
| .cloud-moving { |
| animation: moveCloud 20s linear infinite; |
| } |
| |
| .pulse { |
| animation: pulse 1.5s infinite; |
| } |
| |
| @keyframes pulse { |
| 0% { transform: scale(1); opacity: 1; } |
| 50% { transform: scale(1.05); opacity: 0.8; } |
| 100% { transform: scale(1); opacity: 1; } |
| } |
| |
| .game-container { |
| touch-action: manipulation; |
| } |
| |
| .obstacle { |
| animation: obstacleMove linear forwards; |
| } |
| |
| @keyframes obstacleMove { |
| to { left: -100px; } |
| } |
| |
| .night-mode { |
| background: linear-gradient(to bottom, #0c1445, #1a237e); |
| } |
| |
| .day-mode { |
| background: linear-gradient(to bottom, #87CEEB, #E0F7FA); |
| } |
| |
| .night-ground { |
| background-color: #2c3e50; |
| } |
| |
| .day-ground { |
| background-color: #8B4513; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-900 flex flex-col items-center justify-center min-h-screen p-4"> |
| <div class="max-w-4xl w-full"> |
| <h1 class="text-4xl md:text-5xl font-bold text-center text-yellow-400 mb-2"> |
| <i class="fas fa-dinosaur mr-2"></i>T-Rex Runner |
| </h1> |
| |
| <div class="flex flex-wrap justify-center gap-4 mb-6"> |
| <div class="bg-gray-800 rounded-lg p-4 text-center"> |
| <p class="text-white font-semibold">High Score</p> |
| <p id="highScore" class="text-2xl text-yellow-400 font-bold">0</p> |
| </div> |
| |
| <div class="bg-gray-800 rounded-lg p-4 text-center"> |
| <p class="text-white font-semibold">Current Score</p> |
| <p id="currentScore" class="text-2xl text-green-400 font-bold">0</p> |
| </div> |
| |
| <div class="bg-gray-800 rounded-lg p-4 text-center"> |
| <p class="text-white font-semibold">Speed</p> |
| <p id="speedDisplay" class="text-2xl text-blue-400 font-bold">1.0x</p> |
| </div> |
|
|
| <div class="bg-gray-800 rounded-lg p-4 text-center"> |
| <p class="text-white font-semibold">Health</p> |
| <div id="healthDisplay" class="flex justify-center gap-1"> |
| <i class="fas fa-heart text-red-500 text-2xl"></i> |
| <i class="fas fa-heart text-red-500 text-2xl"></i> |
| <i class="fas fa-heart text-red-500 text-2xl"></i> |
| </div> |
| </div> |
| </div> |
| |
| <div class="relative overflow-hidden rounded-xl shadow-2xl mb-6 game-container" style="height: 300px;"> |
| <div id="gameBackground" class="absolute inset-0 day-mode"></div> |
| |
| |
| <div class="absolute top-10 left-full cloud-moving" style="animation-duration: 15s;"> |
| <i class="fas fa-cloud text-white text-3xl"></i> |
| </div> |
| <div class="absolute top-20 left-full cloud-moving" style="animation-duration: 20s; animation-delay: 3s;"> |
| <i class="fas fa-cloud text-white text-4xl"></i> |
| </div> |
| <div class="absolute top-40 left-full cloud-moving" style="animation-duration: 25s; animation-delay: 7s;"> |
| <i class="fas fa-cloud text-white text-2xl"></i> |
| </div> |
| |
| |
| <div id="ground" class="absolute bottom-0 w-full h-20 day-ground"></div> |
| |
| |
| <div id="dino" class="absolute bottom-20 left-20 w-16 h-16 bg-green-600 rounded-lg flex items-end justify-center"> |
| <div class="w-4 h-4 bg-green-800 rounded-full mb-1"></div> |
| <div class="absolute bottom-0 w-8 h-4 bg-green-700"></div> |
| <div class="absolute bottom-0 left-0 w-4 h-4 bg-green-800 rounded-b-lg"></div> |
| <div class="absolute bottom-0 right-0 w-4 h-4 bg-green-800 rounded-b-lg"></div> |
| </div> |
| |
| |
| <div id="obstacles"></div> |
| |
| |
| <div id="startMessage" class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-50 text-white"> |
| <h2 class="text-3xl font-bold mb-4">T-Rex Runner</h2> |
| <p class="text-xl mb-6">Press SPACE or tap to start</p> |
| <div class="flex gap-4"> |
| <div class="flex flex-col items-center"> |
| <div class="w-8 h-8 bg-gray-200 rounded mb-2"></div> |
| <span>Space/Up Arrow</span> |
| <span class="text-sm">Jump</span> |
| </div> |
| <div class="flex flex-col items-center"> |
| <div class="w-8 h-4 bg-gray-200 rounded mb-2"></div> |
| <span>Down Arrow</span> |
| <span class="text-sm">Duck</span> |
| </div> |
| </div> |
| </div> |
| |
| <div id="gameOver" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-70 text-white"> |
| <h2 class="text-4xl font-bold mb-4 text-red-500">GAME OVER!</h2> |
| <p class="text-2xl mb-2">Score: <span id="finalScore">0</span></p> |
| <p class="text-xl mb-6">Press SPACE to restart</p> |
| </div> |
| </div> |
| |
| <div class="flex flex-wrap justify-center gap-4 mb-8"> |
| <div class="bg-gray-800 p-4 rounded-lg"> |
| <h3 class="text-white font-bold mb-2">Controls:</h3> |
| <div class="flex gap-4"> |
| <div class="flex items-center"> |
| <kbd class="px-2 py-1 bg-gray-700 text-white rounded">Space</kbd> |
| <span class="ml-2 text-white">Jump</span> |
| </div> |
| <div class="flex items-center"> |
| <kbd class="px-2 py-1 bg-gray-700 text-white rounded">↓</kbd> |
| <span class="ml-2 text-white">Duck</span> |
| </div> |
| <div class="flex items-center"> |
| <kbd class="px-2 py-1 bg-gray-700 text-white rounded">R</kbd> |
| <span class="ml-2 text-white">Restart</span> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-gray-800 p-4 rounded-lg"> |
| <h3 class="text-white font-bold mb-2">Achievements:</h3> |
| <div class="flex gap-2"> |
| <div class="bg-yellow-600 rounded-full w-8 h-8 flex items-center justify-center"> |
| <i class="fas fa-medal text-white"></i> |
| </div> |
| <div class="bg-gray-700 rounded-full w-8 h-8 flex items-center justify-center"> |
| <i class="fas fa-star text-gray-500"></i> |
| </div> |
| <div class="bg-gray-700 rounded-full w-8 h-8 flex items-center justify-center"> |
| <i class="fas fa-bolt text-gray-500"></i> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div class="text-center text-gray-400"> |
| <p>Survive as long as possible by jumping over cacti and ducking under birds!</p> |
| <p class="mt-2">The game gets progressively harder over time.</p> |
| </div> |
| </div> |
|
|
| <script> |
| |
| const dino = document.getElementById('dino'); |
| const obstaclesContainer = document.getElementById('obstacles'); |
| const ground = document.getElementById('ground'); |
| const gameBackground = document.getElementById('gameBackground'); |
| const startMessage = document.getElementById('startMessage'); |
| const gameOver = document.getElementById('gameOver'); |
| const currentScoreEl = document.getElementById('currentScore'); |
| const highScoreEl = document.getElementById('highScore'); |
| const finalScoreEl = document.getElementById('finalScore'); |
| const speedDisplay = document.getElementById('speedDisplay'); |
| |
| |
| let gameStarted = false; |
| let gameOverState = false; |
| let isDucking = false; |
| let score = 0; |
| let highScore = localStorage.getItem('trexHighScore') || 0; |
| let gameSpeed = 1; |
| let dayMode = true; |
| let gameInterval; |
| let obstacleInterval; |
| let health = 3; |
| let invincible = false; |
| |
| |
| function initGame() { |
| highScoreEl.textContent = highScore; |
| |
| |
| ground.classList.add('ground-moving'); |
| |
| |
| document.addEventListener('keydown', handleKeyDown); |
| document.addEventListener('touchstart', handleTouch); |
| document.addEventListener('mousedown', handleTouch); |
| |
| |
| startMessage.addEventListener('click', startGame); |
| } |
| |
| |
| function handleKeyDown(e) { |
| if (e.code === 'Space' || e.key === ' ' || e.key === 'ArrowUp') { |
| if (!gameStarted || gameOverState) { |
| resetGame(); |
| startGame(); |
| } else if (!isJumping && !isDucking) { |
| jump(); |
| } |
| } else if (e.key === 'ArrowDown' && gameStarted && !gameOverState && !isJumping) { |
| duck(); |
| } else if (e.key === 'r' || e.key === 'R') { |
| resetGame(); |
| } |
| } |
| |
| |
| function handleTouch(e) { |
| if (!gameStarted || gameOverState) { |
| resetGame(); |
| startGame(); |
| } else if (!isDucking) { |
| jump(); |
| } |
| } |
| |
| |
| function startGame() { |
| if (gameStarted) return; |
| |
| gameStarted = true; |
| startMessage.style.display = 'none'; |
| resetGame(); |
| |
| |
| gameInterval = setInterval(updateGame, 16); |
| |
| |
| obstacleInterval = setInterval(generateObstacle, 800); |
| |
| |
| setInterval(toggleDayNight, 30000); |
| } |
| |
| |
| function resetGame() { |
| gameOverState = false; |
| isJumping = false; |
| isDucking = false; |
| score = 0; |
| gameSpeed = 1; |
| dayMode = true; |
| health = 3; |
| updateHealthDisplay(); |
| updateBackground(); |
| |
| |
| obstaclesContainer.innerHTML = ''; |
| |
| |
| dino.style.bottom = '80px'; |
| dino.style.height = '60px'; |
| dino.classList.remove('dino-jumping', 'dino-ducking'); |
| dino.classList.add('dino-running'); |
| |
| |
| gameOver.style.display = 'none'; |
| |
| |
| currentScoreEl.textContent = '0'; |
| speedDisplay.textContent = '1.0x'; |
| } |
| |
| |
| function updateGame() { |
| if (gameOverState) return; |
| |
| |
| score += 0.1 * gameSpeed; |
| currentScoreEl.textContent = Math.floor(score); |
| |
| |
| if (score > 50 && score % 100 === 0) { |
| gameSpeed = 1 + Math.floor((score - 50) / 100) * 0.2; |
| speedDisplay.textContent = gameSpeed.toFixed(1) + 'x'; |
| |
| |
| document.querySelectorAll('.obstacle').forEach(obstacle => { |
| obstacle.style.animationDuration = (2000 / gameSpeed) + 'ms'; |
| }); |
| } |
| |
| |
| checkCollisions(); |
| } |
| |
| |
| function generateObstacle() { |
| if (!gameStarted || gameOverState) return; |
| |
| const obstacle = document.createElement('div'); |
| obstacle.classList.add('obstacle', 'absolute', 'bottom-20'); |
| obstacle.style.left = '100%'; |
| obstacle.style.animation = `obstacleMove ${2000 / gameSpeed}ms linear forwards`; |
| |
| |
| const obstacleType = Math.random(); |
| |
| if (obstacleType < 0.4) { |
| |
| const cactusHeight = Math.random() > 0.5 ? 40 : 60; |
| obstacle.innerHTML = '<div class="w-6 h-12 bg-green-700 relative"><div class="absolute w-4 h-4 bg-green-800 top-2 -left-2"></div><div class="absolute w-4 h-4 bg-green-800 top-6 -right-2"></div></div>'; |
| obstacle.style.height = `${cactusHeight}px`; |
| obstacle.style.bottom = '20px'; |
| } else if (obstacleType < 0.7) { |
| |
| obstacle.innerHTML = '<div class="flex gap-2"><div class="w-6 h-12 bg-green-700 relative"><div class="absolute w-4 h-4 bg-green-800 top-2 -left-2"></div></div><div class="w-6 h-16 bg-green-700 relative"><div class="absolute w-4 h-4 bg-green-800 top-6 -right-2"></div></div></div>'; |
| obstacle.style.bottom = '20px'; |
| } else if (obstacleType < 0.9 && score > 30) { |
| |
| obstacle.innerHTML = '<i class="fas fa-dove text-blue-300 text-2xl"></i>'; |
| obstacle.style.bottom = Math.random() > 0.5 ? '100px' : '70px'; |
| } else if (score > 50) { |
| |
| obstacle.innerHTML = '<i class="fas fa-dragon text-purple-400 text-3xl"></i>'; |
| obstacle.style.bottom = '90px'; |
| } |
| |
| obstaclesContainer.appendChild(obstacle); |
| |
| |
| if (Math.random() > 0.7) { |
| setTimeout(() => { |
| if (!gameOverState) { |
| const secondObstacle = obstacle.cloneNode(true); |
| obstaclesContainer.appendChild(secondObstacle); |
| |
| setTimeout(() => { |
| if (secondObstacle.parentNode) { |
| secondObstacle.remove(); |
| } |
| }, 2000 / gameSpeed); |
| } |
| }, 300); |
| } |
| |
| |
| setTimeout(() => { |
| if (obstacle.parentNode) { |
| obstacle.remove(); |
| } |
| }, 2000 / gameSpeed); |
| } |
| |
| |
| function jump() { |
| dino.classList.remove('dino-running'); |
| dino.classList.add('dino-jumping'); |
| |
| |
| playSound('jump'); |
| |
| setTimeout(() => { |
| dino.classList.remove('dino-jumping'); |
| dino.classList.add('dino-running'); |
| }, 800); |
| } |
| |
| |
| function duck() { |
| if (isDucking) return; |
| |
| isDucking = true; |
| dino.classList.remove('dino-running'); |
| dino.classList.add('dino-ducking'); |
| |
| setTimeout(() => { |
| dino.classList.remove('dino-ducking'); |
| dino.classList.add('dino-running'); |
| isDucking = false; |
| }, 1000); |
| } |
| |
| |
| function checkCollisions() { |
| const dinoRect = dino.getBoundingClientRect(); |
| const dinoBottom = dinoRect.bottom; |
| const dinoTop = dinoRect.top; |
| const dinoLeft = dinoRect.left; |
| const dinoRight = dinoRect.right; |
| |
| document.querySelectorAll('.obstacle').forEach(obstacle => { |
| const obstacleRect = obstacle.getBoundingClientRect(); |
| |
| |
| if ( |
| !invincible && |
| dinoRight > obstacleRect.left && |
| dinoLeft < obstacleRect.right && |
| dinoBottom > obstacleRect.top && |
| dinoTop < obstacleRect.bottom |
| ) { |
| takeDamage(); |
| } |
| }); |
| } |
| |
| |
| function takeDamage() { |
| health--; |
| updateHealthDisplay(); |
| |
| |
| playSound('collision'); |
| |
| |
| invincible = true; |
| let blinkCount = 0; |
| const blinkInterval = setInterval(() => { |
| dino.style.opacity = dino.style.opacity === '0.5' ? '1' : '0.5'; |
| blinkCount++; |
| if (blinkCount >= 6) { |
| clearInterval(blinkInterval); |
| dino.style.opacity = '1'; |
| invincible = false; |
| } |
| }, 200); |
| |
| if (health <= 0) { |
| endGame(); |
| } |
| } |
| |
| |
| function updateHealthDisplay() { |
| const healthDisplay = document.getElementById('healthDisplay'); |
| healthDisplay.innerHTML = ''; |
| for (let i = 0; i < 3; i++) { |
| const heart = document.createElement('i'); |
| heart.className = 'fas fa-heart text-2xl'; |
| heart.style.color = i < health ? 'red' : 'gray'; |
| healthDisplay.appendChild(heart); |
| } |
| } |
| |
| |
| function endGame() { |
| gameOverState = true; |
| clearInterval(gameInterval); |
| clearInterval(obstacleInterval); |
| |
| |
| if (score > highScore) { |
| highScore = Math.floor(score); |
| localStorage.setItem('trexHighScore', highScore); |
| highScoreEl.textContent = highScore; |
| } |
| |
| |
| finalScoreEl.textContent = Math.floor(score); |
| gameOver.style.display = 'flex'; |
| |
| } |
| |
| |
| function toggleDayNight() { |
| if (!gameStarted || gameOverState) return; |
| |
| dayMode = !dayMode; |
| updateBackground(); |
| } |
| |
| |
| function updateBackground() { |
| if (dayMode) { |
| gameBackground.classList.remove('night-mode'); |
| gameBackground.classList.add('day-mode'); |
| ground.classList.remove('night-ground'); |
| ground.classList.add('day-ground'); |
| } else { |
| gameBackground.classList.remove('day-mode'); |
| gameBackground.classList.add('night-mode'); |
| ground.classList.remove('day-ground'); |
| ground.classList.add('night-ground'); |
| } |
| } |
| |
| |
| function playSound(type) { |
| |
| console.log(`Playing ${type} sound`); |
| } |
| |
| |
| window.addEventListener('load', initGame); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=caio246/dino" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |