royam0820-pong-game / index.html
royam0820's picture
Add 1 files
b2ea39f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CyberPong</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700&display=swap');
body {
font-family: 'Orbitron', sans-serif;
overflow: hidden;
background-color: #000;
color: #00ff41;
}
.game-container {
position: relative;
}
.particle {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
pointer-events: none;
}
.glow {
text-shadow: 0 0 10px #00ff41, 0 0 20px #00ff41;
}
.paddle-glow {
box-shadow: 0 0 15px #00ff41;
}
.ball-glow {
box-shadow: 0 0 20px #ff00ff, 0 0 30px #ff00ff;
}
@keyframes flicker {
0%, 19%, 21%, 23%, 25%, 54%, 56%, 100% {
opacity: 1;
}
20%, 22%, 24%, 55% {
opacity: 0.2;
}
}
.flicker {
animation: flicker 3s infinite;
}
.score-digit {
display: inline-block;
text-align: center;
width: 40px;
}
</style>
</head>
<body class="h-screen flex flex-col items-center justify-center relative">
<div class="absolute top-4 left-4 flex items-center">
<div class="w-4 h-4 bg-green-500 rounded-full mr-2 animate-pulse"></div>
<span class="text-green-500">SYSTEM: ONLINE</span>
</div>
<h1 class="text-5xl mb-6 glow flicker font-bold tracking-wider">CYBERPONG</h1>
<div class="flex justify-between w-full max-w-4xl mb-4 px-10">
<div class="text-3xl glow">
PLAYER <span class="score-digit" id="playerScore">0</span>
</div>
<div class="text-3xl glow">
CPU <span class="score-digit" id="cpuScore">0</span>
</div>
</div>
<div class="game-container border-2 border-green-500 relative w-full max-w-4xl h-96 bg-black">
<div id="paddlePlayer" class="w-4 h-20 bg-green-500 rounded-md absolute left-4 top-1/2 transform -translate-y-1/2 paddle-glow"></div>
<div id="paddleCPU" class="w-4 h-20 bg-purple-500 rounded-md absolute right-4 top-1/2 transform -translate-y-1/2 paddle-glow"></div>
<div id="ball" class="w-5 h-5 bg-white rounded-full absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 ball-glow"></div>
<div class="absolute top-0 left-0 w-full h-full grid grid-cols-15 grid-rows-8 pointer-events-none">
<div class="border-r border-b border-gray-800 opacity-20"></div>
<!-- Grid pattern repeated -->
</div>
</div>
<div class="mt-6 text-green-500 flex gap-8">
<div class="flex items-center">
<i class="fas fa-gamepad mr-2"></i>
<span>W/S or ↑/↓ to move</span>
</div>
<div class="flex items-center">
<i class="fas fa-bolt mr-2"></i>
<span>SPACE to launch</span>
</div>
</div>
<div id="gameOver" class="absolute inset-0 bg-black bg-opacity-80 hidden flex-col items-center justify-center glow">
<h2 class="text-5xl mb-6">GAME OVER</h2>
<div class="text-2xl mb-8" id="winnerText"></div>
<button id="restartBtn" class="px-6 py-3 bg-green-500 text-black font-bold rounded hover:bg-green-400 transition">
SYSTEM REBOOT (Play Again)
</button>
</div>
<script>
// Game elements
const gameContainer = document.querySelector('.game-container');
const paddlePlayer = document.getElementById('paddlePlayer');
const paddleCPU = document.getElementById('paddleCPU');
const ball = document.getElementById('ball');
const playerScoreElement = document.getElementById('playerScore');
const cpuScoreElement = document.getElementById('cpuScore');
const gameOverScreen = document.getElementById('gameOver');
const winnerText = document.getElementById('winnerText');
const restartBtn = document.getElementById('restartBtn');
// Game state
let ballX = 400;
let ballY = 200;
let ballSpeedX = 0;
let ballSpeedY = 0;
let playerY = 160;
let cpuY = 160;
let playerScore = 0;
let cpuScore = 0;
let gameRunning = false;
let gameStarted = false;
// Game constants
const PADDLE_HEIGHT = 80;
const PADDLE_WIDTH = 16;
const BALL_SIZE = 10;
const GAME_WIDTH = gameContainer.clientWidth;
const GAME_HEIGHT = gameContainer.clientHeight;
const PADDLE_SPEED = 8;
const INITIAL_BALL_SPEED = 5;
// Initialize game
function init() {
ballX = GAME_WIDTH / 2;
ballY = GAME_HEIGHT / 2;
ballSpeedX = 0;
ballSpeedY = 0;
playerY = (GAME_HEIGHT - PADDLE_HEIGHT) / 2;
cpuY = (GAME_HEIGHT - PADDLE_HEIGHT) / 2;
gameRunning = false;
gameStarted = false;
updatePositions();
}
// Update element positions
function updatePositions() {
// Ensure paddles stay within bounds
playerY = Math.max(0, Math.min(GAME_HEIGHT - PADDLE_HEIGHT, playerY));
cpuY = Math.max(0, Math.min(GAME_HEIGHT - PADDLE_HEIGHT, cpuY));
paddlePlayer.style.top = `${playerY}px`;
paddleCPU.style.top = `${cpuY}px`;
ball.style.left = `${ballX - BALL_SIZE/2}px`;
ball.style.top = `${ballY - BALL_SIZE/2}px`;
}
// Start the game
function startGame() {
if (!gameStarted) {
gameStarted = true;
ballSpeedX = Math.random() > 0.5 ? INITIAL_BALL_SPEED : -INITIAL_BALL_SPEED;
ballSpeedY = (Math.random() * 4 - 2);
gameRunning = true;
}
}
// Game loop
function gameLoop() {
if (!gameRunning) return;
// Move ball
ballX += ballSpeedX;
ballY += ballSpeedY;
// Ball collision with top and bottom
if (ballY <= 0 || ballY >= GAME_HEIGHT) {
ballSpeedY = -ballSpeedY;
createExplosion(ballX, ballY, 5, '#ff00ff');
}
// Ball collision with paddles
// Player paddle
if (
ballX <= PADDLE_WIDTH + 20 &&
ballY >= playerY &&
ballY <= playerY + PADDLE_HEIGHT
) {
ballSpeedX = Math.abs(ballSpeedX) * 1.1;
ballSpeedY = ((ballY - (playerY + PADDLE_HEIGHT/2)) / PADDLE_HEIGHT) * 8;
createExplosion(ballX, ballY, 10, '#00ff41');
}
// CPU paddle
if (
ballX >= GAME_WIDTH - PADDLE_WIDTH - 20 &&
ballY >= cpuY &&
ballY <= cpuY + PADDLE_HEIGHT
) {
ballSpeedX = -Math.abs(ballSpeedX) * 1.1;
ballSpeedY = ((ballY - (cpuY + PADDLE_HEIGHT/2)) / PADDLE_HEIGHT) * 8;
createExplosion(ballX, ballY, 10, '#ff00ff');
}
// Scoring
if (ballX < 0) {
cpuScore++;
cpuScoreElement.textContent = cpuScore;
createExplosion(ballX, ballY, 30, '#ff0000');
resetBall();
} else if (ballX > GAME_WIDTH) {
playerScore++;
playerScoreElement.textContent = playerScore;
createExplosion(ballX, ballY, 30, '#00ff3c');
resetBall();
}
// AI for CPU paddle - improved to stay in bounds
const cpuPaddleCenter = cpuY + PADDLE_HEIGHT / 2;
const ballCenter = ballY;
if (cpuPaddleCenter < ballCenter - 15) {
cpuY = Math.min(cpuY + PADDLE_SPEED * 0.7, GAME_HEIGHT - PADDLE_HEIGHT);
} else if (cpuPaddleCenter > ballCenter + 15) {
cpuY = Math.max(cpuY - PADDLE_SPEED * 0.7, 0);
}
// Check game over
if (playerScore >= 5 || cpuScore >= 5) {
endGame();
}
updatePositions();
}
// Reset ball after scoring
function resetBall() {
if (playerScore >= 5 || cpuScore >= 5) return;
ballX = GAME_WIDTH / 2;
ballY = GAME_HEIGHT / 2;
ballSpeedX = 0;
ballSpeedY = 0;
gameRunning = false;
gameStarted = false;
setTimeout(() => {
if (!gameRunning) {
ballSpeedX = Math.random() > 0.5 ? INITIAL_BALL_SPEED : -INITIAL_BALL_SPEED;
ballSpeedY = (Math.random() * 4 - 2);
gameRunning = true;
}
}, 1000);
}
// Create explosion effect
function createExplosion(x, y, particleCount, color) {
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.backgroundColor = color;
particle.style.left = `${x}px`;
particle.style.top = `${y}px`;
const angle = Math.random() * Math.PI * 2;
const speed = 1 + Math.random() * 3;
const size = 3 + Math.random() * 8;
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
gameContainer.appendChild(particle);
const duration = 500 + Math.random() * 500;
let startTime = null;
function animate(time) {
if (!startTime) startTime = time;
const elapsed = time - startTime;
const progress = elapsed / duration;
if (progress < 1) {
particle.style.opacity = 1 - progress;
particle.style.transform = `translate(${Math.sin(angle) * speed * progress * 100}px, ${Math.cos(angle) * speed * progress * 100}px)`;
requestAnimationFrame(animate);
} else {
particle.remove();
}
}
requestAnimationFrame(animate);
}
}
// End the game
function endGame() {
gameRunning = false;
gameStarted = false;
if (playerScore > cpuScore) {
winnerText.textContent = "PLAYER VICTORY";
createExplosion(GAME_WIDTH / 2, GAME_HEIGHT / 2, 100, '#00ff41');
} else {
winnerText.textContent = "SYSTEM VICTORY";
createExplosion(GAME_WIDTH / 2, GAME_HEIGHT / 2, 100, '#ff00ff');
}
gameOverScreen.classList.remove('hidden');
gameOverScreen.classList.add('flex');
}
// Restart game
function restartGame() {
playerScore = 0;
cpuScore = 0;
playerScoreElement.textContent = '0';
cpuScoreElement.textContent = '0';
gameOverScreen.classList.add('hidden');
gameOverScreen.classList.remove('flex');
init();
}
// Keyboard controls
const keys = {
w: false,
s: false,
ArrowUp: false,
ArrowDown: false,
' ': false
};
window.addEventListener('keydown', (e) => {
if (keys.hasOwnProperty(e.key)) {
keys[e.key] = true;
if (e.key === ' ' && !gameStarted) {
startGame();
}
}
});
window.addEventListener('keyup', (e) => {
if (keys.hasOwnProperty(e.key)) {
keys[e.key] = false;
}
});
// Handle paddle movement with boundary checks
function handleInput() {
if (!gameRunning) return;
if ((keys.w || keys.ArrowUp)) {
playerY = Math.max(0, playerY - PADDLE_SPEED);
}
if ((keys.s || keys.ArrowDown)) {
playerY = Math.min(GAME_HEIGHT - PADDLE_HEIGHT, playerY + PADDLE_SPEED);
}
updatePositions();
}
// Event listeners
restartBtn.addEventListener('click', restartGame);
// Start the game engine
init();
// Main animation loop
function main() {
gameLoop();
handleInput();
requestAnimationFrame(main);
}
main();
// Generate grid pattern
const gridContainer = document.querySelector('.grid');
if (gridContainer) {
for (let i = 0; i < 15 * 8; i++) {
const cell = document.createElement('div');
cell.className = 'border-r border-b border-gray-800 opacity-20';
gridContainer.appendChild(cell);
}
}
</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=royam0820/royam0820-pong-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>