Эрик Мэтиз - Изучаем Python, Alien Invasion, Глава 12, ошибка "Unresolved attribute reference"
Занимаюсь по книге Эрика Мэтиза, код пишу такой же, как показан в примерах. При этом все равно возникают ошибки.
Код основной программы:
import sys
import pygame
from settings import Settings
from ship import Ship
from bullet import Bullet
from alien import Alien
class AlienInvasion: # управление ресурсами и поведением игры
def __init__(self): # создание игровых ресурсов
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().height
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self.screen)
self.bullets = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
self._create_fleet()
def run_game(self):
while True:
self._check_events()
self.ship.update()
self._update_bullets()
self._update_aliens()
self._upgrade_screen()
def _check_events(self):
for event in pygame.event.get(): # отслеживание клавиатуры и мыши
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
def _check_keydown_events(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._fire_bullet()
def _check_keyup_events(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
def _upgrade_screen(self):
self.screen.fill(self.settings.bg_color) # экран перерисовывается
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
pygame.display.flip() # отображение последнего прорисованного экрана
def _fire_bullet(self):
if len(self.bullets) < self.settings.bullets_allowed:
new_bullet = Bullet(self.screen, self.ship)
self.bullets.add(new_bullet)
def _update_bullets(self):
self.bullets.update()
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
def _update_aliens(self):
self.aliens.update()
def _create_fleet(self):
alien = Alien(self)
alien_width, alien_height = alien.rect.size
ship_height = self.ship.rect.height
available_space_x = self.settings.screen_width - (2 * alien_width)
available_space_y = self.settings.screen_height - ship_height - (3 * alien_height)
number_aliens_x = available_space_x // (2 * alien_width)
number_rows = available_space_y // (2 * alien_height)
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
self._create_alien(alien_number, row_number, alien_width, alien_height)
def _create_alien(self, alien_number, row_number, alien_width, alien_height):
alien = Alien(self)
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
alien.rect.y = alien.rect.height + 2 * alien_height * row_number
self.aliens.add(alien)
def _check_fleet_edges(self):
for alien in self.aliens.sprites():
if alien.check_edges():
self.change_fleet_direction()
break
def change_fleet_direction(self):
for alien in self.aliens.sprites():
alien.rect.y += self.settings.fleet_drop_speed
self.settings.fleet_direction *= -1
if __name__ == '__main__':
ai = AlienInvasion()
ai.run_game()
Ошибки возникают в строчках:
if alien.check_edges(): - Unresolved attribute reference 'check_edges' for class 'Sprite'
bullet.draw_bullet() - Unresolved attribute reference 'draw_bullet' for class 'Sprite'
Насколько я понимаю, проблема в том, что у класса Sprite нет методов check_edges() и draw_bullet()
Но, я создавал классы Bullet и Alien в отдельных файлах:
import pygame
from pygame.sprite import Sprite
from settings import Settings
class Bullet(Sprite):
def __init__(self, ai_game, ship):
# создание снаряда в позиции корабля
super().__init__()
self.screen = ai_game
self.settings = Settings()
self.color = self.settings.bullet_color
# Создание снаряда в (0, 0) и назначение правильной позиции
self.rect = pygame.Rect(0, 0, self.settings.bullet_width, self.settings.bullet_height)
self.rect.midtop = ship.rect.midtop
# Позиция снаряда в вещественном формате
self.y = float(self.rect.y)
def update(self):
self.y -= self.settings.bullet_speed
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect)
import pygame
from pygame.sprite import Sprite
from settings import Settings
class Alien(Sprite):
def __init__(self, ai_game):
super().__init__()
self.screen = ai_game
self.settings = Settings()
self.image = pygame.image.load('data/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 update(self):
self.x += (self.settings.alien_speed * self.settings.fleet_direction)
self.rect.x = self.x
def check_edges(self):
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right or self.rect.left <= 0:
return True
Эти классы наследуются от класса Sprite
В основной программе bullet - экземпляр класса Sprite, почему тогда он не видит методов класса-последователя?
Так же я пробовал bullet.Bullet.draw_bullet(), но тоже не помогло - Unresolved attribute reference 'Bullet' for class 'Sprite'
Ответы (2 шт):
если знаешь инглиш, вот ссылка, там у человека такая же проблема и ее решили успешно
def _check_fleet_edges(self):
for alien in self.aliens.sprites():
^^^^^^^^^^
if alien.check_edges():
self.change_fleet_direction()
break
Так зачем вы берёте у aliens спрайты sprites(), если вам нужны объекты Alien и их методы, а не объекты Sprite? Перебирайте просто aliens и всё:
def _check_fleet_edges(self):
for alien in self.aliens:
if alien.check_edges():
self.change_fleet_direction()
break
И с Bullet точно такая же петрушка с ненужными вам спрайтами:
for bullet in self.bullets.sprites():
^^^^^^^^^^
bullet.draw_bullet()
Перебирайте объекты Bullet, в которых и лежат нужные вам свойства:
for bullet in self.bullets:
bullet.draw_bullet()
И для общего развития: наследование в обратную сторону не работает. У Bullet и Alien есть методы и поля из класса-предка Sprite, но не наоборот. У Sprite нет методов и полей, описанных в его наследниках Bullet и Alien.
