python新手自学者,跟着教材敲外星人入侵的时候遇到点问题,希望各位大佬解答

问题描述

当我跟着课本敲到创建外星人群部分时,在game_functions.py模块的update_screen函数中,发现课本上虽然在Alien类中定义了方法blitme用于在屏幕上绘制外星人,但是绘制外星人编组aliens时,使用的语句却是aliens.draw(screen)而非aliens.blitme(),我尝试改成aliens.blitme()运行会报错,请问这是为什么?

aliens编组中每个元素都是使用Alien类创建的一个实例,正常来说aliens.blitme()不是应该可以对aliens编组中的每个元素调用Alien类中的blitme方法完成绘制吗?

因为与此类似的,在创建飞船子弹的时候,bullets同样为一系列Bullet实例构成的编组,就可以通过bullets.update()语句调用Bullet中的update方法。这两种情况不应该是一回事吗,为啥后者可以成功运行前者就会报错呢?

问题出现的环境背景及自己尝试过哪些方法

教材《Python编程入门到实践》

相关代码

1.主程序:

import pygame
from pygame.sprite import Group

from settings import  Settings
from ship import Ship
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("外星人大战")

    #创建一艘飞船
    ship=Ship(ai_settings,screen)
    #创建一个用于存储子弹的编组
    bullets=Group()
    #创建一个外星人编组
    aliens=Group()

    #创建外星人群
    gf.create_fleet(ai_settings,screen,aliens)

    #开始游戏的主循环
    while True:
        gf.check_events(ai_settings,screen,ship,bullets)
        ship.update()
        gf.update_bullets(bullets)
        gf.update_screen(ai_settings,screen,ship,aliens,bullets)

run_game()

2.按键及事件逻辑game_functions.py

import sys

import pygame
from bullet import Bullet
from alien import  Alien

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 fire_bullet(ai_settings,screen,ship,bullets):
    """如果还没有达到限制,就发射一颗子弹"""
    #创建新子弹,并将其加入到编组bullets中
    if len(bullets)<ai_settings.bullet_number:
        new_bullet=Bullet(ai_settings,screen,ship)
        bullets.add(new_bullet)

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_events(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,bullets):
    """更新屏幕上的图像,并切换到新屏幕"""
    #每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    #在飞船和外星人后面重绘所有的子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    aliens.blitme()

    # 让最近绘制的屏幕可见
    pygame.display.flip()

def update_bullets(bullets):
    """"更新子弹的位置,并删除已消失的子弹"""
    #更新子弹位置
    bullets.update()

    #删除已消失的子弹
    for bullet in bullets:
        if bullet.rect.bottom<=0:
            bullets.remove(bullet)

def create_fleet(ai_settings,screen,aliens):
    """创建外星人群"""
    #创建一个外星人,并计算一行可容纳多少个外星人
    #外星人间距为外星人宽度
    alien=Alien(ai_settings,screen)
    alien_width=alien.rect.width
    available_space_x=ai_settings.screen_width-2*alien_width
    number_aliens_x= int(available_space_x/(2*alien_width))

    #创建第一行外星人
    for alien_number in range(number_aliens_x):
        alien=Alien(ai_settings,screen)
        alien.x=alien_width+alien_number*2*alien_width
        alien.rect.x=alien.x
        aliens.add(alien)

3.外星人相关设置alien.py

import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
    """表示单个外星人的类"""

    def __init__(self,ai_settings,screen):
        super(Alien, self).__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 blitme(self):
        """在指定位置绘制外星人"""
        self.screen.blit(self.image,self.rect)

4.子弹相关设置bullet.py

import pygame
from  pygame.sprite import Sprite

class Bullet(Sprite):
    """一个对飞船发射的子弹进行管理的类"""

    def __init__(self,ai_settings,screen,ship):
        """在飞船所处位置创建一个子弹对象 """
        super().__init__()
        self.screen=screen

        #在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
        self.rect=pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
        self.rect.centerx=ship.rect.centerx
        self.rect.top=ship.rect.top

        #储存用小数表示的子弹位置
        self.y=float(self.rect.y)

        self.color=ai_settings.bullet_color
        self.speed_factor=ai_settings.bullet_speed_factor

    def update(self):
        """向上移动子弹"""
        #更新表示子单位置的小数值
        self.y -= self.speed_factor
        self.rect.y=self.y

    def draw_bullet(self):
        """在屏幕上绘制子弹"""
        pygame.draw.rect(self.screen,self.color,self.rect)

你期待的结果是什么?实际看到的错误信息又是什么?

报错信息:

Traceback (most recent call last):
  File "D:\PycharmProjects\alien_invasion\alien_invasion.py", line 32, in <module>
    run_game()
  File "D:\PycharmProjects\alien_invasion\alien_invasion.py", line 30, in run_game
    gf.update_screen(ai_settings,screen,ship,aliens,bullets)
  File "D:\PycharmProjects\alien_invasion\game_functions.py", line 52, in update_screen
    aliens.blitme()
AttributeError: 'Group' object has no attribute 'blitme'
阅读 2.7k
1 个回答

逻辑取决于是否定义相应的方法与具体的实现, 而不是想当然, 在本例中,
Bullet类的update()只是更新位置数据, 绘制是draw_bullet(), 能不能像bullets.update()一样使用aliens.blitme()取决于Group类中有没有定义blitme()及是否有与Group的update()类似的逻辑.

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题