import gradio as gr import numpy as np from PIL import Image, ImageDraw, ImageFont import random # Game setup WIDTH, HEIGHT = 500, 400 PLAYER_SIZE = 30 ASTEROID_SIZE = 25 BULLET_SIZE = 8 player_x = WIDTH // 2 player_y = HEIGHT - 50 asteroids = [] bullets = [] score = 0 game_over = False explosions = [] # Starry background stars = [(random.randint(0, WIDTH), random.randint(0, HEIGHT)) for _ in range(100)] def draw_frame(): """Draws the game frame with cool visuals.""" img = Image.new("RGB", (WIDTH, HEIGHT), (10, 5, 30)) # Dark blue space draw = ImageDraw.Draw(img) # Draw stars (twinkling background) for x, y in stars: brightness = random.randint(100, 255) draw.ellipse([x, y, x+2, y+2], fill=(brightness, brightness, brightness)) # Draw player (spaceship emoji) try: font = ImageFont.truetype("arial.ttf", PLAYER_SIZE) draw.text((player_x - PLAYER_SIZE//2, player_y - PLAYER_SIZE//2), "🛸", font=font) except: draw.rectangle( # Fallback if emoji fails [player_x - PLAYER_SIZE//2, player_y - PLAYER_SIZE//2, player_x + PLAYER_SIZE//2, player_y + PLAYER_SIZE//2], fill="blue" ) # Draw asteroids (rock emoji) for x, y in asteroids: try: draw.text((x - ASTEROID_SIZE//2, y - ASTEROID_SIZE//2), "🪨", font=font) except: draw.rectangle( [x - ASTEROID_SIZE//2, y - ASTEROID_SIZE//2, x + ASTEROID_SIZE//2, y + ASTEROID_SIZE//2], fill="red" ) # Draw bullets (light beam) for x, y in bullets: draw.rectangle( [x - BULLET_SIZE//2, y, x + BULLET_SIZE//2, y + BULLET_SIZE*2], fill=(255, 255, 0) # Yellow ) # Draw explosions for x, y in explosions: draw.text((x - ASTEROID_SIZE, y - ASTEROID_SIZE), "💥", font=font) # Draw score (modern font) draw.text((10, 10), f"Score: {score}", fill="white", font=font) if game_over: draw.text( (WIDTH//2 - 100, HEIGHT//2 - 20), "GAME OVER! Press [R]", fill="red", font=font ) return np.array(img) def update_game(action): global player_x, asteroids, bullets, score, game_over, explosions if game_over and action == "r": reset_game() return draw_frame() if game_over: return draw_frame() # Handle controls if action == "a": player_x = max(PLAYER_SIZE//2, player_x - 10) elif action == "d": player_x = min(WIDTH - PLAYER_SIZE//2, player_x + 10) elif action == " ": bullets.append([player_x, player_y - PLAYER_SIZE]) # Update bullets for bullet in bullets[:]: bullet[1] -= 12 if bullet[1] < 0: bullets.remove(bullet) # Spawn asteroids if random.random() < 0.03: asteroids.append([random.randint(20, WIDTH-20), 0]) # Update asteroids for asteroid in asteroids[:]: asteroid[1] += 5 if asteroid[1] > HEIGHT: asteroids.remove(asteroid) # Collision with player if (abs(asteroid[0] - player_x) < (ASTEROID_SIZE + PLAYER_SIZE)//2 and \ abs(asteroid[1] - player_y) < (ASTEROID_SIZE + PLAYER_SIZE)//2: game_over = True explosions.append([asteroid[0], asteroid[1]]) # Bullet-asteroid collisions for bullet in bullets[:]: for asteroid in asteroids[:]: if (abs(bullet[0] - asteroid[0]) < (BULLET_SIZE + ASTEROID_SIZE)//2 and \ abs(bullet[1] - asteroid[1]) < (BULLET_SIZE + ASTEROID_SIZE)//2: bullets.remove(bullet) asteroids.remove(asteroid) explosions.append([asteroid[0], asteroid[1]]) score += 10 break # Clear explosions after 3 frames if len(explosions) > 0: explosions.clear() return draw_frame() def reset_game(): global player_x, asteroids, bullets, score, game_over player_x = WIDTH // 2 asteroids.clear() bullets.clear() score = 0 game_over = False # Gradio UI with gr.Blocks(title="🚀 Space Defender") as demo: gr.Markdown("# 🪐 SPACE DEFENDER") with gr.Row(): game_screen = gr.Image(label="Cosmic Battle", width=500, height=400) with gr.Row(): gr.Button("⬅️ Left (A)").click(lambda: update_game("a"), outputs=game_screen) gr.Button("🔫 Shoot (Space)").click(lambda: update_game(" "), outputs=game_screen) gr.Button("➡️ Right (D)").click(lambda: update_game("d"), outputs=game_screen) gr.Button("🔄 Restart (R)").click(lambda: update_game("r"), outputs=game_screen) demo.load(lambda: draw_frame(), outputs=game_screen) demo.launch()