Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import random | |
| import time | |
| from PIL import Image, ImageDraw | |
| # Game constants | |
| SCREEN_WIDTH, SCREEN_HEIGHT = 800, 600 | |
| PLAYER_SIZE = 40 | |
| ENEMY_SIZE = 40 | |
| BULLET_SIZE = 10 | |
| PLAYER_SPEED = 5 | |
| BULLET_SPEED = 10 | |
| ENEMY_SPEED = 2 | |
| SPAWN_RATE = 0.02 | |
| MAX_ENEMIES = 10 | |
| MAX_BULLETS = 5 | |
| class GameObject: | |
| def __init__(self, x, y, width, height): | |
| self.x = x | |
| self.y = y | |
| self.width = width | |
| self.height = height | |
| def rect(self): | |
| return (self.x, self.y, self.x + self.width, self.y + self.height) | |
| def collides_with(self, other): | |
| return (self.x < other.x + other.width and | |
| self.x + self.width > other.x and | |
| self.y < other.y + other.height and | |
| self.y + self.height > other.y) | |
| class Player(GameObject): | |
| def __init__(self, x, y): | |
| super().__init__(x, y, PLAYER_SIZE, PLAYER_SIZE) | |
| self.health = 100 | |
| self.score = 0 | |
| self.bullets = [] | |
| self.last_shot = 0 | |
| self.shot_cooldown = 0.3 | |
| self.dx = 0 | |
| self.dy = 0 | |
| def update_position(self): | |
| self.x = max(0, min(SCREEN_WIDTH - self.width, self.x + self.dx * PLAYER_SPEED)) | |
| self.y = max(0, min(SCREEN_HEIGHT - self.height, self.y + self.dy * PLAYER_SPEED)) | |
| def shoot(self, current_time, target_x, target_y): | |
| if current_time - self.last_shot >= self.shot_cooldown and len(self.bullets) < MAX_BULLETS: | |
| self.last_shot = current_time | |
| dx = target_x - (self.x + self.width/2) | |
| dy = target_y - (self.y + self.height/2) | |
| distance = max(1, (dx**2 + dy**2)**0.5) | |
| dx, dy = dx/distance * BULLET_SPEED, dy/distance * BULLET_SPEED | |
| self.bullets.append({ | |
| 'x': self.x + self.width/2 - BULLET_SIZE/2, | |
| 'y': self.y + self.height/2 - BULLET_SIZE/2, | |
| 'dx': dx, | |
| 'dy': dy, | |
| 'size': BULLET_SIZE | |
| }) | |
| class Enemy(GameObject): | |
| def __init__(self, x, y): | |
| super().__init__(x, y, ENEMY_SIZE, ENEMY_SIZE) | |
| self.speed = ENEMY_SPEED * (0.8 + random.random() * 0.4) | |
| def move_towards(self, target_x, target_y): | |
| dx = target_x - (self.x + self.width/2) | |
| dy = target_y - (self.y + self.height/2) | |
| distance = max(1, (dx**2 + dy**2)**0.5) | |
| self.x += dx/distance * self.speed | |
| self.y += dy/distance * self.speed | |
| class GameState: | |
| def __init__(self): | |
| self.reset() | |
| def reset(self): | |
| self.player = Player(SCREEN_WIDTH//2, SCREEN_HEIGHT//2) | |
| self.enemies = [] | |
| self.game_over = False | |
| self.start_time = time.time() | |
| self.last_enemy_spawn = 0 | |
| self.background = self.create_background() | |
| self.mouse_pos = (SCREEN_WIDTH//2, SCREEN_HEIGHT//2) | |
| def create_background(self): | |
| img = Image.new('RGB', (SCREEN_WIDTH, SCREEN_HEIGHT), color=(30, 30, 40)) | |
| draw = ImageDraw.Draw(img) | |
| for x in range(0, SCREEN_WIDTH, 50): | |
| draw.line((x, 0, x, SCREEN_HEIGHT), fill=(50, 50, 60), width=1) | |
| for y in range(0, SCREEN_HEIGHT, 50): | |
| draw.line((0, y, SCREEN_WIDTH, y), fill=(50, 50, 60), width=1) | |
| return img | |
| def update(self): | |
| if self.game_over: | |
| return self.render() | |
| current_time = time.time() | |
| # Update player position | |
| self.player.update_position() | |
| # Update bullets | |
| for bullet in self.player.bullets[:]: | |
| bullet['x'] += bullet['dx'] | |
| bullet['y'] += bullet['dy'] | |
| if (bullet['x'] < 0 or bullet['x'] > SCREEN_WIDTH or | |
| bullet['y'] < 0 or bullet['y'] > SCREEN_HEIGHT): | |
| self.player.bullets.remove(bullet) | |
| continue | |
| for enemy in self.enemies[:]: | |
| enemy_rect = enemy.rect | |
| if (bullet['x'] < enemy_rect[2] and bullet['x'] + bullet['size'] > enemy_rect[0] and | |
| bullet['y'] < enemy_rect[3] and bullet['y'] + bullet['size'] > enemy_rect[1]): | |
| self.enemies.remove(enemy) | |
| if bullet in self.player.bullets: | |
| self.player.bullets.remove(bullet) | |
| self.player.score += 10 | |
| break | |
| # Spawn enemies | |
| if (len(self.enemies) < MAX_ENEMIES and | |
| current_time - self.last_enemy_spawn > 1 and | |
| random.random() < SPAWN_RATE): | |
| self.last_enemy_spawn = current_time | |
| side = random.randint(0, 3) | |
| if side == 0: # top | |
| x = random.randint(0, SCREEN_WIDTH) | |
| y = -ENEMY_SIZE | |
| elif side == 1: # right | |
| x = SCREEN_WIDTH | |
| y = random.randint(0, SCREEN_HEIGHT) | |
| elif side == 2: # bottom | |
| x = random.randint(0, SCREEN_WIDTH) | |
| y = SCREEN_HEIGHT | |
| else: # left | |
| x = -ENEMY_SIZE | |
| y = random.randint(0, SCREEN_HEIGHT) | |
| self.enemies.append(Enemy(x, y)) | |
| # Move enemies | |
| for enemy in self.enemies: | |
| enemy.move_towards(self.player.x + self.player.width/2, | |
| self.player.y + self.player.height/2) | |
| if enemy.collides_with(self.player): | |
| self.player.health -= 1 | |
| if self.player.health <= 0: | |
| self.game_over = True | |
| return self.render() | |
| def render(self): | |
| img = self.background.copy() | |
| draw = ImageDraw.Draw(img) | |
| # Draw player | |
| player_center = (self.player.x + self.player.width/2, | |
| self.player.y + self.player.height/2) | |
| draw.ellipse(self.player.rect, fill='blue') | |
| draw.line((player_center[0], player_center[1], | |
| player_center[0] + 20, player_center[1]), | |
| fill='white', width=3) | |
| # Draw enemies | |
| for enemy in self.enemies: | |
| draw.ellipse(enemy.rect, fill='red') | |
| # Draw bullets | |
| for bullet in self.player.bullets: | |
| draw.ellipse((bullet['x'], bullet['y'], | |
| bullet['x'] + bullet['size'], | |
| bullet['y'] + bullet['size']), | |
| fill='yellow') | |
| # Draw UI | |
| draw.rectangle((10, 10, 210, 30), fill='black') | |
| draw.rectangle((10, 10, 10 + 2 * self.player.health, 30), fill='red') | |
| draw.text((220, 10), f"Health: {self.player.health}", fill='white') | |
| draw.text((10, 40), f"Score: {self.player.score}", fill='white') | |
| draw.text((10, 70), f"Enemies: {len(self.enemies)}", fill='white') | |
| if self.game_over: | |
| draw.rectangle((SCREEN_WIDTH//2 - 150, SCREEN_HEIGHT//2 - 60, | |
| SCREEN_WIDTH//2 + 150, SCREEN_HEIGHT//2 + 60), | |
| fill='black') | |
| draw.text((SCREEN_WIDTH//2 - 140, SCREEN_HEIGHT//2 - 50), | |
| "GAME OVER", fill='red') | |
| draw.text((SCREEN_WIDTH//2 - 140, SCREEN_HEIGHT//2), | |
| f"Final Score: {self.player.score}", fill='white') | |
| draw.text((SCREEN_WIDTH//2 - 140, SCREEN_HEIGHT//2 + 40), | |
| "Click Restart button to play again", fill='white') | |
| return img | |
| # Create game state | |
| game_state = GameState() | |
| def update_game(): | |
| return game_state.update() | |
| def handle_mouse(evt: gr.SelectData): | |
| game_state.mouse_pos = (evt.index[0], evt.index[1]) | |
| game_state.player.shoot(time.time(), evt.index[0], evt.index[1]) | |
| return update_game() | |
| def move(direction): | |
| if direction == "up": | |
| game_state.player.dy = -1 | |
| elif direction == "down": | |
| game_state.player.dy = 1 | |
| elif direction == "left": | |
| game_state.player.dx = -1 | |
| elif direction == "right": | |
| game_state.player.dx = 1 | |
| elif direction == "stop": | |
| game_state.player.dx = 0 | |
| game_state.player.dy = 0 | |
| return update_game() | |
| def restart_game(): | |
| game_state.reset() | |
| return update_game() | |
| with gr.Blocks(title="Battle Royale Shooter", theme=gr.themes.Soft()) as demo: | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("# Battle Royale Shooter") | |
| game_image = gr.Image(label="Game Screen", | |
| interactive=True, | |
| width=SCREEN_WIDTH, | |
| height=SCREEN_HEIGHT) | |
| # Mouse tracking | |
| game_image.select(handle_mouse, outputs=game_image) | |
| # Movement controls | |
| with gr.Row(): | |
| up_btn = gr.Button("β Move Up") | |
| down_btn = gr.Button("β Move Down") | |
| with gr.Row(): | |
| left_btn = gr.Button("β Move Left") | |
| right_btn = gr.Button("β Move Right") | |
| # Action controls | |
| stop_btn = gr.Button("π Stop Moving") | |
| restart_btn = gr.Button("π Restart") | |
| # Control bindings | |
| up_btn.click(lambda: move("up"), outputs=game_image) | |
| down_btn.click(lambda: move("down"), outputs=game_image) | |
| left_btn.click(lambda: move("left"), outputs=game_image) | |
| right_btn.click(lambda: move("right"), outputs=game_image) | |
| stop_btn.click(lambda: move("stop"), outputs=game_image) | |
| restart_btn.click(restart_game, outputs=game_image) | |
| # Game loop | |
| def main(): | |
| game_loop = gr.Interface( | |
| fn=my_function, | |
| inputs=gr.Textbox(), | |
| outputs=gr.Textbox() | |
| ) | |
| gr.Markdown("how to play:") | |
| 1. Click on the game screen to shoot | |
| 2. Use movement buttons to move your character | |
| 3. Click Stop button to halt movement | |
| 4. Avoid enemies and shoot them to earn points | |
| 5. When game over, click Restart to play again | |
| """) | |
| if __name__ == "__main__": | |
| demo.launch() hello |