继承
# ship继承于Sprite(父类)
class Ship(Sprite):
参考:https://blog.youkuaiyun.com/qq_38787214/article/details/87902291
没有super(A, self).init()时只能调用父类Root的属性
加入super(A, self).init()时调用A的父类Root的属性和方法
Sprites & collide
from pygame.sprite import Sprite
from pygame.sprite import Group
# 继承于Sprite
class Alien(Sprite):
bullets = Group()
# 遍历整个外星人组
for alien in aliens.sprites():
# 删除编组中余下的所有精灵
bullets.empty()
# 删除发生碰撞的子弹和外星人,
# 新增的这行代码遍历编组bullets 中的每颗子弹,再遍历编组aliens 中的每个外星人。每当有子弹和外星人的rect 重叠时,groupcollide() 就在它返回的字典中添加一个键-值对。两个实参True 告诉Pygame删除发生碰撞的子弹和外星人。
collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
# 检测外星人和飞船之间的碰撞
if pygame.sprite.spritecollideany(ship,aliens):
print("ship hit!!!")
collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
if collisions:
for aliens in collisions.values():
stats.score += ai_settings.alien_points * len(aliens)
当有一个个续命的也需要使用sprite
Sprite 下的draw 函数:
说明:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yeTPQNdV-1598948069078)(PYTHON 学习笔记.assets/截屏2020-08-31 下午7.48.34.png)]
具体用法:
def show_score(self):
--snip--
# 绘制飞船,ships继承于Sprite的group
self.ships.draw(self.screen)
blit
ship.blitme()
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
Screen:
设置背景图片
background = pygame.image.load('images/bg.png') # 图片位置
screen.blit(background,(0,0)) #对齐的坐标
暂停
from time import sleep
sleep(0.5)
游戏结束
下面在GameStats 中添加一个作为标志的属性game_active ,以便在玩家的
飞船用完后结束游戏:
game_stats.py
def __init__(self, settings):
--snip--
# 游戏刚启动时处于活动状态 self.game_active = True
game_function.py
def ship_hit(ai_settings, stats, screen, ship, aliens, bullets):
"""响应飞船被外星人撞到"""
if stats.ships_left > 0:
--snip--
else:
# 飞机用完设置成false
stats.game_active = False
在alien_invasion.py中,我们需要确定游戏的哪些部分在任何情况下都应运行,哪些部分仅在游戏处于活动状态时才运行:
按键
game_function.py
def update_screen(ai_settings, screen, stats, ship, aliens, bullets, play_button):
--snip--
# 如果游戏处于非活动状态,就绘制Play按钮,所以一点按钮,状态改变按钮消失
# 为让Play按钮位于其他所有屏幕元素上面,我们在绘制其他所有游戏元素后再绘制这个按钮,然后切换到新屏幕。
if not stats.game_active:
play_button.draw_button()
Button.py
import pygame.font
class Button():
def __init__(self, ai_settings, screen, msg):
"""初始化按钮的属性"""
self.screen = screen
self.screen_rect = screen.get_rect()
# 设置按钮的尺寸和其他属性
self.width, self.height = 200, 50
self.button_color = (0, 255, 0)
self.text_color = (255, 255, 255)
self.font = pygame.font.SysFont(None, 48)
# 创建按钮的rect对象,并使其居中
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.center = self.screen_rect.center
# 按钮的标签只需创建一次
self.prep_msg(msg)
def prep_msg(self, msg):
"""将msg渲染为图像,并使其在按钮上居中"""
# 用font.render() 将存储在msg 中的文本转换为图像,然后将该图像存储在msg_image 中。
# 方法font.render() 还接受一个布尔实参,该实参指定开启还是关闭反锯齿功能(反锯齿让文本的边缘更平滑)
self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
self.msg_image_rect = self.msg_image.get_rect()
self.msg_image_rect.center = self.rect.center
def draw_button(self):
# 绘制一个用颜色填充的按钮,再绘制文本,每个控件都有自己的screen
self.screen.fill(self.button_color, self.rect)
self.screen.blit(self.msg_image, self.msg_image_rect) #blit的参数是image,矩形
def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y):
"""在玩家单击Play按钮时开始新游戏"""
button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
# 当前,Play按钮存在一个问题,那就是即便Play按钮不可见,
# 玩家单击其原来所在的区域时,游戏依然会作出响应。如下设置if 加上not 即可
if button_clicked and not stats.game_active:
# 重置游戏统计信息
play 按下之后要重置分数等
def check_play_button(ai_settings, screen, stats, sb, play_button, ship, aliens, bullets, mouse_x, mouse_y):
"""在玩家单击Play按钮时开始新游戏"""
button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
if button_clicked and not stats.game_active:
# 重置游戏设置
ai_settings.initialize_dynamic_settings()
# 重置记分牌图像
sb.prep_score()
sb.prep_high_score()
sb.prep_level()
鼠标事件
def check_play_button(stats, play_button, mouse_x, mouse_y):
"""在玩家单击Play按钮时开始新游戏"""
if play_button.rect.collidepoint(mouse_x, mouse_y):
stats.game_active = True
def check_events(ai_settings, screen, stats, play_button, ship, bullets):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
--snip--
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos() # 注意这种写法
check_play_button(stats, play_button, mouse_x, mouse_y)
无论玩家单击屏幕的什么地方,Pygame都将检测到一个MOUSEBUTTONDOWN 事件,但我们只想让这个游戏在玩家用鼠标单击Play按钮时作出响应。为此,我们使用 了pygame.mouse.get_pos() ,它返回一个元组,其中包含玩家单击时鼠标的x 和y 坐标,我们将这些值传递给函数check_play_button() ,而这个函 数使用collidepoint() 检查鼠标单击位置是否在Play按钮的rect 内。如果是这样的,我们就将game_active 设置为True ,让游戏就此开始!
隐藏&显示光标
点击play后隐藏,游戏结束后显示光标以进行下一步选择
def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y):
"""在玩家单击Play按钮时开始新游戏"""
button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
if button_clicked and not stats.game_active:
# 隐藏光标
pygame.mouse.set_visible(False)
def ship_hit(ai_settings, stats, screen, ship, aliens, bullets):
"""响应飞船被外星人撞到"""
if stats.ships_left > 0:
--snip--
else:
stats.game_active = False
#显示光标
pygame.mouse.set_visible(True)
提高难度
游戏setting分为静态设置和动态设置
重置参数
一旦是那些动态变化的参量,比如分数,子弹个数,外星人位置,还有游戏速度设置
数字用100,000隔开
def prep_score(self): """将得分转换为渲染的图像"""
❶ rounded_score = int(round(self.stats.score, -1))
❷ score_str = "{:,}".format(rounded_score)
self.score_image = self.font.render(score_str, True, self.text_color,
self.ai_settings.bg_color)
函数round() 通常让小数精确到小数点后多少位,其中小数位数是由第二个实参指定的。然而,如果将第二个实参指定为负数,round() 将圆整到最近的10、100、1000等整 数倍。❶让Python将stats.score 的值圆整到最近的10的整数倍,并将结果存储到rounded_score 中。
注意 在Python 2.7中,round() 总是返回一个小数值,因此我们使用int() 来确保报告的得分为整数。如果你使用的是Python 3,可省略对int() 的调用。
❷处使用了一个字符串格式设置指令,它让Python将数值转换为字符串时在其中插入逗号