Spaces:
Runtime error
Runtime error
| 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() |