Spaces:
Running
Running
<html lang="pt-BR"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Neon Pong Defender</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap'); | |
body { | |
font-family: 'Orbitron', sans-serif; | |
background-color: #0f0f1a; | |
overflow: hidden; | |
margin: 0; | |
padding: 0; | |
cursor: none; | |
} | |
.game-container { | |
position: relative; | |
width: 800px; | |
height: 600px; | |
margin: 20px auto; | |
border: 3px solid #4f46e5; | |
border-radius: 8px; | |
box-shadow: 0 0 20px #4f46e5, inset 0 0 20px rgba(79, 70, 229, 0.3); | |
overflow: hidden; | |
} | |
.ball { | |
position: absolute; | |
width: 20px; | |
height: 20px; | |
border-radius: 50%; | |
background: linear-gradient(145deg, #00ff9d, #00b8ff); | |
box-shadow: 0 0 10px #00ff9d, 0 0 20px #00b8ff; | |
transition: all 0.3s; | |
} | |
.paddle { | |
position: absolute; | |
width: 160px; | |
height: 15px; | |
bottom: 10px; | |
border-radius: 10px; | |
background: linear-gradient(145deg, #ff00aa, #ff0066); | |
box-shadow: 0 0 10px #ff00aa, 0 0 20px rgba(255, 0, 170, 0.5); | |
} | |
.score { | |
color: #00ff9d; | |
text-shadow: 0 0 5px #00ff9d; | |
font-size: 24px; | |
} | |
.timer { | |
color: #00b8ff; | |
text-shadow: 0 0 5px #00b8ff; | |
font-size: 24px; | |
} | |
.pulse { | |
animation: pulse 0.5s ease-out; | |
} | |
@keyframes pulse { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.3); } | |
100% { transform: scale(1); } | |
} | |
.explode { | |
animation: explode 0.5s ease-out; | |
} | |
@keyframes explode { | |
0% { transform: scale(1); opacity: 1; } | |
100% { transform: scale(3); opacity: 0; } | |
} | |
.grid-lines { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: | |
linear-gradient(to right, rgba(79, 70, 229, 0.1) 1px, transparent 1px), | |
linear-gradient(to bottom, rgba(79, 70, 229, 0.1) 1px, transparent 1px); | |
background-size: 20px 20px; | |
pointer-events: none; | |
} | |
.game-over { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-color: rgba(15, 15, 26, 0.8); | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
z-index: 100; | |
color: #ff0066; | |
font-size: 48px; | |
text-shadow: 0 0 10px #ff0066; | |
display: none; | |
} | |
.restart-btn { | |
margin-top: 20px; | |
padding: 10px 30px; | |
background: linear-gradient(145deg, #4f46e5, #7c3aed); | |
border: none; | |
border-radius: 5px; | |
color: white; | |
font-family: 'Orbitron', sans-serif; | |
font-size: 20px; | |
cursor: pointer; | |
box-shadow: 0 0 10px #4f46e5; | |
transition: all 0.3s; | |
} | |
.restart-btn:hover { | |
transform: scale(1.05); | |
box-shadow: 0 0 20px #4f46e5; | |
} | |
.speed-indicator { | |
position: absolute; | |
top: 10px; | |
right: 10px; | |
color: #00b8ff; | |
font-size: 16px; | |
text-shadow: 0 0 5px #00b8ff; | |
} | |
.particle { | |
position: absolute; | |
width: 5px; | |
height: 5px; | |
border-radius: 50%; | |
background-color: #00ff9d; | |
pointer-events: none; | |
} | |
.custom-cursor { | |
position: absolute; | |
width: 20px; | |
height: 20px; | |
border-radius: 50%; | |
background-color: rgba(255, 255, 255, 0.5); | |
pointer-events: none; | |
z-index: 1000; | |
mix-blend-mode: difference; | |
display: none; | |
} | |
.controls-info { | |
position: absolute; | |
bottom: 40px; | |
left: 10px; | |
color: #4f46e5; | |
font-size: 12px; | |
text-shadow: 0 0 5px #4f46e5; | |
} | |
.instructions { | |
position: absolute; | |
top: 40px; | |
left: 10px; | |
color: #4f46e5; | |
font-size: 12px; | |
text-shadow: 0 0 5px #4f46e5; | |
background-color: rgba(15, 15, 26, 0.7); | |
padding: 10px; | |
border-radius: 5px; | |
max-width: 200px; | |
} | |
</style> | |
</head> | |
<body class="flex flex-col items-center justify-center min-h-screen"> | |
<h1 class="text-4xl font-bold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-purple-500 to-pink-500">NEON PONG DEFENDER</h1> | |
<div class="flex justify-between w-96 mb-4"> | |
<div class="score">PONTOS: <span id="player-score">0</span></div> | |
<div class="timer">TEMPO: <span id="game-timer">00:00</span></div> | |
</div> | |
<div class="game-container" id="game-container"> | |
<div class="grid-lines"></div> | |
<div class="speed-indicator">VELOCIDADE: <span id="speed-level">1x</span></div> | |
<div class="ball" id="ball"></div> | |
<div class="paddle" id="paddle"></div> | |
<div class="game-over" id="game-over"> | |
FIM DE JOGO | |
<button class="restart-btn" id="restart-btn">JOGAR NOVAMENTE</button> | |
</div> | |
<div class="controls-info">CONTROLES: Teclas de seta ou mouse</div> | |
<div class="instructions"> | |
<p><strong>COMO JOGAR:</strong></p> | |
<p>- Use as teclas ← → ou o mouse para mover a raquete</p> | |
<p>- Impedir que a bola caia</p> | |
<p>- Cada rebatida marca 1 ponto</p> | |
<p>- A velocidade aumenta a cada minuto</p> | |
</div> | |
</div> | |
<div class="mt-4 text-purple-400 text-center"> | |
<p>Defenda a bola com sua raquete e marque o máximo de pontos!</p> | |
<p class="text-sm text-purple-600">O jogo fica mais rápido a cada minuto!</p> | |
</div> | |
<div class="custom-cursor" id="custom-cursor"></div> | |
<script> | |
document.addEventListener('DOMContentLoaded', () => { | |
const gameContainer = document.getElementById('game-container'); | |
const ball = document.getElementById('ball'); | |
const paddle = document.getElementById('paddle'); | |
const playerScoreElement = document.getElementById('player-score'); | |
const gameTimerElement = document.getElementById('game-timer'); | |
const gameOverScreen = document.getElementById('game-over'); | |
const restartBtn = document.getElementById('restart-btn'); | |
const speedLevelElement = document.getElementById('speed-level'); | |
const customCursor = document.getElementById('custom-cursor'); | |
const containerWidth = gameContainer.offsetWidth; | |
const containerHeight = gameContainer.offsetHeight; | |
const paddleWidth = containerWidth / 5; | |
let ballX = containerWidth / 2; | |
let ballY = 50; | |
let ballSpeedX = 3; | |
let ballSpeedY = 3; | |
let paddleX = (containerWidth - paddleWidth) / 2; | |
let playerScore = 0; | |
let gameTime = 0; | |
let gameSpeed = 1; | |
let gameRunning = true; | |
let animationId; | |
let mouseX = 0; | |
let useMouse = false; | |
// Cores aleatórias para a bola | |
const ballColors = [ | |
{gradient: 'linear-gradient(145deg, #00ff9d, #00b8ff)', shadow1: '#00ff9d', shadow2: '#00b8ff'}, | |
{gradient: 'linear-gradient(145deg, #ff9d00, #ff00b8)', shadow1: '#ff9d00', shadow2: '#ff00b8'}, | |
{gradient: 'linear-gradient(145deg, #9d00ff, #00b8ff)', shadow1: '#9d00ff', shadow2: '#00b8ff'}, | |
{gradient: 'linear-gradient(145deg, #ff0066, #ffcc00)', shadow1: '#ff0066', shadow2: '#ffcc00'}, | |
{gradient: 'linear-gradient(145deg, #00ff66, #6600ff)', shadow1: '#00ff66', shadow2: '#6600ff'} | |
]; | |
// Set initial paddle size | |
paddle.style.width = `${paddleWidth}px`; | |
// Mouse movement tracking | |
gameContainer.addEventListener('mousemove', (e) => { | |
const rect = gameContainer.getBoundingClientRect(); | |
mouseX = e.clientX - rect.left - paddleWidth / 2; | |
useMouse = true; | |
// Update custom cursor position | |
customCursor.style.display = 'block'; | |
customCursor.style.left = `${e.clientX - 10}px`; | |
customCursor.style.top = `${e.clientY - 10}px`; | |
}); | |
gameContainer.addEventListener('mouseleave', () => { | |
useMouse = false; | |
customCursor.style.display = 'none'; | |
}); | |
// Keyboard controls | |
const keys = { | |
ArrowLeft: false, | |
ArrowRight: false | |
}; | |
document.addEventListener('keydown', (e) => { | |
if (e.key in keys) { | |
keys[e.key] = true; | |
useMouse = false; | |
customCursor.style.display = 'none'; | |
} | |
}); | |
document.addEventListener('keyup', (e) => { | |
if (e.key in keys) { | |
keys[e.key] = false; | |
} | |
}); | |
restartBtn.addEventListener('click', resetGame); | |
function updatePaddlePosition() { | |
if (useMouse) { | |
// Mouse control | |
paddleX = Math.max(0, Math.min(mouseX, containerWidth - paddleWidth)); | |
} else { | |
// Keyboard control | |
if (keys.ArrowLeft && paddleX > 0) { | |
paddleX -= 8 * gameSpeed; | |
} | |
if (keys.ArrowRight && paddleX < containerWidth - paddleWidth) { | |
paddleX += 8 * gameSpeed; | |
} | |
} | |
paddle.style.left = `${paddleX}px`; | |
} | |
function updateBallPosition() { | |
ballX += ballSpeedX * gameSpeed; | |
ballY += ballSpeedY * gameSpeed; | |
// Ball collision with walls | |
if (ballX <= 0) { | |
ballX = 0; | |
ballSpeedX = -ballSpeedX; | |
createParticles(ballX, ballY, 5); | |
} | |
if (ballX >= containerWidth - 20) { | |
ballX = containerWidth - 20; | |
ballSpeedX = -ballSpeedX; | |
createParticles(ballX, ballY, 5); | |
} | |
// Ball collision with ceiling | |
if (ballY <= 0) { | |
ballY = 0; | |
ballSpeedY = -ballSpeedY; | |
createParticles(ballX, ballY, 5); | |
} | |
// Ball collision with paddle | |
if ( | |
ballY >= containerHeight - 35 && | |
ballY <= containerHeight - 20 && | |
ballX >= paddleX && | |
ballX <= paddleX + paddleWidth | |
) { | |
ballSpeedY = -ballSpeedY; | |
// Add some randomness to the bounce | |
const hitPosition = (ballX - paddleX) / paddleWidth; | |
ballSpeedX = (hitPosition - 0.5) * 8; | |
playerScore++; | |
playerScoreElement.textContent = playerScore; | |
// Paddle hit effect | |
paddle.classList.add('pulse'); | |
setTimeout(() => paddle.classList.remove('pulse'), 500); | |
// Explode current ball and create new one | |
ball.classList.add('explode'); | |
createParticles(ballX, ballY, 20, '#ff00aa'); | |
// Create new ball with random color | |
setTimeout(() => { | |
ball.classList.remove('explode'); | |
const randomColor = ballColors[Math.floor(Math.random() * ballColors.length)]; | |
ball.style.background = randomColor.gradient; | |
ball.style.boxShadow = `0 0 10px ${randomColor.shadow1}, 0 0 20px ${randomColor.shadow2}`; | |
ballX = containerWidth / 2; | |
ballY = 50; | |
ballSpeedX = (Math.random() > 0.5 ? 3 : -3) * gameSpeed; | |
ballSpeedY = 3 * gameSpeed; | |
}, 500); | |
} | |
// Ball out of bounds (game over) | |
if (ballY >= containerHeight) { | |
gameOver(); | |
// Explosion effect | |
ball.classList.add('explode'); | |
createParticles(ballX, ballY, 20, '#ff0066'); | |
} | |
ball.style.left = `${ballX}px`; | |
ball.style.top = `${ballY}px`; | |
} | |
function createParticles(x, y, count, color = '#00ff9d') { | |
for (let i = 0; i < count; i++) { | |
const particle = document.createElement('div'); | |
particle.className = 'particle'; | |
particle.style.left = `${x}px`; | |
particle.style.top = `${y}px`; | |
particle.style.backgroundColor = color; | |
gameContainer.appendChild(particle); | |
const angle = Math.random() * Math.PI * 2; | |
const speed = 1 + Math.random() * 3; | |
const lifetime = 500 + Math.random() * 500; | |
const particleSpeedX = Math.cos(angle) * speed; | |
const particleSpeedY = Math.sin(angle) * speed; | |
let particleX = x; | |
let particleY = y; | |
const animateParticle = () => { | |
particleX += particleSpeedX; | |
particleY += particleSpeedY; | |
particle.style.opacity = parseFloat(particle.style.opacity || 1) - 0.01; | |
particle.style.left = `${particleX}px`; | |
particle.style.top = `${particleY}px`; | |
if (parseFloat(particle.style.opacity || 1) > 0) { | |
requestAnimationFrame(animateParticle); | |
} else { | |
particle.remove(); | |
} | |
}; | |
setTimeout(() => { | |
animateParticle(); | |
}, 10); | |
setTimeout(() => { | |
particle.remove(); | |
}, lifetime); | |
} | |
} | |
function updateTimer() { | |
gameTime++; | |
const minutes = Math.floor(gameTime / 60).toString().padStart(2, '0'); | |
const seconds = (gameTime % 60).toString().padStart(2, '0'); | |
gameTimerElement.textContent = `${minutes}:${seconds}`; | |
// Increase game speed every minute | |
if (gameTime % 60 === 0) { | |
gameSpeed += 0.25; | |
speedLevelElement.textContent = `${gameSpeed.toFixed(2)}x`; | |
// Speed increase effect | |
gameContainer.style.boxShadow = `0 0 30px #4f46e5, inset 0 0 30px rgba(79, 70, 229, 0.5)`; | |
setTimeout(() => { | |
gameContainer.style.boxShadow = `0 0 20px #4f46e5, inset 0 0 20px rgba(79, 70, 229, 0.3)`; | |
}, 500); | |
} | |
} | |
function gameOver() { | |
gameRunning = false; | |
gameOverScreen.style.display = 'flex'; | |
cancelAnimationFrame(animationId); | |
} | |
function resetGame() { | |
ballX = containerWidth / 2; | |
ballY = 50; | |
ballSpeedX = 3; | |
ballSpeedY = 3; | |
paddleX = (containerWidth - paddleWidth) / 2; | |
playerScore = 0; | |
gameTime = 0; | |
gameSpeed = 1; | |
// Reset ball color | |
ball.style.background = 'linear-gradient(145deg, #00ff9d, #00b8ff)'; | |
ball.style.boxShadow = '0 0 10px #00ff9d, 0 0 20px #00b8ff'; | |
playerScoreElement.textContent = '0'; | |
gameTimerElement.textContent = '00:00'; | |
speedLevelElement.textContent = '1x'; | |
ball.classList.remove('explode'); | |
gameOverScreen.style.display = 'none'; | |
gameRunning = true; | |
// Remove all particles | |
document.querySelectorAll('.particle').forEach(p => p.remove()); | |
gameLoop(); | |
} | |
function gameLoop() { | |
if (!gameRunning) return; | |
updatePaddlePosition(); | |
updateBallPosition(); | |
animationId = requestAnimationFrame(gameLoop); | |
} | |
// Start the game | |
resetGame(); | |
// Start timer | |
setInterval(() => { | |
if (gameRunning) { | |
updateTimer(); | |
} | |
}, 1000); | |
}); | |
</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=gallabs/neon-pong-defender" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |