Python 项目:外星人入侵--第二部分

外星人入侵

6.驾驶飞船

玩家左右移动飞船,用户按左或右按键时作出响应。

6.1响应按键

  • 当用户在按键时,在python中注册一个事件,事件都是通过方法pygame.event.get()获取的。
  • 在函数check_events()中,需要制定要检查哪些类型的事件,每次按键都被注册为一个KEYDOWN事件
  • 检测到KEYDOWN事件时,需要检查按下的是否是特定的键。
# settings.dy
class Settings():
    '''存储《外星人入侵》的所有设置的类'''
    def __init__(self):
        '''初始化游戏设置'''

        self.screen_width = 1200  # 屏幕设置尺寸
        self.screen_height = 800
        self.bg_color = (230,230,230) # 屏幕背景色
# game_functions.py
# 模块sys用于退出游戏
import sys
import pygame

def check_events(ship):
    '''响应按键和鼠标事件'''
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                # 向右移动飞船
                ship.rect.centerx += 1
def update_screen(ai_settings,screen,ship):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()
# alien_invasion.py
import pygame
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(screen)
    '''开始游戏的主循环'''
    while True:
        '''监视键盘和鼠标事件'''
        gf.check_events(ship)
        '''每次循环时都重绘屏幕'''
        gf.update_screen(ai_settings,screen,ship)
        
run_game()

6.2 允许不断移动

  • 按住右箭头不放时,飞船不断地向右移动,知道松开为止。通过一个名为moving_right的标志来实现持续移动。
  • 飞船不动时,标志moving_right为False,按下右按键时,将这个标志设置为True,玩家松开手时,这个标志重新设置为False
  • 飞船的属性都由Ship类控制,因此给这个类添加moving_right的属性和update()方法,方法update()检查moving_right的状态,如果这个标志为True,调整飞船的位置。
# ship.py
# ship.py
# 创建一个名为ship的模块,包含Ship类,负责管理飞船的大部分行为
import pygame
class Ship():
    def __init__(self,screen): # screen指定飞船绘制到的地方
        '''初始化飞船并设置其初始位置'''
        self.screen = screen
        # 加载飞船图像并获取其它外接矩形
        self.image = pygame.image.load('C:\Study\Python\Project_外星人入侵\images\ship.bmp')
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        #将每艘新飞船放在屏幕底部中央
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        # 移动标志
        self.moving_right = False
    def update(self):
        '''根据移动标志调整飞船的位置'''
        if self.moving_right == True:
            self.rect.centerx += 1
    def blitme(self):
        '''在指定位置绘制飞船'''
        self.screen.blit(self.image,self.rect)
# game_functions.py
# 模块sys用于退出游戏
import sys
import pygame

def check_events(ship):
    '''响应按键和鼠标事件'''
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = True
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = False

def update_screen(ai_settings,screen,ship):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()
# alien_inbasion.py
import pygame
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(screen)
    '''开始游戏的主循环'''
    while True:
        '''监视键盘和鼠标事件'''
        gf.check_events(ship)
        # 根据移动标志调整飞船的位置
        ship.update()
        '''每次循环时都重绘屏幕'''
        gf.update_screen(ai_settings,screen,ship)

run_game()

6.3 左右移动

  • 在ship中增加左右移动的属性,填加通过响应标志,更新飞船响应位置。
  • 在游戏用途模块中填加左右按键,按键和抬起的响应标志。
# ship.py
# 创建一个名为ship的模块,包含Ship类,负责管理飞船的大部分行为
import pygame
class Ship():
    def __init__(self,screen): # screen指定飞船绘制到的地方
        '''初始化飞船并设置其初始位置'''
        self.screen = screen
        # 加载飞船图像并获取其它外接矩形
        self.image = pygame.image.load('C:\Study\Python\Project_外星人入侵\images\ship.bmp')
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        #将每艘新飞船放在屏幕底部中央
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        # 移动标志
        self.moving_right = False
        self.moving_left = False
    def update(self):
        '''根据移动标志调整飞船的位置'''
        if self.moving_right == True:
            self.rect.centerx += 1
        if self.moving_left == True:
            self.rect.centerx -= 1
    def blitme(self):
        '''在指定位置绘制飞船'''
        self.screen.blit(self.image,self.rect)
# game_functions.py
# 模块sys用于退出游戏
import sys
import pygame

def check_events(ship):
    '''响应按键和鼠标事件'''
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = True
            elif event.key == pygame.K_LEFT:
                ship.moving_left = True
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = False
            elif event.key == pygame.K_LEFT:
                ship.moving_left = False

def update_screen(ai_settings,screen,ship):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()
# aline_inbasion.py
import pygame
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(screen)
    '''开始游戏的主循环'''
    while True:
        '''监视键盘和鼠标事件'''
        gf.check_events(ship)
        # 根据移动标志调整飞船的位置
        ship.update()
        '''每次循环时都重绘屏幕'''
        gf.update_screen(ai_settings,screen,ship)

run_game()

6.调整飞船的速度

  • while循环中,飞船移动1像素,在Settings类中添加属性ship_speed_factor,用于控制飞船的速度。
  • 在ship模块中设置x的值,存为小数,根据移动标志调整飞船的位置,此位置通过飞船的center值,来更新rect对象,从而更新飞船的位置。
  • 通过game_functions.py中调用响应按键和鼠标事件及更新屏幕图像函数
  • 最后运行aline.inbasion.py,调用run_game()函数
# settings.py
class Settings():
    '''存储《外星人入侵》的所有设置的类'''
    def __init__(self):
        '''初始化游戏设置'''
        self.screen_width = 1200  # 屏幕设置尺寸
        self.screen_height = 800
        self.bg_color = (230,230,230) # 屏幕背景色
        # 飞船的设置
        self.ship_speed_factor = 1.5
# ship.py
# 创建一个名为ship的模块,包含Ship类,负责管理飞船的大部分行为
import pygame
class Ship():
    def __init__(self,ai_settings,screen): # screen指定飞船绘制到的地方
        '''初始化飞船并设置其初始位置'''
        self.screen = screen
        self.ai_settings = ai_settings
        # 加载飞船图像并获取其它外接矩形
        self.image = pygame.image.load('C:\Study\Python\Project_外星人入侵\images\ship.bmp')
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        #将每艘新飞船放在屏幕底部中央
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        # 在飞船的属性center中存储小数值
        self.center = float(self.rect.centerx)
        # 移动标志
        self.moving_right = False
        self.moving_left = False
    def update(self):
        '''根据移动标志调整飞船的位置'''
        # 更新飞船的center值,而不是rect
        if self.moving_right:
            self.center += self.ai_settings.ship_speed_factor
        if self.moving_left:
            self.center -= self.ai_settings.ship_speed_factor
        # 根据self.center更新rect对象
        self.rect.centerx = self.center

    def blitme(self):
        '''在指定位置绘制飞船'''
        self.screen.blit(self.image,self.rect)
# game_functions.py
# 模块sys用于退出游戏
import sys
import pygame

def check_events(ship):
    '''响应按键和鼠标事件'''
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = True
            elif event.key == pygame.K_LEFT:
                ship.moving_left = True
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = False
            elif event.key == pygame.K_LEFT:
                ship.moving_left = False

def update_screen(ai_settings,screen,ship):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()
# aline_inbasion.py
import pygame
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)
    '''开始游戏的主循环'''
    while True:
        '''监视键盘和鼠标事件'''
        gf.check_events(ship)
        # 根据移动标志调整飞船的位置
        ship.update()
        '''每次循环时都重绘屏幕'''
        gf.update_screen(ai_settings,screen,ship)

run_game()

运行:
左右按键后,飞船速度加快

6.5 限制飞船的活动范围

  • 按住左或右按键时间足够长,飞船将移到屏幕外面,消失的无影无踪。
  • 让飞船达到屏幕边缘后停止移动
  • 修改ship模块update()方法

修改 self.center 的值之前检查飞船的位置。 self.rect.right 返回飞船外接矩形的右边缘的 x 坐标,如果这个值小于 self.screen_rect.right 的值,就说明飞船未触及屏幕右边缘。左边缘的情况与此类似:如果 rect 的左边缘的 x 坐标大于零,就说明飞船未触及屏幕左边缘。这确保仅当飞船在屏幕内时,才调整 self.center 的值。

# ship.py
# 创建一个名为ship的模块,包含Ship类,负责管理飞船的大部分行为
import pygame
class Ship():
    def __init__(self,ai_settings,screen): # screen指定飞船绘制到的地方
        '''初始化飞船并设置其初始位置'''
        self.screen = screen
        self.ai_settings = ai_settings
        # 加载飞船图像并获取其它外接矩形
        self.image = pygame.image.load('C:\Study\Python\Project_外星人入侵\images\ship.bmp')
        self.rect = self.image.get_rect()
        self.screen_rect = screen.get_rect()
        #将每艘新飞船放在屏幕底部中央
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        # 在飞船的属性center中存储小数值
        self.center = float(self.rect.centerx)
        # 移动标志
        self.moving_right = False
        self.moving_left = False
    def update(self):
        '''根据移动标志调整飞船的位置'''
        # 更新飞船的center值,而不是rect
        if self.moving_right and self.rect.right <self.screen_rect.right:
            self.center += self.ai_settings.ship_speed_factor
        if self.moving_left and self.rect.left > 0:
            self.center -= self.ai_settings.ship_speed_factor
            
        # 根据self.center更新rect对象
        self.rect.centerx = self.center

    def blitme(self):
        '''在指定位置绘制飞船'''
        self.screen.blit(self.image,self.rect)

运行:
飞船到达右边缘停止移动,到达左边缘停止移动

6.6 重构check_events()

  • 随着游戏进度函数check_events()将越来越长,拆分函数,一个函数处理KEYDOWN事件,一个处理KEYUP事件
  • 修改game.functions.py模块
# game_functions.py
# 模块sys用于退出游戏
import sys
import pygame

def check_keydown_events(event,ship):
    '''响应按键'''
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True

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(ship):
    '''响应按键和鼠标事件'''
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event,ship)
        elif event.type == pygame.KEYUP:
            check_keyup_events(event,ship)
            
def update_screen(ai_settings,screen,ship):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

7.射击

添加射击功能,将编写玩家按空格时发射子弹(小矩形)的代码。子弹将在屏幕汇总向上穿行,抵达屏幕上边缘后消失。

7.1添加子弹设置

  • 更新settings.py,在方法__init__()末尾存储新类Bullet所需的属性值:
# settings.py
class Settings():
    '''存储《外星人入侵》的所有设置的类'''
    def __init__(self):
        '''初始化游戏设置'''
        self.screen_width = 1200  # 屏幕设置尺寸
        self.screen_height = 800
        self.bg_color = (230,230,230) # 屏幕背景色
        # 飞船的设置
        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

7.2创建Bullet类

  • Bullet类继承模块pygame.sprite中导入的Sprite类,通过使用精灵,可将游戏中相关的元素编组,进而同时操作编组中的所有元素。
  • 为创建子弹实例,需要向__init__()传递ai_settings、screen和ship,还调用了super()来继承Sprite
  • 创建子弹的属性rect,子弹并非基于图像的,使用pygame.Rect()类从空白开始创建一个矩形,创建这个类的实例时,必须提供左上角的x、y左边,还有矩形的宽度和高度,在(0,0)处创建矩形,并根据飞船确定子弹的位置。
  • 设置子弹y坐标,微调子弹的速度。子弹向上移动,y逐渐减小。
  • 调用该函数draw_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)
        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.screem,self.color,self.rect)

7.3 将子弹存储到编组中

  • 玩家每次按空格键时发出一发子弹。
  • 在alien_invasion.py中创建一个编组(group),用于存储有效的子弹,以便能够管理发射出去的所有子弹。该编组将是pygame.sprite.Group类的一个实例bullets;pygame.sprite.Group类类似于列表。
  • bullets传递给检查按键,更新屏幕,在check_events()中,玩家按空格键处理bullets,在update_screen()中更新要绘制到屏幕上的bullets。
  • 对编组调用update()时,编组将自动对其中每个精灵调用update(),所以bullets.update()将为编组bullets中的每颗子弹调用bullet.update()
# aline_inbasion.py
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()

    '''开始游戏的主循环'''
    while True:
        '''监视键盘和鼠标事件'''
        gf.check_events(ai_settings,screen,ship,bullets)
        # 根据移动标志调整飞船的位置
        ship.update()
        bullets.update()
        '''每次循环时都重绘屏幕'''
        gf.update_screen(ai_settings,screen,ship,bullets)

run_game()

7.4 开火

  • 修改check_keydown_events(),以便玩家按空格键时发射一颗子弹
  • 修改update_screen(),确保调用flip()前在屏幕上重绘每颗子弹
  • 编组bulltes传递给监听按键事件函数,玩家按空格键,创建一个子弹,名为new_bullet的Bullet实例,并使用add()将其加入到编组bullets中。
  • 检测按键函数传递了形参bullets中,调用具体按键按下函数,也需要将实参bullets传递给它
  • 方法bullets.sprites()返回一个列表,包含编组bullets中的所有精灵,需要遍历bullets中的精灵才能在屏幕上绘制所有子弹。
# game_functions.py
# 模块sys用于退出游戏
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:
        '''创建一颗子弹,并将其加入到编组bullets中'''
        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,bullets):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色

    '''在飞船和外星人后面重绘所有子弹'''
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

运行:
在这里插入图片描述

7.5 删除已消失的子弹

  • 子弹抵达屏幕顶端后消失,因Pygame无法在屏幕外面绘制它们,y坐标为负数,且越来越小,将消耗内存
  • 需删除消失的子弹,否则游戏变得越来越慢。
  • for循环中不应从列表或编组删除中删除条目,因此必须遍历编组的副本,使用方法copy()来复制为副本,若子弹底端值小于屏幕垂直坐标0,确认子弹消失,使用方法remove()删除编组中的元素。
# aline_inbasion.py
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()

    '''开始游戏的主循环'''
    while True:
        '''监视键盘和鼠标事件'''
        gf.check_events(ai_settings,screen,ship,bullets)
        # 根据移动标志调整飞船的位置
        ship.update()
        bullets.update()

        '''删除已消失的子弹'''
        for bullet in bullets.copy():
            if bullet.rect.bottom <= 0:
                bullets.remove(bullet)
            print(len(bullets))
        '''每次循环时都重绘屏幕'''
        gf.update_screen(ai_settings,screen,ship,bullets)

run_game()

运行:
子弹到达屏幕顶端,将被移除,终端显示剩余子弹数量

7.6 限制子弹数量

  • 限制子弹数量,以鼓励玩家有效地射击目标
  • 在settings中增加能在编组中存储最大子弹数量。
  • 在按键响应添加判断函数,是否达到子弹数量最大范围。
# settings.py
class Settings():
    '''存储《外星人入侵》的所有设置的类'''
    def __init__(self):
        '''初始化游戏设置'''
        self.screen_width = 1200  # 屏幕设置尺寸
        self.screen_height = 800
        self.bg_color = (230,230,230) # 屏幕背景色
        # 飞船的设置
        self.ship_speed_factor = 1.5

        '''子弹的设置'''
        self.bullet_speed_factor = 0.5
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = 60,60,60
        self.bullets_allowed = 3  # 增加编组中子弹最大数量限制
# game_functions.py
# 模块sys用于退出游戏
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:
        '''创建一颗子弹,并将其加入到编组bullets中'''
        if len(bullets) < ai_settings.bullets_allowed:
            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,bullets):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色

    '''在飞船和外星人后面重绘所有子弹'''
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

运行:
在这里插入图片描述

7.7 创建函数update_bullets()

  • 为使主程序文件alien_invasion.py尽可能简单,可将子弹管理代码存放至update_bullets()函数中
# game_functions.py
# 模块sys用于退出游戏
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:
        '''创建一颗子弹,并将其加入到编组bullets中'''
        if len(bullets) < ai_settings.bullets_allowed:
            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,bullets):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色
    '''在飞船和外星人后面重绘所有子弹'''
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

def update_bullets(bullets):
    '''更新子弹的位置,并删除已消失的子弹'''
    # 更新子弹的位置
    bullets.update()
    # 删除已消失的子弹
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
        print(len(bullets))
# aline_inbasion.py
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()

    '''开始游戏的主循环'''
    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()

7.8 创建函数fire_bullet()

  • 将发射子弹的代码移到一个独立的函数中,这样简化按下键响应函数中。
# game_functions.py
# 模块sys用于退出游戏
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 fire_bullet(ai_settings,screen,ship,bullets):
    '''创建新子弹,并将其加入到编组bullets中'''
    # 如果还没有到达限制,就发射一颗子弹'
    if len(bullets) < ai_settings.bullets_allowed:
        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,bullets):
    '''更新屏幕上的图像'''
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    # 调用方法screen.fill()用背景色填充屏幕,这个方法只接受一个实参:一种颜色
    '''在飞船和外星人后面重绘所有子弹'''
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    ship.blitme()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

def update_bullets(bullets):
    '''更新子弹的位置,并删除已消失的子弹'''
    # 更新子弹的位置
    bullets.update()
    # 删除已消失的子弹
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
        print(len(bullets))
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YEGE学AI算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值