| | <!DOCTYPE html> |
| | <html lang="en"> |
| |
|
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>Dino Runner Game</title> |
| | <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet"> |
| | <style> |
| | * { |
| | margin: 0; |
| | padding: 0; |
| | box-sizing: border-box; |
| | } |
| | |
| | body { |
| | min-height: 100vh; |
| | display: flex; |
| | flex-direction: column; |
| | align-items: center; |
| | background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); |
| | font-family: 'Press Start 2P', cursive; |
| | overflow: hidden; |
| | } |
| | |
| | header { |
| | width: 100%; |
| | padding: 1rem; |
| | text-align: center; |
| | background: rgba(255, 255, 255, 0.1); |
| | backdrop-filter: blur(10px); |
| | border-bottom: 2px solid rgba(255, 255, 255, 0.2); |
| | } |
| | |
| | header a { |
| | color: #00d4ff; |
| | text-decoration: none; |
| | font-size: 0.7rem; |
| | transition: all 0.3s ease; |
| | } |
| | |
| | header a:hover { |
| | color: #fff; |
| | text-shadow: 0 0 10px #00d4ff; |
| | } |
| | |
| | .game-container { |
| | display: flex; |
| | flex-direction: column; |
| | align-items: center; |
| | justify-content: center; |
| | flex: 1; |
| | padding: 2rem; |
| | width: 100%; |
| | max-width: 900px; |
| | } |
| | |
| | h1 { |
| | color: #fff; |
| | font-size: clamp(1rem, 4vw, 2rem); |
| | margin-bottom: 1rem; |
| | text-shadow: 0 0 20px rgba(0, 212, 255, 0.5); |
| | text-align: center; |
| | } |
| | |
| | .score-board { |
| | display: flex; |
| | gap: 2rem; |
| | margin-bottom: 1rem; |
| | flex-wrap: wrap; |
| | justify-content: center; |
| | } |
| | |
| | .score-item { |
| | color: #fff; |
| | font-size: clamp(0.6rem, 2vw, 0.9rem); |
| | padding: 0.5rem 1rem; |
| | background: rgba(255, 255, 255, 0.1); |
| | border-radius: 10px; |
| | border: 1px solid rgba(255, 255, 255, 0.2); |
| | } |
| | |
| | .score-item span { |
| | color: #00d4ff; |
| | } |
| | |
| | #gameCanvas { |
| | border: 4px solid #00d4ff; |
| | border-radius: 15px; |
| | box-shadow: 0 0 30px rgba(0, 212, 255, 0.3), |
| | inset 0 0 50px rgba(0, 0, 0, 0.5); |
| | background: linear-gradient(180deg, #87CEEB 0%, #E0F6FF 60%, #90EE90 60%, #228B22 100%); |
| | max-width: 100%; |
| | cursor: pointer; |
| | } |
| | |
| | .instructions { |
| | color: rgba(255, 255, 255, 0.7); |
| | font-size: clamp(0.5rem, 1.5vw, 0.7rem); |
| | margin-top: 1rem; |
| | text-align: center; |
| | line-height: 2; |
| | } |
| | |
| | .instructions kbd { |
| | background: rgba(255, 255, 255, 0.2); |
| | padding: 0.3rem 0.6rem; |
| | border-radius: 5px; |
| | border: 1px solid rgba(255, 255, 255, 0.3); |
| | } |
| | |
| | .game-over-overlay { |
| | position: fixed; |
| | top: 0; |
| | left: 0; |
| | width: 100%; |
| | height: 100%; |
| | background: rgba(0, 0, 0, 0.8); |
| | display: none; |
| | justify-content: center; |
| | align-items: center; |
| | z-index: 100; |
| | } |
| | |
| | .game-over-content { |
| | text-align: center; |
| | color: #fff; |
| | padding: 2rem; |
| | background: linear-gradient(135deg, #1a1a2e, #16213e); |
| | border-radius: 20px; |
| | border: 3px solid #00d4ff; |
| | box-shadow: 0 0 50px rgba(0, 212, 255, 0.5); |
| | } |
| | |
| | .game-over-content h2 { |
| | font-size: clamp(1.5rem, 5vw, 2.5rem); |
| | margin-bottom: 1rem; |
| | color: #ff4757; |
| | } |
| | |
| | .game-over-content p { |
| | font-size: clamp(0.7rem, 2vw, 1rem); |
| | margin-bottom: 1.5rem; |
| | } |
| | |
| | .restart-btn { |
| | font-family: 'Press Start 2P', cursive; |
| | font-size: clamp(0.6rem, 2vw, 0.9rem); |
| | padding: 1rem 2rem; |
| | background: linear-gradient(135deg, #00d4ff, #0099cc); |
| | color: #fff; |
| | border: none; |
| | border-radius: 10px; |
| | cursor: pointer; |
| | transition: all 0.3s ease; |
| | } |
| | |
| | .restart-btn:hover { |
| | transform: scale(1.05); |
| | box-shadow: 0 0 20px rgba(0, 212, 255, 0.5); |
| | } |
| | |
| | .start-screen { |
| | position: fixed; |
| | top: 0; |
| | left: 0; |
| | width: 100%; |
| | height: 100%; |
| | background: rgba(0, 0, 0, 0.9); |
| | display: flex; |
| | justify-content: center; |
| | align-items: center; |
| | z-index: 100; |
| | } |
| | |
| | .start-content { |
| | text-align: center; |
| | color: #fff; |
| | padding: 2rem; |
| | } |
| | |
| | .start-content h2 { |
| | font-size: clamp(1.5rem, 5vw, 3rem); |
| | margin-bottom: 2rem; |
| | color: #00d4ff; |
| | text-shadow: 0 0 30px rgba(0, 212, 255, 0.7); |
| | } |
| | |
| | .dino-art { |
| | font-size: clamp(3rem, 10vw, 6rem); |
| | margin-bottom: 2rem; |
| | animation: bounce 1s infinite; |
| | } |
| | |
| | @keyframes bounce { |
| | |
| | 0%, |
| | 100% { |
| | transform: translateY(0); |
| | } |
| | |
| | 50% { |
| | transform: translateY(-20px); |
| | } |
| | } |
| | |
| | .start-btn { |
| | font-family: 'Press Start 2P', cursive; |
| | font-size: clamp(0.8rem, 2.5vw, 1.2rem); |
| | padding: 1.5rem 3rem; |
| | background: linear-gradient(135deg, #00d4ff, #0099cc); |
| | color: #fff; |
| | border: none; |
| | border-radius: 15px; |
| | cursor: pointer; |
| | transition: all 0.3s ease; |
| | animation: pulse 2s infinite; |
| | } |
| | |
| | @keyframes pulse { |
| | |
| | 0%, |
| | 100% { |
| | box-shadow: 0 0 20px rgba(0, 212, 255, 0.5); |
| | } |
| | |
| | 50% { |
| | box-shadow: 0 0 40px rgba(0, 212, 255, 0.8); |
| | } |
| | } |
| | |
| | .start-btn:hover { |
| | transform: scale(1.1); |
| | } |
| | |
| | @media (max-width: 600px) { |
| | .game-container { |
| | padding: 1rem; |
| | } |
| | |
| | .score-board { |
| | gap: 1rem; |
| | } |
| | } |
| | </style> |
| | </head> |
| |
|
| | <body> |
| | <header> |
| | <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a> |
| | </header> |
| |
|
| | <div class="start-screen" id="startScreen"> |
| | <div class="start-content"> |
| | <h2>🦖 DINO RUNNER 🦖</h2> |
| | <div class="dino-art">🦕</div> |
| | <button class="start-btn" id="startBtn">START GAME</button> |
| | </div> |
| | </div> |
| |
|
| | <div class="game-container"> |
| | <h1>🦖 DINO RUNNER 🦖</h1> |
| |
|
| | <div class="score-board"> |
| | <div class="score-item">SCORE: <span id="score">0</span></div> |
| | <div class="score-item">HIGH SCORE: <span id="highScore">0</span></div> |
| | </div> |
| |
|
| | <canvas id="gameCanvas" width="800" height="300"></canvas> |
| |
|
| | <div class="instructions"> |
| | Press <kbd>SPACE</kbd> or <kbd>↑</kbd> to jump | <kbd>↓</kbd> to duck | <kbd>TAP</kbd> on mobile |
| | </div> |
| | </div> |
| |
|
| | <div class="game-over-overlay" id="gameOverOverlay"> |
| | <div class="game-over-content"> |
| | <h2>GAME OVER!</h2> |
| | <p>Your Score: <span id="finalScore">0</span></p> |
| | <button class="restart-btn" id="restartBtn">PLAY AGAIN</button> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | const canvas = document.getElementById('gameCanvas'); |
| | const ctx = canvas.getContext('2d'); |
| | const scoreElement = document.getElementById('score'); |
| | const highScoreElement = document.getElementById('highScore'); |
| | const finalScoreElement = document.getElementById('finalScore'); |
| | const gameOverOverlay = document.getElementById('gameOverOverlay'); |
| | const startScreen = document.getElementById('startScreen'); |
| | const startBtn = document.getElementById('startBtn'); |
| | const restartBtn = document.getElementById('restartBtn'); |
| | |
| | |
| | function resizeCanvas() { |
| | const maxWidth = Math.min(800, window.innerWidth - 40); |
| | const ratio = 300 / 800; |
| | canvas.style.width = maxWidth + 'px'; |
| | canvas.style.height = (maxWidth * ratio) + 'px'; |
| | } |
| | resizeCanvas(); |
| | window.addEventListener('resize', resizeCanvas); |
| | |
| | |
| | let gameRunning = false; |
| | let gameSpeed = 6; |
| | let score = 0; |
| | let highScore = localStorage.getItem('dinoHighScore') || 0; |
| | highScoreElement.textContent = highScore; |
| | |
| | |
| | const dino = { |
| | x: 50, |
| | y: 220, |
| | width: 50, |
| | height: 60, |
| | velocityY: 0, |
| | jumping: false, |
| | ducking: false, |
| | duckHeight: 35, |
| | normalHeight: 60, |
| | groundY: 220, |
| | frame: 0, |
| | frameCount: 0 |
| | }; |
| | |
| | |
| | let obstacles = []; |
| | let obstacleTimer = 0; |
| | const obstacleInterval = 100; |
| | |
| | |
| | let clouds = []; |
| | |
| | |
| | let groundX = 0; |
| | |
| | |
| | const gravity = 0.8; |
| | const jumpForce = -15; |
| | |
| | |
| | function initClouds() { |
| | clouds = []; |
| | for (let i = 0; i < 5; i++) { |
| | clouds.push({ |
| | x: Math.random() * canvas.width, |
| | y: 30 + Math.random() * 60, |
| | width: 60 + Math.random() * 40, |
| | speed: 1 + Math.random() |
| | }); |
| | } |
| | } |
| | |
| | |
| | function drawCloud(cloud) { |
| | ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; |
| | ctx.beginPath(); |
| | ctx.arc(cloud.x, cloud.y, 20, 0, Math.PI * 2); |
| | ctx.arc(cloud.x + 25, cloud.y - 10, 25, 0, Math.PI * 2); |
| | ctx.arc(cloud.x + 50, cloud.y, 20, 0, Math.PI * 2); |
| | ctx.arc(cloud.x + 25, cloud.y + 5, 22, 0, Math.PI * 2); |
| | ctx.fill(); |
| | } |
| | |
| | |
| | function drawDino() { |
| | const height = dino.ducking ? dino.duckHeight : dino.normalHeight; |
| | const y = dino.ducking ? dino.groundY + (dino.normalHeight - dino.duckHeight) : dino.y; |
| | |
| | |
| | ctx.fillStyle = '#2d5016'; |
| | ctx.beginPath(); |
| | ctx.roundRect(dino.x, y, dino.width - 10, height, 10); |
| | ctx.fill(); |
| | |
| | |
| | ctx.fillStyle = '#3d6b1e'; |
| | if (!dino.ducking) { |
| | ctx.beginPath(); |
| | ctx.roundRect(dino.x + 15, y - 25, 35, 30, 8); |
| | ctx.fill(); |
| | |
| | |
| | ctx.fillStyle = '#fff'; |
| | ctx.beginPath(); |
| | ctx.arc(dino.x + 40, y - 12, 6, 0, Math.PI * 2); |
| | ctx.fill(); |
| | ctx.fillStyle = '#000'; |
| | ctx.beginPath(); |
| | ctx.arc(dino.x + 42, y - 12, 3, 0, Math.PI * 2); |
| | ctx.fill(); |
| | |
| | |
| | ctx.strokeStyle = '#1a3d0c'; |
| | ctx.lineWidth = 2; |
| | ctx.beginPath(); |
| | ctx.moveTo(dino.x + 45, y - 5); |
| | ctx.lineTo(dino.x + 50, y - 5); |
| | ctx.stroke(); |
| | } else { |
| | |
| | ctx.beginPath(); |
| | ctx.roundRect(dino.x + 30, y - 5, 30, 20, 5); |
| | ctx.fill(); |
| | |
| | |
| | ctx.fillStyle = '#fff'; |
| | ctx.beginPath(); |
| | ctx.arc(dino.x + 50, y + 5, 4, 0, Math.PI * 2); |
| | ctx.fill(); |
| | ctx.fillStyle = '#000'; |
| | ctx.beginPath(); |
| | ctx.arc(dino.x + 51, y + 5, 2, 0, Math.PI * 2); |
| | ctx.fill(); |
| | } |
| | |
| | |
| | ctx.fillStyle = '#2d5016'; |
| | dino.frameCount++; |
| | if (dino.frameCount > 5) { |
| | dino.frame = (dino.frame + 1) % 2; |
| | dino.frameCount = 0; |
| | } |
| | |
| | if (!dino.jumping) { |
| | const legOffset = dino.frame === 0 ? 5 : -5; |
| | ctx.fillRect(dino.x + 8, y + height - 5, 8, 15 + legOffset); |
| | ctx.fillRect(dino.x + 25, y + height - 5, 8, 15 - legOffset); |
| | } else { |
| | ctx.fillRect(dino.x + 8, y + height - 5, 8, 12); |
| | ctx.fillRect(dino.x + 25, y + height - 5, 8, 12); |
| | } |
| | |
| | |
| | ctx.fillStyle = '#3d6b1e'; |
| | ctx.beginPath(); |
| | ctx.moveTo(dino.x, y + 20); |
| | ctx.lineTo(dino.x - 20, y + 15); |
| | ctx.lineTo(dino.x, y + 35); |
| | ctx.fill(); |
| | } |
| | |
| | |
| | function drawCactus(obstacle) { |
| | ctx.fillStyle = '#228B22'; |
| | |
| | |
| | ctx.beginPath(); |
| | ctx.roundRect(obstacle.x + 10, obstacle.y, 20, obstacle.height, 5); |
| | ctx.fill(); |
| | |
| | |
| | ctx.beginPath(); |
| | ctx.roundRect(obstacle.x, obstacle.y + 15, 12, 25, 4); |
| | ctx.fill(); |
| | ctx.beginPath(); |
| | ctx.roundRect(obstacle.x, obstacle.y + 10, 8, 15, 3); |
| | ctx.fill(); |
| | |
| | |
| | ctx.beginPath(); |
| | ctx.roundRect(obstacle.x + 28, obstacle.y + 25, 12, 20, 4); |
| | ctx.fill(); |
| | ctx.beginPath(); |
| | ctx.roundRect(obstacle.x + 32, obstacle.y + 20, 8, 12, 3); |
| | ctx.fill(); |
| | |
| | |
| | ctx.fillStyle = '#1a6b1a'; |
| | for (let i = 0; i < 5; i++) { |
| | ctx.beginPath(); |
| | ctx.arc(obstacle.x + 20, obstacle.y + i * 12, 2, 0, Math.PI * 2); |
| | ctx.fill(); |
| | } |
| | } |
| | |
| | |
| | function drawBird(obstacle) { |
| | ctx.fillStyle = '#8B4513'; |
| | |
| | |
| | ctx.beginPath(); |
| | ctx.ellipse(obstacle.x + 20, obstacle.y + 15, 20, 12, 0, 0, Math.PI * 2); |
| | ctx.fill(); |
| | |
| | |
| | ctx.beginPath(); |
| | ctx.arc(obstacle.x + 40, obstacle.y + 10, 10, 0, Math.PI * 2); |
| | ctx.fill(); |
| | |
| | |
| | ctx.fillStyle = '#FFA500'; |
| | ctx.beginPath(); |
| | ctx.moveTo(obstacle.x + 50, obstacle.y + 10); |
| | ctx.lineTo(obstacle.x + 60, obstacle.y + 12); |
| | ctx.lineTo(obstacle.x + 50, obstacle.y + 14); |
| | ctx.fill(); |
| | |
| | |
| | ctx.fillStyle = '#fff'; |
| | ctx.beginPath(); |
| | ctx.arc(obstacle.x + 43, obstacle.y + 8, 4, 0, Math.PI * 2); |
| | ctx.fill(); |
| | ctx.fillStyle = '#000'; |
| | ctx.beginPath(); |
| | ctx.arc(obstacle.x + 44, obstacle.y + 8, 2, 0, Math.PI * 2); |
| | ctx.fill(); |
| | |
| | |
| | ctx.fillStyle = '#6B3E26'; |
| | const wingY = Math.sin(Date.now() / 100) * 10; |
| | ctx.beginPath(); |
| | ctx.moveTo(obstacle.x + 10, obstacle.y + 15); |
| | ctx.lineTo(obstacle.x - 10, obstacle.y + wingY); |
| | ctx.lineTo(obstacle.x + 20, obstacle.y + 15); |
| | ctx.fill(); |
| | } |
| | |
| | |
| | function drawGround() { |
| | ctx.fillStyle = '#8B4513'; |
| | ctx.fillRect(0, 280, canvas.width, 20); |
| | |
| | ctx.fillStyle = '#654321'; |
| | groundX -= gameSpeed; |
| | if (groundX <= -20) groundX = 0; |
| | |
| | for (let i = groundX; i < canvas.width; i += 20) { |
| | ctx.fillRect(i, 282, 15, 3); |
| | ctx.fillRect(i + 7, 288, 10, 2); |
| | } |
| | |
| | |
| | ctx.fillStyle = '#228B22'; |
| | ctx.fillRect(0, 275, canvas.width, 5); |
| | } |
| | |
| | |
| | function spawnObstacle() { |
| | const type = Math.random() > 0.7 ? 'bird' : 'cactus'; |
| | const obstacle = { |
| | x: canvas.width, |
| | type: type, |
| | width: type === 'cactus' ? 40 : 60, |
| | height: type === 'cactus' ? 50 + Math.random() * 20 : 30 |
| | }; |
| | |
| | if (type === 'cactus') { |
| | obstacle.y = 280 - obstacle.height; |
| | } else { |
| | obstacle.y = Math.random() > 0.5 ? 180 : 230; |
| | } |
| | |
| | obstacles.push(obstacle); |
| | } |
| | |
| | |
| | function checkCollision() { |
| | const dinoHeight = dino.ducking ? dino.duckHeight : dino.normalHeight; |
| | const dinoY = dino.ducking ? dino.groundY + (dino.normalHeight - dino.duckHeight) : dino.y; |
| | |
| | for (let obstacle of obstacles) { |
| | if (dino.x + dino.width - 15 > obstacle.x && |
| | dino.x + 10 < obstacle.x + obstacle.width && |
| | dinoY + dinoHeight > obstacle.y && |
| | dinoY < obstacle.y + obstacle.height) { |
| | return true; |
| | } |
| | } |
| | return false; |
| | } |
| | |
| | |
| | function gameOver() { |
| | gameRunning = false; |
| | finalScoreElement.textContent = score; |
| | |
| | if (score > highScore) { |
| | highScore = score; |
| | localStorage.setItem('dinoHighScore', highScore); |
| | highScoreElement.textContent = highScore; |
| | } |
| | |
| | gameOverOverlay.style.display = 'flex'; |
| | } |
| | |
| | |
| | function resetGame() { |
| | score = 0; |
| | gameSpeed = 6; |
| | obstacles = []; |
| | obstacleTimer = 0; |
| | dino.y = dino.groundY; |
| | dino.velocityY = 0; |
| | dino.jumping = false; |
| | dino.ducking = false; |
| | initClouds(); |
| | gameOverOverlay.style.display = 'none'; |
| | gameRunning = true; |
| | gameLoop(); |
| | } |
| | |
| | |
| | function update() { |
| | |
| | if (dino.jumping) { |
| | dino.velocityY += gravity; |
| | dino.y += dino.velocityY; |
| | |
| | if (dino.y >= dino.groundY) { |
| | dino.y = dino.groundY; |
| | dino.jumping = false; |
| | dino.velocityY = 0; |
| | } |
| | } |
| | |
| | |
| | obstacleTimer++; |
| | if (obstacleTimer >= obstacleInterval - Math.min(score / 10, 50)) { |
| | spawnObstacle(); |
| | obstacleTimer = 0; |
| | } |
| | |
| | for (let i = obstacles.length - 1; i >= 0; i--) { |
| | obstacles[i].x -= gameSpeed; |
| | |
| | if (obstacles[i].x + obstacles[i].width < 0) { |
| | obstacles.splice(i, 1); |
| | score++; |
| | scoreElement.textContent = score; |
| | } |
| | } |
| | |
| | |
| | for (let cloud of clouds) { |
| | cloud.x -= cloud.speed; |
| | if (cloud.x + cloud.width < 0) { |
| | cloud.x = canvas.width + 50; |
| | cloud.y = 30 + Math.random() * 60; |
| | } |
| | } |
| | |
| | |
| | if (score > 0 && score % 10 === 0) { |
| | gameSpeed = 6 + Math.floor(score / 10) * 0.5; |
| | } |
| | |
| | |
| | if (checkCollision()) { |
| | gameOver(); |
| | } |
| | } |
| | |
| | |
| | function draw() { |
| | |
| | const gradient = ctx.createLinearGradient(0, 0, 0, 280); |
| | gradient.addColorStop(0, '#87CEEB'); |
| | gradient.addColorStop(0.6, '#E0F6FF'); |
| | gradient.addColorStop(0.6, '#90EE90'); |
| | gradient.addColorStop(1, '#228B22'); |
| | ctx.fillStyle = gradient; |
| | ctx.fillRect(0, 0, canvas.width, canvas.height); |
| | |
| | |
| | ctx.fillStyle = '#FFD700'; |
| | ctx.beginPath(); |
| | ctx.arc(700, 50, 30, 0, Math.PI * 2); |
| | ctx.fill(); |
| | ctx.fillStyle = 'rgba(255, 215, 0, 0.3)'; |
| | ctx.beginPath(); |
| | ctx.arc(700, 50, 45, 0, Math.PI * 2); |
| | ctx.fill(); |
| | |
| | |
| | for (let cloud of clouds) { |
| | drawCloud(cloud); |
| | } |
| | |
| | |
| | drawGround(); |
| | |
| | |
| | for (let obstacle of obstacles) { |
| | if (obstacle.type === 'cactus') { |
| | drawCactus(obstacle); |
| | } else { |
| | drawBird(obstacle); |
| | } |
| | } |
| | |
| | |
| | drawDino(); |
| | } |
| | |
| | |
| | function gameLoop() { |
| | if (!gameRunning) return; |
| | |
| | update(); |
| | draw(); |
| | requestAnimationFrame(gameLoop); |
| | } |
| | |
| | |
| | function jump() { |
| | if (!dino.jumping && !dino.ducking) { |
| | dino.jumping = true; |
| | dino.velocityY = jumpForce; |
| | } |
| | } |
| | |
| | function duck(isDucking) { |
| | if (!dino.jumping) { |
| | dino.ducking = isDucking; |
| | } |
| | } |
| | |
| | |
| | document.addEventListener('keydown', (e) => { |
| | if (!gameRunning) return; |
| | |
| | if (e.code === 'Space' || e.code === 'ArrowUp') { |
| | e.preventDefault(); |
| | jump(); |
| | } |
| | if (e.code === 'ArrowDown') { |
| | e.preventDefault(); |
| | duck(true); |
| | } |
| | }); |
| | |
| | document.addEventListener('keyup', (e) => { |
| | if (e.code === 'ArrowDown') { |
| | duck(false); |
| | } |
| | }); |
| | |
| | |
| | canvas.addEventListener('touchstart', (e) => { |
| | e.preventDefault(); |
| | if (gameRunning) { |
| | const touch = e.touches[0]; |
| | const rect = canvas.getBoundingClientRect(); |
| | const y = touch.clientY - rect.top; |
| | |
| | if (y > rect.height / 2) { |
| | duck(true); |
| | } else { |
| | jump(); |
| | } |
| | } |
| | }); |
| | |
| | canvas.addEventListener('touchend', (e) => { |
| | duck(false); |
| | }); |
| | |
| | canvas.addEventListener('click', () => { |
| | if (gameRunning) { |
| | jump(); |
| | } |
| | }); |
| | |
| | |
| | startBtn.addEventListener('click', () => { |
| | startScreen.style.display = 'none'; |
| | resetGame(); |
| | }); |
| | |
| | restartBtn.addEventListener('click', resetGame); |
| | |
| | |
| | initClouds(); |
| | draw(); |
| | </script> |
| | </body> |
| |
|
| | </html> |