Ошибка: AttributeError: 'Group' object has no attribute 'get_rect'

Изучаю python по книге Эрик Метиз "Изучаем Python". Недавно я задавал похожий вопрос и получил ответ, который частично исправил мой проблемный код, но теперь появилась другая, проблема с которой я несколько дней пытаюсь разобраться, переписывал код из учебника, потом переписал код https://github.com/TitanVA/Metiz/tree/master/AlienInvasion, но все равно выдает это:

Traceback (most recent call last):
  File "c:\python\alien_invasion\alien_invasion.py", line 38, in <module>
    run_game()
    ^^^^^^^^^^
  File "c:\python\alien_invasion\alien_invasion.py", line 35, in run_game
    gf.update_aliens(ai_settings, stats, screen, ship, aliens, bullets)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\python\alien_invasion\game_functions.py", line 135, in update_aliens
    check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets)
  File "c:\python\alien_invasion\game_functions.py", line 156, in check_aliens_bottom
    for alien in aliens.get_rect():
                 ^^^^^^^^^^^^^^^
AttributeError: 'Group' object has no attribute 'get_rect'

Вот полный код: alien_invasion.py

import pygame
from pygame.sprite import Group

from settings import Settings
from ship import Ship
from game_stats import GameStats

import game_functions as gf

def run_game():
    #Инициализирует игру и создает объект экрана
    pygame.init()
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("Alien Invasion")
    #Создание корабля, группы пуль и пришельцев 
    stats = GameStats(ai_settings)
    ship = Ship(ai_settings, screen)
    bullets = Group()
    aliens = Group()
    drops = Group()

    #Создание флота пришельцев
    gf.create_rain(ai_settings, screen, drops)
    gf.create_fleet(ai_settings, screen, ship, aliens)


    #Запуск основного цикла игры
    while True:
        gf.check_ivents(ai_settings, screen, ship, bullets)
        if stats.game_active:
            ship.update()
            gf.update_bullets(ai_settings, screen, ship, aliens, bullets)
            gf.update_drops(ai_settings, screen, drops)
            gf.update_aliens(ai_settings, stats, screen, ship, aliens, bullets)  
        gf.update_screen(ai_settings, screen, ship, aliens, drops, bullets)

run_game()    

game_functions.py

import sys
import pygame

from bullet import Bullet
from alien import Alien
from random import randint
from drops import Drop
from stars import Stars
from time import sleep

def check_keydown_events(event, ai_settings, screen, ship, bullets):
    '''Реагирует на нажатие клавиш'''
    if event.key == pygame.K_RIGHT:
    #Переместить корабль вправо
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        fire_bullet(ai_settings, screen, ship, bullets)
    elif event.key == pygame.K_q:
        sys.exit()

def check_keyup_events(event, ship):
    '''Реагирует на отпускание клавиш'''
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False

def check_ivents(ai_settings, screen, ship, bullets):
    '''Обрабатывает нажатия клавиш и события мыши'''
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event, ai_settings, screen, ship, bullets)
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, ship)

def update_screen(ai_settings, screen, ship, aliens, drops, bullets):
    '''Обновляет изображения на экране и отображает новый экран'''
    screen.fill(ai_settings.bg_color)
    drops.draw(screen)
    ship.blitme()
    aliens.draw(screen)
    #Все пули выводятся спереди изображений корабля и пришельцев
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    #Отображение последнего прорисованного экрана
    pygame.display.flip()

def update_bullets(ai_settings, screen, ship, aliens, bullets):
    '''Обновляет позиции пуль и уничтожает старые пули'''
    #обновление позиции пуль
    bullets.update()
    #Удаление старых пуль, вышедших за край экрана
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    #Проверка попаданий в пришельцев
    #При обнаружении попадания удалить пулю и пришельца
    check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets)

def check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets):
    """ Обработка коллизий пуль с пришельцами. """
    #Удаление пуль и пришельцев, участвующих в коллизиях
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
    if len(aliens) == 0:
        #Уничтожение существующих пуль и создание нового флота
        bullets.empty()
        create_fleet(ai_settings, screen, ship, aliens)

def fire_bullet(ai_settings, screen, ship, bullets):
    '''Выпускает пули, если максимум еще не достигнут'''
    #Создание новой пули и включение ее в группу bullets
    if len(bullets) < ai_settings.bullets_allowed:
        new_bullet = Bullet(ai_settings, screen, ship)
        bullets.add(new_bullet)

def get_number_aliens_x(ai_settings, alien_width):
    """ Вычисляет количество пришельцев в ряду """
    available_space_x = ai_settings.screen_width - 2 * alien_width
    number_aliens_x = int(available_space_x / (2 * alien_width))
    return number_aliens_x

def create_alien(ai_settings, screen, aliens, alien_number, row_number):
    """ Создает пришельца и размещает его в ряду """
    alien = Alien(ai_settings, screen)
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * alien_number
    alien.rect.x = alien.x
    alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
    aliens.add(alien)

def create_fleet(ai_settings, screen, ship, aliens):
    '''Создает флот пришельцев'''
    #Создание пришельца и вычисление количества пришельцев в ряду
    alien = Alien(ai_settings, screen)
    number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)
    number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)
    #Создание первого ряда пришельцев
    for row_number in range(number_rows):
        for alien_number in range(number_aliens_x):
            #Создание пришельца и размещение его в ряду
            create_alien(ai_settings, screen, aliens, alien_number, row_number)

def get_number_rows(ai_settings, ship_height, alien_height):
    """ Определяет количество рядов, помещающихся на экране """
    available_space_y = (ai_settings.screen_height - 
                         (3 * alien_height) - ship_height)
    number_rows = int(available_space_y / (2 * alien_height))
    return number_rows

def check_fleet_edges(ai_settings, aliens):
    """ Реагирует на достижение пришельцем края экрана """
    for alien in aliens.sprites():
        if alien.check_edges():
            change_fleet_direction(ai_settings, aliens)
            break

def change_fleet_direction(ai_settings, aliens):
    """ Опускает весь флот и меняет направление флота """
    for alien in aliens.sprites():
        alien.rect.y += ai_settings.fleet_drop_speed
    ai_settings.fleet_direction *= -1

def update_aliens(ai_settings, stats, screen, ship, aliens, bullets):
    """ Проверяет, достиг ли флот края экрана, 
     после чего обновляет позиции всех пришельцев во флоте """
    check_fleet_edges(ai_settings, aliens)
    aliens.update()
    #Проверка коллизий пришелец-корабль
    if pygame.sprite.spritecollideany(ship, aliens):
        ship_hit(ai_settings, stats, screen, ship, aliens, bullets)
    check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets)

def ship_hit(ai_settings, stats, screen, ship, aliens, bullets):
    """Обрабатывает столкновение корабля с пришельцем"""
    #Уменьшение списков пришельцев и пуль
    if stats.ships_left > 0:
        stats.ships_left -= 1
        #Очистка списков пришельцев и пуль
        aliens.empty()
        bullets.empty()
        #Создание нового флота и размещение корабля в центре
        create_fleet(ai_settings, screen, ship, aliens)
        ship.center_ship()
        #Пауза
        sleep(0.5)
    else:
        stats.game_active = False

def check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets):
    """Проверяет добрались ли пришельцы до нижнего края экрана"""
    screen_rect = screen.get_rect()
    for alien in aliens.get_rect():
        if alien.rect.bottom >= screen_rect.bottom:
            ship_hit(ai_settings, stats, screen, ship, aliens, bullets)
            break

def get_number_drops(ai_settings, drop_height):
    """ Определяет количество рядов, помещающихся на экране """
    available_space_y = (ai_settings.screen_height - 
                         (3 * drop_height) - drop_height)
    number_drop_rows = int(available_space_y / (2 * drop_height))
    return number_drop_rows

def get_number_drop_x(ai_settings, drop_width):
    """ Вычисляет количество капель в ряду """
    available_space_x = ai_settings.screen_width - 2 * drop_width
    number_drop_x = int(available_space_x / (2 * drop_width))
    return number_drop_x

def create_drop(ai_settings, screen, drops, drop_number, row_number):
    """ Создает капли и размещает его в ряду """
    drop = Drop(ai_settings, screen)
    drop_width = drop.rect.width
    drop.x = drop_width + 2 * drop_width * drop_number
    drop.rect.x = drop.x
    drop.rect.y = drop.rect.height + 2 * drop.rect.height * row_number
    drops.add(drop)

def create_rain(ai_settings, screen, drops):
    '''Создает дождь'''
    drop = Drop(ai_settings, screen)
    number_drop_x = get_number_drop_x(ai_settings, drop.rect.width)
    number_drop_rows = get_number_drops(ai_settings, drop.rect.height)
    #Создание первого ряда капель
    for row_number in range(number_drop_rows):
        for drop_number in range(number_drop_x):
            #Создание дождя и размещение его в ряду
            create_drop(ai_settings, screen, drops, drop_number, row_number)

def check_drop_edges(ai_settings, screen, drops):
    """ Проверяет достигнут ли низ """
    flag = False
    for drop in drops.sprites():
        if drop.check_edges():
            change_drop_direction(ai_settings, drops)
            drops.remove(drop)                
            flag = True
    if flag:
        create_rain(ai_settings, screen, drops)
                        
def change_drop_direction(ai_settings, drops):
    """ Капли стекают """
    for drop in drops.sprites():
        drop.rect.y += ai_settings.drop_speed

def update_drops(ai_settings, screen, drops):
    """ Обновляет позиции капель """
    check_drop_edges(ai_settings, screen, drops)
    drops.update(ai_settings)

game_stats.py

class GameStats():
    """ Отслеживание статистики для игры Alien Invasion """
    def __init__(self, ai_settings):
        """Инициализирует статистику"""
        self.ai_settings = ai_settings
        self.reset_stats()
        self.game_active = True

    def reset_stats(self):
        """Инициализирует статистику изменяющуюся в ходе игры"""
        self.ships_left = self.ai_settings.ship_limit

alien.py

import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
    '''Класс представляющий одного пришельца'''
    def __init__(self, ai_settings, screen):
        '''Инициализирует пришельца и задает его начальную позицию'''
        super().__init__()
        self.screen = screen
        self.ai_settings = ai_settings

        #Загрузка изображения пришельца и назначение атрибута rect
        self.image = pygame.image.load('images/alien.bmp')
        self.rect = self.image.get_rect()

        #Каждый новый пришелец появляется в левом верхнем углу экрана
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height
        
        #Сохранение точной позиции пришельца
        self.x = float(self.rect.x)

    def check_edges(self):
        """ Проверяет True, если пришелец находится у края экрана """
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right:
            return True
        elif self.rect.left <= 0:
            return True

    def update(self):
        """ Перемещает пришельца вправо или влево """
        self.x += (self.ai_settings.alien_speed_factor * 
                   self.ai_settings.fleet_direction)
        self.rect.x = self.x

    def blitme(self):
        '''Выводит пришельца в текущем положении'''
        self.screen.blit(self.image, self.rect)   

ship.py

import pygame
from pygame.sprite import Sprite

class Ship(Sprite):

    def __init__(self, ai_settings, screen):
        super().__init__()
        '''Инициализирует корабль и задает его начальную позицию'''
        self.screen = screen
        self.ai_settings = ai_settings

        #Загрузка изображения корабля и получение прямоугольника
        self.image = pygame.image.load('images/ship.bmp')
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()

        #Каждый новый корабль появляется у нижнего края экрана
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        self.center = float(self.rect.centerx)

        #Флаг перемещения
        self.moving_right = False
        self.moving_left = False
   
    def update(self):
        '''Обновляет позицию корабля с учетом флага'''
        #Обновляется атрибут center, не rect
        if self.moving_right and self.rect.right < self.screen_rect.right:
            self.center += self.ai_settings.ship_speed_factor
        if self.moving_left and self.rect.left > 0:
            self.center -= self.ai_settings.ship_speed_factor
        #обновление атрибута rect на основании self.center
        self.rect.centerx = self.center

    def blitme(self):
        '''Рисует корабль в текущей позиции'''
        self.screen.blit(self.image, self.rect)

    def center_ship(self):
        """Размещает корабль в центре нижней стороны"""
        self.center = self.screen_rect.centerx

settings.py

class Settings():
    '''Класс для хранения всех настроек игры'''

    def __init__(self):
        '''Инициализирует настройки игры'''
        self.screen_width = 800
        self.screen_height = 600
        self.bg_color = (230, 230, 230)
        self.ship_speed_factor = 0.9
        self.ship_limit = 3

        #Параметры пули
        self.bullet_speed_factor = 0.9
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = 60, 60, 60
        self.bullets_allowed = 4

        #Настройки пришельцев
        self.alien_speed_factor = 0.7
        self.fleet_drop_speed = 10
        #fleet_direction = 1 обозначает движение вправо; a -1 - влево
        self.fleet_direction = 1

        #Настройки капель
        self.drop_speed = 0.5

Ответы (0 шт):