game / app.py
sagar007's picture
Update app.py
dacd0b6 verified
raw
history blame
18.5 kB
import gradio as gr
# The HTML content of the bird shooter game
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>Bird Shooter Game</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #87CEEB;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: Arial, sans-serif;
}
#game-container {
position: relative;
width: 800px;
height: 600px;
border: 2px solid black;
background-color: #87CEEB;
overflow: hidden;
}
#score {
position: absolute;
top: 10px;
left: 10px;
font-size: 24px;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
#game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 48px;
color: red;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
display: none;
}
#restart-button {
position: absolute;
top: 60%;
left: 50%;
transform: translate(-50%, -50%);
padding: 10px 20px;
font-size: 24px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
display: none;
}
.cloud {
position: absolute;
fill: white;
opacity: 0.8;
}
</style>
</head>
<body>
<div id="game-container">
<svg id="game-canvas" width="800" height="600"></svg>
<div id="score">Score: 0</div>
<div id="game-over">GAME OVER</div>
<button id="restart-button">Restart</button>
</div>
<script>
const gameCanvas = document.getElementById('game-canvas');
const scoreDisplay = document.getElementById('score');
const gameOverDisplay = document.getElementById('game-over');
const restartButton = document.getElementById('restart-button');
let score = 0;
let gameRunning = true;
let birds = [];
let explosions = [];
// Create clouds in the background
function createClouds() {
const cloudCount = 5;
for (let i = 0; i < cloudCount; i++) {
const cloud = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
cloud.setAttribute("cx", Math.random() * 800);
cloud.setAttribute("cy", 50 + Math.random() * 100);
cloud.setAttribute("rx", 50 + Math.random() * 50);
cloud.setAttribute("ry", 20 + Math.random() * 20);
cloud.setAttribute("fill", "white");
cloud.setAttribute("opacity", "0.8");
cloud.classList.add("cloud");
gameCanvas.appendChild(cloud);
// Create smaller ellipse attached to the cloud
const cloudPart = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
cloudPart.setAttribute("cx", parseFloat(cloud.getAttribute("cx")) + 30);
cloudPart.setAttribute("cy", parseFloat(cloud.getAttribute("cy")) - 5);
cloudPart.setAttribute("rx", 30);
cloudPart.setAttribute("ry", 15);
cloudPart.setAttribute("fill", "white");
cloudPart.setAttribute("opacity", "0.8");
gameCanvas.appendChild(cloudPart);
}
}
// Bird class
class Bird {
constructor() {
this.x = -50;
this.y = 100 + Math.random() * 300;
this.speed = 2 + Math.random() * 3;
this.size = 30 + Math.random() * 20;
this.element = this.createBirdElement();
gameCanvas.appendChild(this.element);
}
createBirdElement() {
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
// Bird body
const body = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
body.setAttribute("cx", "0");
body.setAttribute("cy", "0");
body.setAttribute("rx", this.size / 2);
body.setAttribute("ry", this.size / 3);
body.setAttribute("fill", this.getRandomColor());
group.appendChild(body);
// Bird head
const head = document.createElementNS("http://www.w3.org/2000/svg", "circle");
head.setAttribute("cx", this.size / 2);
head.setAttribute("cy", -this.size / 6);
head.setAttribute("r", this.size / 4);
head.setAttribute("fill", this.getRandomColor());
group.appendChild(head);
// Bird eye
const eye = document.createElementNS("http://www.w3.org/2000/svg", "circle");
eye.setAttribute("cx", this.size / 2 + this.size / 8);
eye.setAttribute("cy", -this.size / 6 - this.size / 8);
eye.setAttribute("r", this.size / 10);
eye.setAttribute("fill", "black");
group.appendChild(eye);
// Bird beak
const beak = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
beak.setAttribute("points",
`${this.size / 2 + this.size / 4},-${this.size / 6}
${this.size},0
${this.size / 2 + this.size / 4},${this.size / 10}`);
beak.setAttribute("fill", "orange");
group.appendChild(beak);
// Bird wings
const wing = document.createElementNS("http://www.w3.org/2000/svg", "ellipse");
wing.setAttribute("cx", "0");
wing.setAttribute("cy", this.size / 4);
wing.setAttribute("rx", this.size / 3);
wing.setAttribute("ry", this.size / 6);
wing.setAttribute("fill", this.getRandomColor());
wing.setAttribute("class", "wing");
group.appendChild(wing);
return group;
}
getRandomColor() {
const colors = ["#FF5733", "#33FF57", "#3357FF", "#F3FF33", "#FF33F3", "#33FFF3"];
return colors[Math.floor(Math.random() * colors.length)];
}
update() {
this.x += this.speed;
this.element.setAttribute("transform", `translate(${this.x}, ${this.y})`);
// Animate wings
const wing = this.element.querySelector(".wing");
if (wing) {
const wingAngle = 15 * Math.sin(Date.now() / 100);
wing.setAttribute("transform", `rotate(${wingAngle})`);
}
// Check if bird has left the screen
if (this.x > 850) {
this.remove();
return false;
}
return true;
}
remove() {
if (this.element.parentNode) {
gameCanvas.removeChild(this.element);
}
}
checkHit(x, y) {
const birdX = this.x;
const birdY = this.y;
const distance = Math.sqrt(Math.pow(birdX - x, 2) + Math.pow(birdY - y, 2));
return distance < this.size;
}
}
// Explosion class
class Explosion {
constructor(x, y, size) {
this.x = x;
this.y = y;
this.size = size;
this.frame = 0;
this.maxFrames = 20;
this.element = this.createExplosionElement();
gameCanvas.appendChild(this.element);
this.playSound();
}
createExplosionElement() {
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
// Create explosion particles
const colors = ["#FF0000", "#FF7700", "#FFFF00"];
const particleCount = 12;
for (let i = 0; i < particleCount; i++) {
const angle = (i / particleCount) * 2 * Math.PI;
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("cx", Math.cos(angle) * (this.size / 3));
circle.setAttribute("cy", Math.sin(angle) * (this.size / 3));
circle.setAttribute("r", this.size / 8);
circle.setAttribute("fill", colors[Math.floor(Math.random() * colors.length)]);
circle.setAttribute("class", "particle");
circle.setAttribute("data-angle", angle);
group.appendChild(circle);
}
// Add central explosion
const center = document.createElementNS("http://www.w3.org/2000/svg", "circle");
center.setAttribute("cx", 0);
center.setAttribute("cy", 0);
center.setAttribute("r", this.size / 2);
center.setAttribute("fill", "#FF0000");
center.setAttribute("class", "center");
group.appendChild(center);
group.setAttribute("transform", `translate(${this.x}, ${this.y})`);
return group;
}
playSound() {
// Create explosion sound
const explosion = new Audio();
explosion.src = "data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=";
explosion.volume = 0.3;
explosion.play();
}
update() {
this.frame++;
// Update explosion size and opacity
const center = this.element.querySelector(".center");
const sizeMultiplier = 1 + this.frame / 5;
center.setAttribute("r", (this.size / 2) * sizeMultiplier);
center.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
// Update particles
const particles = this.element.querySelectorAll(".particle");
particles.forEach(particle => {
const angle = parseFloat(particle.getAttribute("data-angle"));
const distance = (this.size / 3) + (this.frame * 2);
const x = Math.cos(angle) * distance;
const y = Math.sin(angle) * distance;
particle.setAttribute("cx", x);
particle.setAttribute("cy", y);
particle.setAttribute("opacity", 1 - (this.frame / this.maxFrames));
particle.setAttribute("r", this.size / 8 * (1 - this.frame / this.maxFrames));
});
// Check if explosion is finished
if (this.frame >= this.maxFrames) {
this.remove();
return false;
}
return true;
}
remove() {
if (this.element.parentNode) {
gameCanvas.removeChild(this.element);
}
}
}
// Initialize the game
function initGame() {
score = 0;
gameRunning = true;
scoreDisplay.textContent = `Score: ${score}`;
gameOverDisplay.style.display = 'none';
restartButton.style.display = 'none';
// Remove all birds and explosions
birds.forEach(bird => bird.remove());
explosions.forEach(explosion => explosion.remove());
birds = [];
explosions = [];
// Clear any existing elements
while (gameCanvas.firstChild) {
gameCanvas.removeChild(gameCanvas.firstChild);
}
// Create clouds
createClouds();
// Start game loop
gameLoop();
}
// Game loop
function gameLoop() {
if (!gameRunning) return;
// Create new birds randomly
if (Math.random() < 0.02) {
birds.push(new Bird());
}
// Update birds
for (let i = birds.length - 1; i >= 0; i--) {
if (!birds[i].update()) {
birds.splice(i, 1);
}
}
// Update explosions
for (let i = explosions.length - 1; i >= 0; i--) {
if (!explosions[i].update()) {
explosions.splice(i, 1);
}
}
requestAnimationFrame(gameLoop);
}
// Handle mouse clicks
gameCanvas.addEventListener('click', (e) => {
if (!gameRunning) return;
const rect = gameCanvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
let hit = false;
// Check if any bird was hit
for (let i = birds.length - 1; i >= 0; i--) {
if (birds[i].checkHit(x, y)) {
// Create explosion
const birdX = birds[i].x;
const birdY = birds[i].y;
const birdSize = birds[i].size;
// Remove the bird
birds[i].remove();
birds.splice(i, 1);
// Create explosion
explosions.push(new Explosion(birdX, birdY, birdSize * 2));
// Increment score
score += 10;
scoreDisplay.textContent = `Score: ${score}`;
hit = true;
}
}
// Play miss sound if no bird was hit
if (!hit) {
const miss = new Audio();
miss.src = "data:audio/wav;base64,UklGRiQDAABXQVZFZm10IBAAAAABAAEAESsAABErAAABAAgAZGF0YQADAABkAGQAZABkAGQAfACEAJwAsAC8AMgA1ADsAOQA7ADkANQA0AC8AKgAnACMAHQAXABMAEQAPABEADwANAA0ADQALAAsACQAHAAUAAwABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA8AFgAaAB8AIQAnACsAMAAyADMANwA3ADcAMgA0ADAALAApACQAIQAbABYAEQAMAAUAAAAAAAAAAAAAAAAAAAAAAAAAAP//9//x//X/9f/4/wAABwANABYAHAAnADIAOABDAEsAVABdAGQAbQBzAH4AhQCKAJEAlQCYAJ4AnwCgAKIAoQCgAJwAmgCXAJIAjwCIAIMAfQB2AG4AZgBeAFQATABGAD4ANQAvACgAIgAaABUADAAIAAQAAQD+//r/9//0//H/7//u/+z/6//r/+r/6v/p/+n/6v/q/+v/7P/u/+//8f/z//X/+P/7//7/AQADAAYACQALABAAEQAUABYAGAAZAB0AHQAfACEAIgAkACUAJQAmACcAJwAoACkAKQAqACsAKwAsACwALQAtAC0ALQAuAC4ALgAuAC4ALgAtAC0ALQAsACwALAAqACkAKQAnACYAJgAkACMAIgAgAB8AHgAcABoAGQAYABYAFAAQAA4ADAAJAAcABQADAAEA//89//7//f/8//v/+v/5//j/9//2//X/9P/z//P/8v/x//D/8P/v/+7/7v/t/+3/7P/s/+v/6//q/+r/6v/p/+n/6f/p/+n/6f/p/+n/6f/p/+n/6v/q/+v/6//s/+z/7f/u/+7/7//w//H/8v/z//T/9f/2//f/+P/5//v//P/9/wAAAgADAAUABgAIAAkACwAMAA4AEAARACMACwAEAP//+//4//X/8v/v/+v/6P/l/+L/4P/e/9v/2f/X/9X/1P/S/9H/z//O/83/zf/M/8v/y//K/8r/yv/K/8v/y//L/8z/zf/O/8//0P/S/9P/1f/X/9j/2v/c/97/4f/j/+X/6P/q/+3/8P/z//X/+P/7//7/AQA=";
miss.volume = 0.2;
miss.play();
}
});
// Restart game when button is clicked
restartButton.addEventListener('click', () => {
initGame();
});
// Initialize the game
initGame();
</script>
</body>
</html>
"""
def create_game():
return gr.HTML(html_content, height=650)
# Create Gradio interface
with gr.Blocks(title="Bird Shooter Game") as demo:
gr.Markdown("# 🎮 Bird Shooter Game")
gr.Markdown("Click on the birds to shoot them and score points!")
game_interface = create_game()
gr.Markdown("""
## How to Play
- Click on birds to shoot them
- Each hit earns you 10 points
- Try to get the highest score possible!
## About
This is a simple bird shooter game created with SVG and JavaScript, embedded in a Gradio app for Hugging Face Spaces.
""")
# Launch the app
if __name__ == "__main__":
demo.launch()