We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Asteroids

A critical part of Asteroids is the... well, asteroids. Let's create another class to represent them.

Asteroids in our game are simply circles.

Assignment

  1. def __init__(self, x: float, y: float, radius: float) -> None:
        super().__init__(x, y, radius)
    
    • The "surface" to draw on (the screen object)
    • The color of the circle ("white")
    • Its own position as the center
    • Its own radius
    • The width of the line to draw the circle (use LINE_WIDTH from constants.py)
  2. Asteroid.containers = (asteroids, updatable, drawable)
    
  3. ASTEROID_MIN_RADIUS = 20
    ASTEROID_KINDS = 3
    ASTEROID_SPAWN_RATE_SECONDS = 0.8
    ASTEROID_MAX_RADIUS = ASTEROID_MIN_RADIUS * ASTEROID_KINDS
    
  4. import random
    from collections.abc import Callable
    
    import pygame
    from asteroid import Asteroid
    from constants import *
    
    Edge = tuple[pygame.Vector2, Callable[[float], pygame.Vector2]]
    
    
    class AsteroidField(pygame.sprite.Sprite):
        containers: pygame.sprite.Group
    
        edges: list[Edge] = [
            (
                pygame.Vector2(1, 0),
                lambda y: pygame.Vector2(-ASTEROID_MAX_RADIUS, y * SCREEN_HEIGHT),
            ),
            (
                pygame.Vector2(-1, 0),
                lambda y: pygame.Vector2(
                    SCREEN_WIDTH + ASTEROID_MAX_RADIUS, y * SCREEN_HEIGHT
                ),
            ),
            (
                pygame.Vector2(0, 1),
                lambda x: pygame.Vector2(x * SCREEN_WIDTH, -ASTEROID_MAX_RADIUS),
            ),
            (
                pygame.Vector2(0, -1),
                lambda x: pygame.Vector2(
                    x * SCREEN_WIDTH, SCREEN_HEIGHT + ASTEROID_MAX_RADIUS
                ),
            ),
        ]
    
        def __init__(self) -> None:
            pygame.sprite.Sprite.__init__(self, self.containers)
            self.spawn_timer = 0.0
    
        def spawn(
            self, radius: float, position: pygame.Vector2, velocity: pygame.Vector2
        ) -> None:
            asteroid = Asteroid(position.x, position.y, radius)
            asteroid.velocity = velocity
    
        def update(self, dt: float) -> None:
            self.spawn_timer += dt
            if self.spawn_timer > ASTEROID_SPAWN_RATE_SECONDS:
                self.spawn_timer = 0
    
                # spawn a new asteroid at a random edge
                edge = random.choice(self.edges)
                speed = random.randint(40, 100)
                velocity = edge[0] * speed
                velocity = velocity.rotate(random.randint(-30, 30))
                position = edge[1](random.uniform(0, 1))
                kind = random.randint(1, ASTEROID_KINDS)
                self.spawn(ASTEROID_MIN_RADIUS * kind, position, velocity)
    

If everything looks good, run and submit the CLI tests.