在settings模块中更新子弹设置
settings.py
class Settings:
'''存储所有设置'''
def __init__(self):
'''初始化游戏设置'''
# 屏幕设置
self.screen_width = 1200 # 窗口宽度为1200像素
self.screen_height = 800 # 窗口高度为800像素
self.bg_color = (230,230,230) # 创建名为bu_color的背景色 以RGB值为参数指定
# 飞船设置
self.ship_speed_factor = 1.5 # 飞船速度设置
# 子弹设置
self.bullet_speed_factor = 1 # 子弹速度
self.bullet_width = 3 # 子弹大小
self.bullet_height = 15
self.bullet_color = 60,60,60 # 子弹颜色
self.bullet_allowed = 3 # 同屏最大子弹数
创建储存Bullet类的模块bullet,其中包含Bullet类的属性及方法
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)
# pygame.Rect(lefe,top,width,height)
# left指矩形到左边界距离,top指矩形到上边界距离
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
# 更新表示子弹的rect的位置
self.rect.y = self.y
def draw_bullet(self):
'''在频幕上绘制子弹'''
pygame.draw.rect(self.screen,self.color,self.rect)
在game_functions模块中修改发射子弹的相关判定,以及更新将新的子弹加入编组,将超出屏幕的子弹删除等方法
game_functions.py
import sys
import pygame
from bullet import Bullet
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)
def check_keyup_evets(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(0) # 退出游戏 不抛出异常退出
elif event.type == pygame.KEYDOWN: # 按下按钮
check_keydown_events(event,ai_settings,screen,ship,bullets)
elif event.type == pygame.KEYUP: # 松开按钮
check_keyup_evets(event,ship)
def fire_bullet(ai_settings,screen,ship,bullets):
if len(bullets) < ai_settings.bullet_allowed:
new_bullet = Bullet(ai_settings,screen,ship) # 创建一颗新子弹
bullets.add(new_bullet) # 将新子弹存入编组bulllets中
def update_bullets(bullets):
'''更新子弹位置,并删除超出屏幕上边界的子弹'''
# 更新子弹位置
bullets.update()
# 删除超出屏幕上边界的子弹
for bullet in bullets:
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
def update_screen(ai_settings,screen,ship,bullets):
'''更新屏幕上的图像,并切换到新屏幕'''
# 使用背景色填充屏幕
screen.fill(ai_settings.bg_color)
for bullet in bullets.sprites(): # 重绘所有子弹
bullet.draw_bullet()
ship.blitme() # 在背景上绘上飞船
# 让最近绘制的屏幕可见
pygame.display.flip() # 重绘屏幕
最后根据以上修改,对主程序进行更新
alien_invasion.py
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
def run_game():
# 初始化游戏并创建一个屏幕对象
pygame.init() # 初始化背景设置
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height)) #创建名为screen的显示窗口
pygame.display.set_caption("Alien Invasion")
# 创建一艘飞船
ship = Ship(ai_settings,screen)
# 创建一个用于存储子弹的编组
bullets = Group()
# 开始游戏的主循环
while True:
# 监视键盘和鼠标事件
gf.check_events(ai_settings,screen,ship,bullets)
# 飞船更新位置(移动)
ship.update()
# 子弹更新位置,并删除超出屏幕上边界的子弹
gf.update_bullets(bullets)
# 更新屏幕
gf.update_screen(ai_settings,screen,ship,bullets)
run_game()
from pygame.sprite import Sprite
Sprite类是pygame中所定义的类,通过使用它,可以将游戏中相关的元素进行编组。我们创建的Bullet类就是Sprite类的一个子类,目的在于将所有Bullet对象关联起来,便于之后的操作
self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
rect(left, top, width, height) -> Rect
pygame中rect对象的定义方式,除了之前所提到的方法get_rect(),还可以通过直接对矩形的描述来定义。同样的,参数left,top表示矩形左边到左边界的距离,上边到上边界的距离,也可以认为是矩形左上角的x,y坐标(实际上,rect.x与rect.y表示的就是矩形左上角的坐标);参数width,height表示矩形的宽度与高度
pygame.draw.rect(self.screen,self.color,self.rect)
draw.rect(surface, color, rect) -> Rect
draw.rect(surface, color, rect, width=0, border_radius=0, border_radius=-1, border_top_left_radius=-1, border_top_right_radius=-1, border_bottom_left_radius=-1) -> Rect
函数通过确定参数surface,color,rect来将确定的rect填满color画在surface上
bullets = Group()
创建一个存储子弹的编组bullets,本质上是创建一个Group类对象,而Group允许接受一系列Sprite类对象,所以可以接受先前创建的Bullet类(Sprite类子类)的对象,进而将所有的bullet关联起来
bullets.update()
对编组bullets调用方法update()时,相当于对其中每一个Bullet类(Sprite类子类)的对象bullet调用方法update()
bullets.add(new_bullet)
通过方法add()将新创建的Bullet类对象new_bullet加入编组bullets
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
当需要通过循环删除容器中的元素时,我们不应直接从容器中删除,而应该遍历其副本的同时,对容器中元素进行操作