出现问题:
应为类型 '_SpriteSupportsGroup | AbstractGroup[_SpriteSupportsGroup | Any] | Iterable[_SpriteSupportsGroup | Any] | Any' (匹配的泛型类型 '_TSprite | AbstractGroup[_TSprite] | Iterable[_TSprite]'),但实际为 'Ship'
一、最底下一行为问题代码
def prep_ship(self):
"""显示还余多少飞船"""
self.ships=Group()
for ship_number in range(self.stats.ships_left):
ship=Ship(self.ai_game)
ship.rect.x=10+ship_number*ship.rect.width
ship.rect.y=10
self.ships.add(ship)
二、与问题相关的模块
1.本模块的完整代码
import pygame.font
from pygame.sprite import Group
from py_03_ship import Ship
class Scoreboard():
"""显示得分信息的类"""
def __init__(self, ai_game):
"""初始化显示得分涉及的属性"""
self.ai_game=ai_game
self.screen = ai_game.screen
self.screen_rect = self.screen.get_rect()
self.settings = ai_game.settings
self.stats = ai_game.stats
# 显示得分信息时使用的字体设置
self.text_color = (30, 30, 30)
self.font = pygame.font.SysFont(None, 48) # 实例化字体对象
# 准备最高分和当前得分的图像
self.prep_score()
self.prep_high_score()
self.prep_level()
self.prep_ship()
def prep_score(self):
"""将得分渲染为图像"""
#精确到小数点后某一位,第二个参数为负数,表示舍入到最近的10的整数倍
rounded_score=round(self.stats.score,-1)
score_str = f'Score:{rounded_score:,}'
self.score_image = self.font.render(score_str, True,
self.text_color, self.settings.bg_color)
#在屏幕的右上角显示得分
self.score_rect=self.score_image.get_rect()
self.score_rect.right=self.screen_rect.right-20
self.score_rect.top=20
def prep_high_score(self):
"""将最高分渲染为图像"""
high_score = round(self.stats.high_score, -1)
high_score_str = f"High Score:{high_score:,}"
self.high_score_image = self.font.render(high_score_str, True,
self.text_color, self.settings.bg_color)
# 将最高分放在屏幕顶部中央
self.high_score_rect = self.high_score_image.get_rect()
self.high_score_rect.centerx = self.screen_rect.centerx
self.high_score_rect.top = self.score_rect.top
def prep_level(self):
"""将等级渲染为图像"""
level_str ='Level:'+str(self.stats.level)
self.level_image = self.font.render(level_str, True,
self.text_color, self.settings.bg_color)
# 将等级放在得分下方
self.level_rect = self.level_image.get_rect()
self.level_rect.right = self.score_rect.right
self.level_rect.top = self.score_rect.bottom+40
def prep_ship(self):
"""显示还余多少飞船"""
self.ships=Group()
for ship_number in range(self.stats.ships_left):
ship=Ship(self.ai_game)
ship.rect.x=10+ship_number*ship.rect.width
ship.rect.y=10
self.ships.add(ship)
def check_high_score(self):
"""检查是否诞生了新的最高分"""
if self.stats.score>self.stats.high_score:
self.stats.high_score=self.stats.score
self.prep_high_score()
def show_score(self):
"""在屏幕上显示得分、等级和余下的飞船数"""
self.screen.blit(self.score_image, self.score_rect)
self.screen.blit(self.high_score_image, self.high_score_rect)
self.screen.blit(self.level_image,self.level_rect)
self.ships.draw(self.screen)#编组的draw方法
2.主代码完整代码
import sys # 退出游戏的模块
import time
import pygame
from py_02_settings import Settings
from py_06_game_stats import GameStats
from py_03_ship import Ship
from py_04_bullet import Bullet
from py_05_alien import Alien
from py_07_button import Button
from py_08_scoreboard import Scoreboard
class AlienInversion:
"""管理游戏资源和行为的类"""
def __init__(self):
"""初始化游戏,并创建游戏资源"""
pygame.init()
self.clock = pygame.time.Clock() # 控制帧率
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
"""
# 指定幕布宽与高
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
# 设置当前窗口的标题栏
pygame.display.set_caption('Alien Invasion')
# 创建一个用于存储游戏统计信息的实例,并创建记分牌
self.stats = GameStats(self)
self.sb = Scoreboard(self)
# 创建飞船实例
self.ship = Ship(self)
self.bullets = pygame.sprite.Group() # 存储子弹的编组
# 创建外星人实例
self.aliens = pygame.sprite.Group() # 存储外星人的编组
self._create_fleet()
# 让游戏一直处于非活动的状态
self.game_active = False
# 创建play按钮
self.play_button = Button(self, 'Play')
def run_game(self):
"""开始游戏的主循环"""
while True:
self._check_events() # 响应按键和鼠标事件
if self.game_active:
self.ship.update() # 根据移动的标志来调整飞船的位置
self._update_bullets() # 更新子弹的位置并删除已消失的子弹
self._update_aliens() # 更新外星人位置
self._update_screen() # 更新屏幕上的图像,并切换到新屏幕
self.clock.tick(60) # 保证循环一次60秒
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_event(event)
elif event.type == pygame.KEYUP:
self._check_keyup_event(event)
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
self._check_play_button(mouse_pos)
def _check_play_button(self, mouse_pos):
"""在玩家单击Play按钮时开始新游戏"""
button_clicked = self.play_button.rect.collidepoint(mouse_pos)
if button_clicked and not self.game_active:
# 还原游戏设置
self.settings.initialize_dynamic_settings()
# 重置游戏的统计信息
self.stats.reset_stats()
self.sb.prep_score() # 分数
self.sb.prep_level()#等级
self.sb.prep_ship()#飞船数
self.game_active = True
# 清空外星人列表和子弹
self.bullets.empty()
self.aliens.empty()
# 创建一个新的外星舰队,并将飞船放在屏幕中央
self._create_fleet()
self.ship.center_ship()
# 隐藏光标
pygame.mouse.set_visible(False)
def _check_keydown_event(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_event(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 _fire_bullet(self):
"""创建一颗子弹,并将其加入bullets编组"""
if len(self.bullets) < self.settings.bullets_allowed:
new_bullet = Bullet(self)
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)
self._check_bullet_alien_collisions()
def _check_bullet_alien_collisions(self):
"""响应子弹和外星人的碰撞"""
# 删除发生碰撞的子弹和外星人,如果发生碰撞,返回字典collisions
collisions = pygame.sprite.groupcollide(
self.bullets, self.aliens, True, True)
if collisions:
# 如果击落,更新得分,保证每个被击落的外星人都计入得分
for aliens in collisions.values():
self.stats.score += self.settings.alien_points * len(aliens)
self.sb.prep_score()
self.sb.check_high_score()
if not self.aliens:
# 删除现有子弹并创建一个新的外星人舰队
self.bullets.empty()
self._create_fleet()
self.settings.inscrease_speed()
#提高等级
self.stats.level+=1
self.sb.prep_level()
def _update_screen(self):
"""更新屏幕上的图像,并切换到新屏幕"""
self.screen.fill(self.settings.bg_color) # 每次循环都重新绘制屏幕,fill()背景色填充
for bullet in self.bullets.sprites():
bullet.draw_bullet() # 子弹绘制到屏幕
self.ship.blitme() # 将飞船绘制到屏幕(没有编组)
self.aliens.draw(self.screen) # 编组的draw方法
# 显示得分
self.sb.show_score()
# 如果游戏处于非活动状态,就绘制Play按钮
if not self.game_active:
self.play_button.draw_button()
pygame.display.flip() # 让最近绘制的屏幕可见
def _create_fleet(self):
"""创建一个外星舰队"""
# 创建一个外星人,再不断地添加,直到没有空间为止;外星人的间距为外星人的宽度
alien = Alien(self)
alien_width, alien_height = alien.rect.size
current_x, current_y = alien_width, alien_height
while current_y < (self.settings.screen_height - 3 * alien_width):
while current_x < (self.settings.screen_width - 2 * alien_width):
self._creat_alien(current_x, current_y)
current_x += 2 * alien_width
# 添加一行外星人后,重置x值,并传递y值
current_x = alien_width
current_y += 2 * alien_height
def _creat_alien(self, x_position, y_position):
"""创建一个外星人,并将其放在当前行中"""
new_alien = Alien(self)
new_alien.x = x_position
new_alien.rect.x = x_position
new_alien.rect.y = y_position
self.aliens.add(new_alien)
def _update_aliens(self):
"""检测是否有外星人位于屏幕边缘,并更新外星舰队的位置"""
self._check_fleet_edges()
self.aliens.update()
# 检测外星人和飞船之间的碰撞
if pygame.sprite.spritecollideany(self.ship, self.aliens):
self._ship_hit()
# 检查是否有外星人到达了屏幕的下边缘
self._check_aliens_bottom()
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
def _ship_hit(self):
"""响应飞船和外星人的碰撞"""
if self.stats.ships_left > 0:
# 将飞船数量减1,并更新积分牌
self.stats.ships_left -= 1
self.sb.prep_ship()
# 清空外星人列表和子弹
self.aliens.empty()
self.bullets.empty()
# 创建一个新的外星舰队,将飞船放在屏幕底部的中央
self._create_fleet()
self.ship.center_ship()
# 暂停
time.sleep(0.5)
else:
self.game_active = False
pygame.mouse.set_visible(True)
def _check_aliens_bottom(self):
"""检查是否有外星人到达了屏幕的下边缘"""
for alien in self.aliens.sprites():
if alien.rect.bottom >= self.settings.screen_height:
# 像飞船被撞到一样处理
self._ship_hit()
break
if __name__ == '__main__':
ai = AlienInversion()
ai.run_game()