| | import pygame |
| | import random |
| | import math |
| |
|
| | |
| | WIDTH, HEIGHT = 800, 600 |
| | FPS = 60 |
| | WHITE = (255, 255, 255) |
| | BLACK = (0, 0, 0) |
| | SHIP_THRUST = 0.2 |
| | SHIP_MAX_SPEED = 5 |
| | BULLET_SPEED = 7 |
| |
|
| | |
| | pygame.init() |
| | screen = pygame.display.set_mode((WIDTH, HEIGHT)) |
| | pygame.display.set_caption("Pygame Asteroids Clone") |
| | clock = pygame.time.Clock() |
| |
|
| | |
| |
|
| | def wrap_around(sprite): |
| | """Wraps sprite position when it leaves the screen edges.""" |
| | if sprite.rect.left > WIDTH: |
| | sprite.rect.right = 0 |
| | if sprite.rect.right < 0: |
| | sprite.rect.left = WIDTH |
| | if sprite.rect.top > HEIGHT: |
| | sprite.rect.bottom = 0 |
| | if sprite.rect.bottom < 0: |
| | sprite.rect.top = HEIGHT |
| |
|
| | def distance(p1, p2): |
| | """Calculates the distance between two (x, y) points.""" |
| | return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) |
| |
|
| | |
| |
|
| | class Ship(pygame.sprite.Sprite): |
| | def __init__(self): |
| | super().__init__() |
| | |
| | self.image_orig = pygame.Surface((30, 30), pygame.SRCALPHA) |
| | |
| | pygame.draw.polygon(self.image_orig, WHITE, [(15, 0), (0, 30), (30, 30)]) |
| | self.image = self.image_orig.copy() |
| | self.rect = self.image.get_rect(center=(WIDTH / 2, HEIGHT / 2)) |
| | |
| | self.pos = pygame.math.Vector2(self.rect.center) |
| | self.vel = pygame.math.Vector2(0, 0) |
| | self.angle = 0 |
| | self.rotation_speed = 4 |
| |
|
| | def update(self): |
| | |
| | keys = pygame.key.get_pressed() |
| | if keys[pygame.K_LEFT]: |
| | self.angle += self.rotation_speed |
| | if keys[pygame.K_RIGHT]: |
| | self.angle -= self.rotation_speed |
| | |
| | |
| | self.angle %= 360 |
| | |
| | |
| | self.image = pygame.transform.rotate(self.image_orig, self.angle) |
| | self.rect = self.image.get_rect(center=self.rect.center) |
| | |
| | |
| | if keys[pygame.K_UP]: |
| | |
| | angle_rad = math.radians(self.angle - 90) |
| | |
| | |
| | thrust_x = SHIP_THRUST * math.cos(angle_rad) |
| | thrust_y = SHIP_THRUST * math.sin(angle_rad) |
| | |
| | self.vel += pygame.math.Vector2(thrust_x, thrust_y) |
| | |
| | |
| | if self.vel.length() > SHIP_MAX_SPEED: |
| | self.vel.scale_to_length(SHIP_MAX_SPEED) |
| |
|
| | |
| | self.pos += self.vel |
| | self.rect.center = (int(self.pos.x), int(self.pos.y)) |
| |
|
| | |
| | wrap_around(self) |
| |
|
| | def shoot(self, all_sprites, bullets): |
| | |
| | angle_rad = math.radians(self.angle - 90) |
| | |
| | |
| | spawn_x = self.pos.x + 15 * math.cos(angle_rad) |
| | spawn_y = self.pos.y + 15 * math.sin(angle_rad) |
| | |
| | bullet_vel_x = BULLET_SPEED * math.cos(angle_rad) |
| | bullet_vel_y = BULLET_SPEED * math.sin(angle_rad) |
| | |
| | bullet = Bullet(spawn_x, spawn_y, bullet_vel_x, bullet_vel_y) |
| | all_sprites.add(bullet) |
| | bullets.add(bullet) |
| |
|
| |
|
| | class Asteroid(pygame.sprite.Sprite): |
| | def __init__(self, size, center): |
| | super().__init__() |
| | self.size = size |
| | self.radius = self.size * 15 |
| | |
| | self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA) |
| | |
| | pygame.draw.circle(self.image, WHITE, (self.radius, self.radius), self.radius, 1) |
| | |
| | self.rect = self.image.get_rect(center=center) |
| | |
| | |
| | angle = random.uniform(0, 2 * math.pi) |
| | speed = random.uniform(0.5, 2) |
| | self.vel = pygame.math.Vector2(speed * math.cos(angle), speed * math.sin(angle)) |
| |
|
| | def update(self): |
| | self.rect.centerx += self.vel.x |
| | self.rect.centery += self.vel.y |
| | wrap_around(self) |
| |
|
| | def spawn_smaller(self): |
| | """Splits the asteroid into two smaller ones.""" |
| | if self.size > 1: |
| | new_size = self.size - 1 |
| | |
| | return [ |
| | Asteroid(new_size, self.rect.center), |
| | Asteroid(new_size, self.rect.center) |
| | ] |
| | return [] |
| |
|
| | class Bullet(pygame.sprite.Sprite): |
| | def __init__(self, x, y, vel_x, vel_y): |
| | super().__init__() |
| | self.image = pygame.Surface((4, 4)) |
| | self.image.fill(WHITE) |
| | self.rect = self.image.get_rect(center=(x, y)) |
| | self.vel = pygame.math.Vector2(vel_x, vel_y) |
| | |
| | self.lifespan = 90 |
| |
|
| | def update(self): |
| | self.rect.centerx += self.vel.x |
| | self.rect.centery += self.vel.y |
| | |
| | |
| | if not (0 < self.rect.x < WIDTH and 0 < self.rect.y < HEIGHT): |
| | self.kill() |
| | |
| | |
| | self.lifespan -= 1 |
| | if self.lifespan <= 0: |
| | self.kill() |
| |
|
| | |
| | all_sprites = pygame.sprite.Group() |
| | asteroids = pygame.sprite.Group() |
| | bullets = pygame.sprite.Group() |
| |
|
| | player = Ship() |
| | all_sprites.add(player) |
| |
|
| | |
| | for i in range(4): |
| | |
| | spawn_pos = (random.choice([random.randrange(0, 100), random.randrange(WIDTH - 100, WIDTH)]), |
| | random.choice([random.randrange(0, 100), random.randrange(HEIGHT - 100, HEIGHT)])) |
| | asteroid = Asteroid(3, spawn_pos) |
| | all_sprites.add(asteroid) |
| | asteroids.add(asteroid) |
| |
|
| | |
| | running = True |
| | last_shot_time = 0 |
| | SHOT_DELAY = 250 |
| |
|
| | while running: |
| | |
| | for event in pygame.event.get(): |
| | if event.type == pygame.QUIT: |
| | running = False |
| | if event.type == pygame.KEYDOWN: |
| | if event.key == pygame.K_SPACE: |
| | |
| | now = pygame.time.get_ticks() |
| | if now - last_shot_time > SHOT_DELAY: |
| | player.shoot(all_sprites, bullets) |
| | last_shot_time = now |
| |
|
| | |
| | all_sprites.update() |
| |
|
| | |
| | |
| | |
| | hits = pygame.sprite.groupcollide(bullets, asteroids, True, False) |
| | for bullet, hit_asteroids in hits.items(): |
| | for asteroid in hit_asteroids: |
| | |
| | new_asteroids = asteroid.spawn_smaller() |
| | for new_ast in new_asteroids: |
| | all_sprites.add(new_ast) |
| | asteroids.add(new_ast) |
| | |
| | asteroid.kill() |
| |
|
| | |
| | |
| | if pygame.sprite.spritecollide(player, asteroids, True, pygame.sprite.collide_mask): |
| | |
| | print("Ship Destroyed! Game Over.") |
| | running = False |
| |
|
| | |
| | screen.fill(BLACK) |
| | all_sprites.draw(screen) |
| |
|
| | |
| | pygame.display.flip() |
| |
|
| | |
| | clock.tick(FPS) |
| |
|
| | pygame.quit() |