pinball / index.html
jungnerd's picture
undefined - Initial Deployment
6535e16 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pinball Game</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@keyframes bump {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
@keyframes flash {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.bump-animation {
animation: bump 0.2s ease;
}
.flash-animation {
animation: flash 0.3s ease;
}
#game-container {
perspective: 1000px;
}
#pinball-table {
transform-style: preserve-3d;
transform: rotateX(10deg);
box-shadow: 0 20px 30px rgba(0, 0, 0, 0.3);
}
#ball {
transition: transform 0.05s linear;
}
.flipper {
transform-origin: left center;
transition: transform 0.1s ease;
}
.flipper.active {
transform: rotate(-30deg);
}
.bumper {
transition: transform 0.2s ease;
}
.bumper.hit {
transform: scale(1.1);
}
@media (max-width: 768px) {
#pinball-table {
transform: rotateX(15deg);
}
.controls {
flex-direction: column;
}
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-center p-4">
<div class="text-center mb-4">
<h1 class="text-4xl font-bold text-yellow-400 mb-2">Cosmic Pinball</h1>
<div class="flex justify-center gap-8 mb-4">
<div class="bg-gray-800 px-4 py-2 rounded-lg">
<span class="text-yellow-400">Score:</span> <span id="score" class="text-xl font-mono">0</span>
</div>
<div class="bg-gray-800 px-4 py-2 rounded-lg">
<span class="text-yellow-400">Balls:</span> <span id="balls" class="text-xl font-mono">3</span>
</div>
</div>
</div>
<div id="game-container" class="relative mb-8">
<div id="pinball-table" class="relative bg-blue-900 border-4 border-yellow-600 rounded-lg overflow-hidden" style="width: 600px; height: 800px;">
<!-- Ball -->
<div id="ball" class="absolute w-6 h-6 bg-white rounded-full shadow-lg z-10"></div>
<!-- Flippers -->
<div class="absolute bottom-16 left-32 w-32 h-6 bg-red-600 rounded-lg flipper" id="left-flipper"></div>
<div class="absolute bottom-16 right-32 w-32 h-6 bg-red-600 rounded-lg flipper" id="right-flipper" style="transform-origin: right center;"></div>
<!-- Bumpers -->
<div class="absolute top-40 left-40 w-16 h-16 bg-purple-600 rounded-full bumper" id="bumper1"></div>
<div class="absolute top-40 right-40 w-16 h-16 bg-purple-600 rounded-full bumper" id="bumper2"></div>
<div class="absolute top-60 left-1/2 transform -translate-x-1/2 w-16 h-16 bg-purple-600 rounded-full bumper" id="bumper3"></div>
<!-- Targets -->
<div class="absolute top-20 left-20 w-8 h-20 bg-green-500 rounded target" id="target1"></div>
<div class="absolute top-20 right-20 w-8 h-20 bg-green-500 rounded target" id="target2"></div>
<!-- Slingshots -->
<div class="absolute bottom-40 left-10 w-4 h-20 bg-orange-500 rounded slingshot" id="left-slingshot"></div>
<div class="absolute bottom-40 right-10 w-4 h-20 bg-orange-500 rounded slingshot" id="right-slingshot"></div>
<!-- Plunger area -->
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 w-24 h-8 bg-yellow-600 rounded"></div>
<!-- Side walls -->
<div class="absolute top-0 left-0 w-full h-8 bg-yellow-600"></div>
<div class="absolute top-0 left-0 w-8 h-full bg-yellow-600"></div>
<div class="absolute top-0 right-0 w-8 h-full bg-yellow-600"></div>
<!-- Decorations -->
<div class="absolute top-10 left-1/2 transform -translate-x-1/2 text-yellow-400 font-bold text-xl">COSMIC PINBALL</div>
<div class="absolute top-80 left-1/2 transform -translate-x-1/2 text-yellow-400 font-bold text-lg">EXTRA BALL</div>
<div class="absolute bottom-24 left-1/2 transform -translate-x-1/2 w-32 h-2 bg-yellow-400 rounded-full"></div>
</div>
</div>
<div class="controls flex gap-8 mb-8">
<button id="start-btn" class="bg-green-600 hover:bg-green-700 px-6 py-3 rounded-lg font-bold transition">START GAME</button>
<button id="left-btn" class="bg-red-600 hover:bg-red-700 px-6 py-3 rounded-lg font-bold transition">LEFT FLIPPER (A)</button>
<button id="right-btn" class="bg-red-600 hover:bg-red-700 px-6 py-3 rounded-lg font-bold transition">RIGHT FLIPPER (L)</button>
<button id="plunger-btn" class="bg-blue-600 hover:bg-blue-700 px-6 py-3 rounded-lg font-bold transition">PLUNGER (SPACE)</button>
</div>
<div class="text-gray-400 text-sm text-center max-w-md">
<p>Use the buttons or keyboard (A for left flipper, L for right flipper, SPACE for plunger)</p>
<p class="mt-2">Hit bumpers and targets to score points. Don't let the ball fall!</p>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Game elements
const ball = document.getElementById('ball');
const leftFlipper = document.getElementById('left-flipper');
const rightFlipper = document.getElementById('right-flipper');
const bumpers = document.querySelectorAll('.bumper');
const targets = document.querySelectorAll('.target');
const slingshots = document.querySelectorAll('.slingshot');
const scoreDisplay = document.getElementById('score');
const ballsDisplay = document.getElementById('balls');
const startBtn = document.getElementById('start-btn');
const leftBtn = document.getElementById('left-btn');
const rightBtn = document.getElementById('right-btn');
const plungerBtn = document.getElementById('plunger-btn');
// Game state
let score = 0;
let balls = 3;
let ballX = 300;
let ballY = 750;
let ballSpeedX = 0;
let ballSpeedY = 0;
let gravity = 0.2;
let friction = 0.99;
let gameActive = false;
let gameInterval;
let leftFlipperActive = false;
let rightFlipperActive = false;
// Initialize game
function initGame() {
resetBall();
score = 0;
balls = 3;
updateDisplay();
gameActive = true;
if (gameInterval) clearInterval(gameInterval);
gameInterval = setInterval(updateGame, 16);
}
// Reset ball to plunger position
function resetBall() {
ballX = 300;
ballY = 750;
ballSpeedX = 0;
ballSpeedY = 0;
updateBallPosition();
}
// Launch ball
function launchBall() {
if (ballY >= 750 && !gameActive) {
ballSpeedY = -15 + Math.random() * 5;
ballSpeedX = (Math.random() - 0.5) * 5;
gameActive = true;
}
}
// Update game state
function updateGame() {
if (!gameActive) return;
// Apply gravity
ballSpeedY += gravity;
// Apply friction
ballSpeedX *= friction;
ballSpeedY *= friction;
// Update position
ballX += ballSpeedX;
ballY += ballSpeedY;
// Wall collisions
if (ballX <= 8) {
ballX = 8;
ballSpeedX = -ballSpeedX * 0.8;
playSound('wall');
}
if (ballX >= 592) {
ballX = 592;
ballSpeedX = -ballSpeedX * 0.8;
playSound('wall');
}
if (ballY <= 8) {
ballY = 8;
ballSpeedY = -ballSpeedY * 0.8;
playSound('wall');
}
// Bottom out
if (ballY >= 792) {
balls--;
updateDisplay();
if (balls <= 0) {
gameActive = false;
setTimeout(() => alert(`Game Over! Final Score: ${score}`), 100);
} else {
setTimeout(() => {
resetBall();
gameActive = false;
}, 500);
}
playSound('lose');
}
// Flipper collisions
checkFlipperCollision(leftFlipper, true);
checkFlipperCollision(rightFlipper, false);
// Bumper collisions
bumpers.forEach(bumper => {
const rect = bumper.getBoundingClientRect();
const tableRect = document.getElementById('pinball-table').getBoundingClientRect();
const bumperX = rect.left - tableRect.left + rect.width / 2;
const bumperY = rect.top - tableRect.top + rect.height / 2;
const bumperRadius = rect.width / 2;
const dx = ballX - bumperX;
const dy = ballY - bumperY;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < bumperRadius + 12) {
// Collision detected
const angle = Math.atan2(dy, dx);
const force = 10;
ballSpeedX = Math.cos(angle) * force;
ballSpeedY = Math.sin(angle) * force;
// Visual feedback
bumper.classList.add('hit', 'flash-animation');
setTimeout(() => {
bumper.classList.remove('hit', 'flash-animation');
}, 300);
// Score
addScore(100);
playSound('bumper');
}
});
// Target collisions
targets.forEach(target => {
const rect = target.getBoundingClientRect();
const tableRect = document.getElementById('pinball-table').getBoundingClientRect();
const targetX = rect.left - tableRect.left;
const targetY = rect.top - tableRect.top;
const targetWidth = rect.width;
const targetHeight = rect.height;
if (ballX > targetX && ballX < targetX + targetWidth &&
ballY > targetY && ballY < targetY + targetHeight) {
// Collision detected
if (ballSpeedY < 0) ballSpeedY = -ballSpeedY * 1.2;
else ballSpeedY = Math.abs(ballSpeedY) * 1.2;
ballSpeedX += (Math.random() - 0.5) * 5;
// Visual feedback
target.classList.add('bump-animation');
setTimeout(() => {
target.classList.remove('bump-animation');
}, 200);
// Score
addScore(200);
playSound('target');
}
});
// Slingshot collisions
slingshots.forEach(slingshot => {
const rect = slingshot.getBoundingClientRect();
const tableRect = document.getElementById('pinball-table').getBoundingClientRect();
const slingX = rect.left - tableRect.left;
const slingY = rect.top - tableRect.top;
const slingWidth = rect.width;
const slingHeight = rect.height;
if (ballX > slingX && ballX < slingX + slingWidth &&
ballY > slingY && ballY < slingY + slingHeight) {
// Determine which side
const isLeft = slingshot.id === 'left-slingshot';
// Apply force
ballSpeedX = isLeft ? 8 : -8;
ballSpeedY = -5;
// Visual feedback
slingshot.classList.add('bump-animation');
setTimeout(() => {
slingshot.classList.remove('bump-animation');
}, 200);
// Score
addScore(50);
playSound('slingshot');
}
});
// Update ball position
updateBallPosition();
}
// Check flipper collision
function checkFlipperCollision(flipper, isLeft) {
if (!(leftFlipperActive && isLeft) && !(rightFlipperActive && !isLeft)) return;
const rect = flipper.getBoundingClientRect();
const tableRect = document.getElementById('pinball-table').getBoundingClientRect();
const flipperX = rect.left - tableRect.left;
const flipperY = rect.top - tableRect.top;
const flipperWidth = rect.width;
const flipperHeight = rect.height;
// Simple rectangular collision for flippers
if (ballX > flipperX && ballX < flipperX + flipperWidth &&
ballY > flipperY && ballY < flipperY + flipperHeight) {
// Apply force based on flipper direction
const force = isLeft ? -8 : 8;
ballSpeedX = force;
ballSpeedY = -10;
// Score
addScore(25);
playSound('flipper');
}
}
// Update ball position on screen
function updateBallPosition() {
ball.style.left = `${ballX - 12}px`;
ball.style.top = `${ballY - 12}px`;
}
// Add to score
function addScore(points) {
score += points;
updateDisplay();
}
// Update display
function updateDisplay() {
scoreDisplay.textContent = score;
ballsDisplay.textContent = balls;
}
// Play sound (simulated with class changes)
function playSound(type) {
// In a real game, you would play actual sounds here
// For this demo, we'll just log the sound type
console.log(`Playing sound: ${type}`);
}
// Event listeners
startBtn.addEventListener('click', initGame);
plungerBtn.addEventListener('click', launchBall);
// Flipper controls
function activateLeftFlipper() {
leftFlipper.classList.add('active');
leftFlipperActive = true;
}
function deactivateLeftFlipper() {
leftFlipper.classList.remove('active');
leftFlipperActive = false;
}
function activateRightFlipper() {
rightFlipper.classList.add('active');
rightFlipperActive = true;
}
function deactivateRightFlipper() {
rightFlipper.classList.remove('active');
rightFlipperActive = false;
}
leftBtn.addEventListener('mousedown', activateLeftFlipper);
leftBtn.addEventListener('mouseup', deactivateLeftFlipper);
leftBtn.addEventListener('mouseleave', deactivateLeftFlipper);
rightBtn.addEventListener('mousedown', activateRightFlipper);
rightBtn.addEventListener('mouseup', deactivateRightFlipper);
rightBtn.addEventListener('mouseleave', deactivateRightFlipper);
// Keyboard controls
document.addEventListener('keydown', (e) => {
if (e.key === 'a' || e.key === 'A') activateLeftFlipper();
if (e.key === 'l' || e.key === 'L') activateRightFlipper();
if (e.key === ' ') launchBall();
});
document.addEventListener('keyup', (e) => {
if (e.key === 'a' || e.key === 'A') deactivateLeftFlipper();
if (e.key === 'l' || e.key === 'L') deactivateRightFlipper();
});
// Initial setup
resetBall();
});
</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=jungnerd/pinball" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>