Created
February 6, 2025 06:19
-
-
Save mojoaxel/d4e1c95220816fd3eb89cfd1906aca52 to your computer and use it in GitHub Desktop.
Flapp-Bird like game create by "Anthropic: Claude 3.5 Sonnet (2024-06-20) (self-moderated)" - CC-0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
<title>Emoji Flappy Ball</title> | |
<style> | |
* { margin: 0; padding: 0; box-sizing: border-box; } | |
html, body { width: 100%; height: 100%; overflow: hidden; } | |
body { font-family: Arial, sans-serif; background-color: #87CEEB; touch-action: manipulation; } | |
#game-container { width: 100%; height: 100%; position: relative; overflow: hidden; background-color: #4AA7FF; } | |
#ball { position: absolute; font-size: 30px; user-select: none; } | |
.pipe { position: absolute; width: 15%; background-color: #444444; } | |
#score { position: fixed; top: 10px; left: 50%; transform: translateX(-50%); font-size: 36px; font-weight: bold; color: white; z-index: 10; text-shadow: 2px 2px 4px rgba(0,0,0,0.5); } | |
#game-over, #start-prompt { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: white; z-index: 20; } | |
#game-over { display: none; background-color: rgba(0, 0, 0, 0.7); width: 100%; height: 100%; } | |
</style> | |
</head> | |
<body> | |
<div id="game-container"> | |
<div id="ball">🏐</div> | |
<div id="score">0</div> | |
<div id="game-over"> | |
<div>Game Over</div> | |
<div>Score: <span id="final-score"></span></div> | |
</div> | |
<div id="start-prompt">Click or tap to start<br>Double-click or double-tap to jump higher</div> | |
</div> | |
<script> | |
// DOM elements | |
const gameContainer = document.getElementById('game-container'); | |
const ball = document.getElementById('ball'); | |
const scoreElement = document.getElementById('score'); | |
const gameOverElement = document.getElementById('game-over'); | |
const finalScoreElement = document.getElementById('final-score'); | |
const startPrompt = document.getElementById('start-prompt'); | |
// Game variables | |
let ballY, ballVelocity, score, pipes, gameLoop, gameOver, gameStarted; | |
let containerWidth, containerHeight; | |
let gameSpeed = 1; | |
let pipeSpacing = 0.5; | |
// Constants | |
const JUMP_STRENGTH = 0.007; | |
const GRAVITY = 0.5; | |
const PIPE_WIDTH = 0.15; | |
const INITIAL_GAP = 0.35; | |
const MIN_GAP = 0.2; | |
const MIN_PIPE_SPACING = 0.3; | |
function initGame() { | |
// Reset game state | |
containerWidth = gameContainer.clientWidth; | |
containerHeight = gameContainer.clientHeight; | |
ballY = containerHeight / 2; | |
ballVelocity = 0; | |
score = 0; | |
pipes = []; | |
gameOver = false; | |
gameStarted = false; | |
gameSpeed = 1; | |
pipeSpacing = 0.5; | |
// Reset UI | |
scoreElement.textContent = score; | |
gameOverElement.style.display = 'none'; | |
startPrompt.style.display = 'block'; | |
document.querySelectorAll('.pipe').forEach(pipe => pipe.remove()); | |
// Position ball | |
ball.style.left = '10%'; | |
ball.style.top = ballY + 'px'; | |
// Start game loop | |
cancelAnimationFrame(gameLoop); | |
update(); | |
} | |
function update() { | |
if (gameOver) return; | |
if (gameStarted) { | |
// Update ball position | |
ballVelocity += GRAVITY * gameSpeed; | |
ballY += ballVelocity; | |
ball.style.top = ballY + 'px'; | |
// Check for collisions | |
if (ballY < 0 || ballY > containerHeight - 30) { | |
endGame(); | |
} | |
// Create new pipe if needed | |
if (pipes.length === 0 || pipes[pipes.length - 1].x < containerWidth * pipeSpacing) { | |
createPipe(); | |
} | |
// Update pipes | |
pipes.forEach(pipe => { | |
pipe.x -= containerWidth * 0.003 * gameSpeed; | |
pipe.topPipe.style.left = pipe.bottomPipe.style.left = pipe.x + 'px'; | |
if (pipe.x < -containerWidth * PIPE_WIDTH) { | |
gameContainer.removeChild(pipe.topPipe); | |
gameContainer.removeChild(pipe.bottomPipe); | |
pipes.shift(); | |
updateScore(); | |
} | |
if (checkCollision(pipe)) { | |
endGame(); | |
} | |
}); | |
} | |
gameLoop = requestAnimationFrame(update); | |
} | |
function createPipe() { | |
const gap = Math.max(containerHeight * (INITIAL_GAP - (score * 0.002)), containerHeight * MIN_GAP); | |
const topHeight = Math.random() * (containerHeight - gap - 100) + 50; | |
const bottomHeight = containerHeight - topHeight - gap; | |
const createPipeElement = (height, position) => { | |
const pipe = document.createElement('div'); | |
pipe.className = 'pipe'; | |
pipe.style[position] = '0'; | |
pipe.style.height = height + 'px'; | |
return pipe; | |
}; | |
const topPipe = createPipeElement(topHeight, 'top'); | |
const bottomPipe = createPipeElement(bottomHeight, 'bottom'); | |
gameContainer.appendChild(topPipe); | |
gameContainer.appendChild(bottomPipe); | |
pipes.push({ x: containerWidth, topPipe, bottomPipe }); | |
} | |
function checkCollision(pipe) { | |
const ballRect = ball.getBoundingClientRect(); | |
const topPipeRect = pipe.topPipe.getBoundingClientRect(); | |
const bottomPipeRect = pipe.bottomPipe.getBoundingClientRect(); | |
return ( | |
ballRect.right > topPipeRect.left && | |
ballRect.left < topPipeRect.right && | |
(ballRect.top < topPipeRect.bottom || ballRect.bottom > bottomPipeRect.top) | |
); | |
} | |
function updateScore() { | |
score++; | |
scoreElement.textContent = score; | |
// Increase difficulty | |
gameSpeed = 1 + (score / 25); // Linear increase, double speed at score 25 | |
pipeSpacing = Math.max(MIN_PIPE_SPACING, 0.5 - (score * 0.008)); // Decrease spacing, but not below minimum | |
} | |
function endGame() { | |
cancelAnimationFrame(gameLoop); | |
gameOver = true; | |
gameOverElement.style.display = 'flex'; | |
finalScoreElement.textContent = score; | |
setTimeout(initGame, 3000); | |
} | |
function jump(strength = 1) { | |
if (!gameStarted) { | |
gameStarted = true; | |
startPrompt.style.display = 'none'; | |
} | |
ballVelocity = -containerHeight * JUMP_STRENGTH * strength * gameSpeed; | |
} | |
// Event handling | |
let lastInteraction = 0; | |
function handleInteraction(e) { | |
e.preventDefault(); | |
if (gameOver) return; | |
const currentTime = new Date().getTime(); | |
const interactionLength = currentTime - lastInteraction; | |
jump(interactionLength < 300 && interactionLength > 0 ? 1.5 : 1); | |
lastInteraction = currentTime; | |
} | |
gameContainer.addEventListener('touchstart', handleInteraction); | |
gameContainer.addEventListener('mousedown', handleInteraction); | |
document.addEventListener('keydown', event => { | |
if (event.code === 'Space' && !gameOver) jump(); | |
}); | |
window.addEventListener('resize', initGame); | |
initGame(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment