Код IT Загрузка примера кода…

Python alien_wave.py
"""Стая пришельцев, бомбы и движение."""

from __future__ import annotations

import random
from dataclasses import dataclass
from typing import List, Optional

import pygame

import settings as S


@dataclass
class Alien:
    row: int
    rect: pygame.Rect
    points: int
    color: tuple[int, int, int]
    alive: bool = True


class AlienWave:
    def __init__(self) -> None:
        self.aliens: List[Alien] = []
        self.direction = 1
        self.bombs: List[pygame.Rect] = []
        self.bomb_cd = 120
        self._spawn_grid()

    def _spawn_grid(self) -> None:
        self.aliens.clear()
        for row in range(S.ALIEN_ROWS):
            y = S.ALIEN_TOP + row * (S.ALIEN_H + S.ALIEN_GAP_Y)
            row_width = S.ALIEN_COLS * S.ALIEN_W + (S.ALIEN_COLS - 1) * S.ALIEN_GAP_X
            start_x = (S.WIDTH - row_width) // 2
            for col in range(S.ALIEN_COLS):
                x = start_x + col * (S.ALIEN_W + S.ALIEN_GAP_X)
                self.aliens.append(
                    Alien(
                        row=row,
                        rect=pygame.Rect(x, y, S.ALIEN_W, S.ALIEN_H),
                        points=S.ROW_POINTS[row],
                        color=S.ROW_COLORS[row],
                    )
                )

    def living(self) -> List[Alien]:
        return [a for a in self.aliens if a.alive]

    def speed(self) -> int:
        left = len(self.living())
        return S.ALIEN_H_SPEED + max(0, (S.ALIEN_ROWS * S.ALIEN_COLS - left) // 8)

    def update(self) -> None:
        alive = self.living()
        if not alive:
            return
        edge = any(a.rect.left <= 8 or a.rect.right >= S.WIDTH - 8 for a in alive)
        drop = False
        if edge:
            self.direction *= -1
            drop = True
        spd = self.speed()
        for a in alive:
            a.rect.x += spd * self.direction
            if drop:
                a.rect.y += S.ALIEN_DROP
        self.bomb_cd -= 1
        if self.bomb_cd <= 0:
            bottom_row = max(a.row for a in alive)
            shooters = [a for a in alive if a.row == bottom_row]
            shooter = random.choice(shooters)
            self.bombs.append(pygame.Rect(shooter.rect.centerx - 3, shooter.rect.bottom, 6, 14))
            self.bomb_cd = random.randint(90, 180)
        for bomb in self.bombs[:]:
            bomb.y += S.BOMB_SPEED
            if bomb.top > S.HEIGHT:
                self.bombs.remove(bomb)

    def drop_bombs(self) -> List[pygame.Rect]:
        return list(self.bombs)

    def remove_bomb(self, bomb: pygame.Rect) -> None:
        if bomb in self.bombs:
            self.bombs.remove(bomb)

    def hit_test(self, rect: pygame.Rect) -> Optional[Alien]:
        for alien in self.living():
            if rect.colliderect(alien.rect):
                return alien
        return None

    def cleared(self) -> bool:
        return len(self.living()) == 0

    def reached_player(self, player: pygame.Rect) -> bool:
        alive = self.living()
        if not alive:
            return False
        return max(a.rect.bottom for a in alive) >= player.top - 8

    def draw(self, surface: pygame.Surface) -> None:
        for alien in self.living():
            pygame.draw.rect(surface, alien.color, alien.rect, border_radius=4)
        for bomb in self.bombs:
            pygame.draw.rect(surface, S.BOMB_COLOR, bomb, border_radius=2)
"""Стая пришельцев, бомбы и движение."""

from __future__ import annotations

import random
from dataclasses import dataclass
from typing import List, Optional

import pygame

import settings as S


@dataclass
class Alien:
    row: int
    rect: pygame.Rect
    points: int
    color: tuple[int, int, int]
    alive: bool = True


class AlienWave:
    def __init__(self) -> None:
        self.aliens: List[Alien] = []
        self.direction = 1
        self.bombs: List[pygame.Rect] = []
        self.bomb_cd = 120
        self._spawn_grid()

    def _spawn_grid(self) -> None:
        self.aliens.clear()
        for row in range(S.ALIEN_ROWS):
            y = S.ALIEN_TOP + row * (S.ALIEN_H + S.ALIEN_GAP_Y)
            row_width = S.ALIEN_COLS * S.ALIEN_W + (S.ALIEN_COLS - 1) * S.ALIEN_GAP_X
            start_x = (S.WIDTH - row_width) // 2
            for col in range(S.ALIEN_COLS):
                x = start_x + col * (S.ALIEN_W + S.ALIEN_GAP_X)
                self.aliens.append(
                    Alien(
                        row=row,
                        rect=pygame.Rect(x, y, S.ALIEN_W, S.ALIEN_H),
                        points=S.ROW_POINTS[row],
                        color=S.ROW_COLORS[row],
                    )
                )

    def living(self) -> List[Alien]:
        return [a for a in self.aliens if a.alive]

    def speed(self) -> int:
        left = len(self.living())
        return S.ALIEN_H_SPEED + max(0, (S.ALIEN_ROWS * S.ALIEN_COLS - left) // 8)

    def update(self) -> None:
        alive = self.living()
        if not alive:
            return
        edge = any(a.rect.left <= 8 or a.rect.right >= S.WIDTH - 8 for a in alive)
        drop = False
        if edge:
            self.direction *= -1
            drop = True
        spd = self.speed()
        for a in alive:
            a.rect.x += spd * self.direction
            if drop:
                a.rect.y += S.ALIEN_DROP
        self.bomb_cd -= 1
        if self.bomb_cd <= 0:
            bottom_row = max(a.row for a in alive)
            shooters = [a for a in alive if a.row == bottom_row]
            shooter = random.choice(shooters)
            self.bombs.append(pygame.Rect(shooter.rect.centerx - 3, shooter.rect.bottom, 6, 14))
            self.bomb_cd = random.randint(90, 180)
        for bomb in self.bombs[:]:
            bomb.y += S.BOMB_SPEED
            if bomb.top > S.HEIGHT:
                self.bombs.remove(bomb)

    def drop_bombs(self) -> List[pygame.Rect]:
        return list(self.bombs)

    def remove_bomb(self, bomb: pygame.Rect) -> None:
        if bomb in self.bombs:
            self.bombs.remove(bomb)

    def hit_test(self, rect: pygame.Rect) -> Optional[Alien]:
        for alien in self.living():
            if rect.colliderect(alien.rect):
                return alien
        return None

    def cleared(self) -> bool:
        return len(self.living()) == 0

    def reached_player(self, player: pygame.Rect) -> bool:
        alive = self.living()
        if not alive:
            return False
        return max(a.rect.bottom for a in alive) >= player.top - 8

    def draw(self, surface: pygame.Surface) -> None:
        for alien in self.living():
            pygame.draw.rect(surface, alien.color, alien.rect, border_radius=4)
        for bomb in self.bombs:
            pygame.draw.rect(surface, S.BOMB_COLOR, bomb, border_radius=2)