python代码实践编程“武装飞船”

2022-08-10,,,,

这里写目录标题

    • 12.3 开始游戏项目
      • 12.3.1 创建pygame窗口以及响应用户输入
      • 12.3.2 设置背景颜色
      • 12.3.3 创建设置类
    • 12.4 添加飞船图像
      • 12.4.1 创建Ship类
      • 12.4.2 在屏幕上绘制飞船
    • 12.5 重构:模块game_functions
      • 12.5.1 函数check_events()
      • 12.5.2 函数update_screen()
    • 12.6 驾驶飞船
      • 12.6.1 响应按键
      • 12.6.2 允许不断移动
      • 12.6.3 左右移动
      • 12.6.4 调整飞船的速度
      • 12.6.5 限制飞船的活动范围
      • 12.6.6重构check_events()
    • 12.8 射击
      • 12.8.1 添加子弹设置
      • 12.8.2 创建Bullet类
      • 12.8.3 将子弹存储在编组中
      • 12.8.4 开火
      • 12.8.5 删除消失的子弹
      • 12.8.6 限制子弹数量
      • 12.8.7 创建函数update_bullets()
      • 12.8.4 创建函数fire_bullet()

12.3 开始游戏项目

12.3.1 创建pygame窗口以及响应用户输入

alien_invision.py

import sys    #需要这个模块退出游戏  #sysy.exit()退出游戏

import pygame   #需要这个模块开发游戏有需要的功能

def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    #对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    #在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    #display.set_mode()返回的surface表示整个游戏窗口。
    screen = pygame.display.set_mode((1200, 750))   #里面的宽高可以调整
    pygame.display.set_caption("外星人入侵")

    # 开始游戏的主循环
    while True:

        # 监视键盘和鼠标事件
        #方法pygame.event.get()访问pygame检测到的事件
        #所有键盘和鼠标事件都将促使for循环运行
        for event in pygame.event.get():
            #在循环中,编写一系列if语句检测并相应特定的事件。
            if event.type == pygame.QUIT:
                sys.exit()  # 退出游戏

        # 让最近绘制的屏幕可见
        #在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
        pygame.display.flip()


run_game()

12.3.2 设置背景颜色

alien_invision.py

import sys    #需要这个模块退出游戏  #sysy.exit()退出游戏

import pygame   #需要这个模块开发游戏有需要的功能

def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    #对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    #在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    #display.set_mode()返回的surface表示整个游戏窗口。
    screen = pygame.display.set_mode((1200, 750))   #里面的宽高可以调整
    pygame.display.set_caption("外星人入侵")

    #设置背景颜色,RGB颜色组合
    bg_color = (230, 230, 230)

    # 开始游戏的主循环
    while True:

        # 监视键盘和鼠标事件
        #方法pygame.event.get()访问pygame检测到的事件
        #所有键盘和鼠标事件都将促使for循环运行
        for event in pygame.event.get():
            #在循环中,编写一系列if语句检测并相应特定的事件。
            if event.type == pygame.QUIT:
                sys.exit()  # 退出游戏

        #每次循环时都重绘屏幕
        #调用方法screen.fill(),用背景颜色填充屏幕,这种方法只接受一个实参:一种颜色
        screen.fill(bg_color)    #设置背景颜色

        # 让最近绘制的屏幕可见
        #在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
        pygame.display.flip()


run_game()

12.3.3 创建设置类

alien_invision.py

import sys    #需要这个模块退出游戏  #sysy.exit()退出游戏

import pygame   #需要这个模块开发游戏有需要的功能

from settings import Settings   #导入settings模块中Settings类

def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    #对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    #在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    #display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    #创建实例
    #使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))
    pygame.display.set_caption("外星人入侵")



    # 开始游戏的主循环
    while True:

        # 监视键盘和鼠标事件
        #方法pygame.event.get()访问pygame检测到的事件
        #所有键盘和鼠标事件都将促使for循环运行
        for event in pygame.event.get():
            #在循环中,编写一系列if语句检测并相应特定的事件。
            if event.type == pygame.QUIT:
                sys.exit()  # 退出游戏

        #每次循环时都重绘屏幕
        #调用方法screen.fill(),用背景颜色填充屏幕,这种方法只接受一个实参:一种颜色
        screen.fill(ai_settings.bg_color)    #设置背景颜色,使用ai_settings中的属性bg_color

        # 让最近绘制的屏幕可见
        #在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
        pygame.display.flip()


run_game()

settings.py

class Settings():
    """存储《外星人入侵》的所有设置的类"""
    
    def __init__(self):
        """初始化游戏的设置"""
        #屏幕设置
        self.screen_width = 1200
        self.screen_height = 800
        self.bg_color = (230, 230, 230)

12.4 添加飞船图像

在Python中,原点(0,0)位于屏幕的左上角,向右下角移动时,坐标值将增大。
在1200×800的屏幕上,原点在左上角,坐标(1200,800)在右下角。

12.4.1 创建Ship类

ship.py

import pygame

class Ship():
    # 方法__init__接受两个参数,screen是需要外部输入的参数
    def __init__(self, screen):
        """初始化飞船并设置其初始化位置"""
        self.screen = screen   #外来参数screen赋值给属性

        #加载飞船图像并获取其外接矩形
        #pygame.image.load()加载图片,存储在self.image
        self.image = pygame.image.load('images/ship.bmp')
        #get_rect()获取相应surface的属性rect
        self.rect = self.image.get_rect()      #飞机所在的矩形
        #将表示屏幕的矩形存储在self.screen_rect中
        self.screen_rect = screen.get_rect()   #整个屏幕的矩形

        #将每艘新飞船放在屏幕底部中央
        #将self.rect.centerx(飞船中心的x坐标)设置为表示屏幕的矩形的属性centerx
        self.rect.centerx = self.screen_rect.centerx    #设置飞机所在矩形到中央
        #将self.rect.bottom(飞船下边缘的y坐标)设置为表示屏幕的矩形的属性bottom
        self.rect.bottom = self.screen_rect.bottom      #设置飞机所在矩形到底部

    # 定义blitme()方法,它根据self.rect指定的位置将图像绘制到屏幕上
    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)    #两个参数,飞机图片、飞机所在的矩形

12.4.2 在屏幕上绘制飞船

alien_invision.py

import sys    #需要这个模块退出游戏  #sysy.exit()退出游戏

import pygame   #需要这个模块开发游戏有需要的功能

from settings import Settings   #导入settings模块中Settings类
from ship import Ship           #导入ship模块中Ship类


def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    #对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    #在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    #display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    #创建实例
    #使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  #赋值给screen
    pygame.display.set_caption("外星人入侵")

    #创建一艘飞船
    ship = Ship(screen)    #创建名为ship的Ship实例,实参为前面的screen

    # 开始游戏的主循环
    while True:

        # 监视键盘和鼠标事件
        #方法pygame.event.get()访问pygame检测到的事件
        #所有键盘和鼠标事件都将促使for循环运行
        for event in pygame.event.get():
            #在循环中,编写一系列if语句检测并相应特定的事件。
            if event.type == pygame.QUIT:
                sys.exit()  # 退出游戏

        #每次循环时都重绘屏幕
        #调用方法screen.fill(),用背景颜色填充屏幕,这种方法只接受一个实参:一种颜色
        screen.fill(ai_settings.bg_color)   #设置背景颜色,使用ai_settings中的属性bg_color
        ship.blitme()   #调用,创建实例

        # 让最近绘制的屏幕可见
        #在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
        pygame.display.flip()


run_game()

12.5 重构:模块game_functions

旨在简化既有代码的结构,使其更容易扩展。
实际的开发过程,一开始将代码编写的尽可能简单,并在项目越来越复杂时进行重构。

12.5.1 函数check_events()

game_functions.py

import sys

import pygame

def check_events():
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

alien_invision.py

import pygame   #需要这个模块开发游戏有需要的功能

from settings import Settings   #导入settings模块中Settings类
from ship import Ship           #导入ship模块中Ship类
import game_functions as gf     #导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    #对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    #在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    #display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    #创建实例
    #使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  #赋值给screen
    pygame.display.set_caption("外星人入侵")

    #创建一艘飞船
    ship = Ship(screen)    #创建名为ship的Ship实例,实参为前面的screen

    # 开始游戏的主循环
    while True:
        gf.check_events()     #调用gf模块中的方法check_events()

        #每次循环时都重绘屏幕
        #调用方法screen.fill(),用背景颜色填充屏幕,这种方法只接受一个实参:一种颜色
        screen.fill(ai_settings.bg_color)   #设置背景颜色,使用ai_settings中的属性bg_color
        ship.blitme()   #调用,创建实例

        # 让最近绘制的屏幕可见
        #在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
        pygame.display.flip()


run_game()

12.5.2 函数update_screen()

game_functions.py

import sys

import pygame

def check_events():
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

def update_screen(ai_settings, screen, ship):   #三个参数
    """更新屏幕上的图像,并切换到新屏幕"""
    # 每次循环时都重绘屏幕
    # 调用方法screen.fill(),用背景颜色填充屏幕,这种方法只接受一个实参:一种颜色
    # 设置背景颜色,使用ai_settings中的属性bg_color,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中
    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    pygame.display.flip()

alien_invision.py

import pygame   #需要这个模块开发游戏有需要的功能

from settings import Settings   #导入settings模块中Settings类
from ship import Ship           #导入ship模块中Ship类
import game_functions as gf     #导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    #对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    #在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    #display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    #创建实例
    #使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  #赋值给screen
    pygame.display.set_caption("外星人入侵")

    #创建一艘飞船
    ship = Ship(screen)    #创建名为ship的Ship实例,实参为前面的screen

    # 开始游戏的主循环
    while True:
        gf.check_events()     #调用gf模块中的方法check_events()
        # 调用gf模块中的方法update_screen(),三个参数
        gf.update_screen(ai_settings, screen, ship)

run_game()

12.6 驾驶飞船

1、左右移动飞船,按左键或右键能及时作出响应
2、首先专注于向右移动,用同样的原理控制向左

12.6.1 响应按键

game_functions.py

import sys

import pygame

def check_events(ship):   #加了ship参数
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

        elif event.type == pygame.KEYDOWN:   #每次按键都被注册为一个KEYDOWN事件
            if event.key == pygame.K_RIGHT:  #如果按下的是右键
                # 向右移动飞船
                ship.rect.centerx += 1       #x坐标加1



def update_screen(ai_settings, screen, ship):   #三个参数
    """更新屏幕上的图像,并切换到新屏幕"""
    # 每次循环时都重绘屏幕
    # 调用方法screen.fill(),用背景颜色填充屏幕,这种方法只接受一个实参:一种颜色
    # 设置背景颜色,使用ai_settings中的属性bg_color,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中
    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    pygame.display.flip()

alien_invision.py

import pygame   #需要这个模块开发游戏有需要的功能

from settings import Settings   #导入settings模块中Settings类
from ship import Ship           #导入ship模块中Ship类
import game_functions as gf     #导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    #对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    #在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    #display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    #创建实例
    #使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  #赋值给screen
    pygame.display.set_caption("外星人入侵")

    #创建一艘飞船
    ship = Ship(screen)    #创建名为ship的Ship实例,实参为前面的screen

    # 开始游戏的主循环
    while True:
        gf.check_events(ship)     #调用gf模块中的方法check_events(),ship为飞船
        # 调用gf模块中的方法update_screen(),三个参数
        gf.update_screen(ai_settings, screen, ship)

run_game()

12.6.2 允许不断移动

1、按住右键不放能不断移动

ship.py

import pygame

class Ship():
    # 方法__init__接受两个参数,screen是需要外部输入的参数
    def __init__(self, screen):
        """初始化飞船并设置其初始化位置"""
        self.screen = screen   #外来参数screen赋值给属性

        #加载飞船图像并获取其外接矩形
        #pygame.image.load()加载图片,存储在self.image
        self.image = pygame.image.load('images/ship.bmp')
        #get_rect()获取相应surface的属性rect
        self.rect = self.image.get_rect()      #飞机所在的矩形
        #将表示屏幕的矩形存储在self.screen_rect中
        self.screen_rect = screen.get_rect()   #整个屏幕的矩形

        #将每艘新飞船放在屏幕底部中央
        #将self.rect.centerx(飞船中心的x坐标)设置为表示屏幕的矩形的属性centerx
        self.rect.centerx = self.screen_rect.centerx    #设置飞机所在矩形到中央
        #将self.rect.bottom(飞船下边缘的y坐标)设置为表示屏幕的矩形的属性bottom
        self.rect.bottom = self.screen_rect.bottom      #设置飞机所在矩形到底部

        #移动标志
        self.moving_right = False    #添加属性self.moving_right,初始值设置为False

    def update(self):
        """根据移动标志调整飞船的位置"""
        if self.moving_right:        #为True时
            self.rect.centerx += 1

    # 定义blitme()方法,它根据self.rect指定的位置将图像绘制到屏幕上
    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)    #两个参数,飞机图片、飞机所在的矩形

game_functions.py

import sys

import pygame

def check_events(ship):   #加了ship参数
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

        # 每次按键都被注册为一个KEYDOWN事件
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:  #如果按下的是右键,按下一直为True
                # 向右移动飞船
                ship.moving_right = True     #x坐标加1,ship在主函数实例,最终在ship.py

        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,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中
    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    pygame.display.flip()

alien_invision.py

import pygame   #需要这个模块开发游戏有需要的功能

from settings import Settings   #导入settings模块中Settings类
from ship import Ship           #导入ship模块中Ship类
import game_functions as gf     #导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    #对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    #在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    #display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    #创建实例
    #使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  #赋值给screen
    pygame.display.set_caption("外星人入侵")

    #创建一艘飞船
    ship = Ship(screen)    #创建名为ship的Ship实例,实参为前面的screen

    # 开始游戏的主循环
    while True:
        gf.check_events(ship)     #调用gf模块中的方法check_events(),ship为飞船
        ship.update()
        # 调用gf模块中的方法update_screen(),三个参数
        gf.update_screen(ai_settings, screen, ship)

run_game()

12.6.3 左右移动

ship.py

import pygame

class Ship():
    # 方法__init__接受两个参数,screen是需要外部输入的参数
    def __init__(self, screen):
        """初始化飞船并设置其初始化位置"""
        self.screen = screen   # 外来参数screen赋值给属性

        # 加载飞船图像并获取其外接矩形
        # pygame.image.load()加载图片,存储在self.image
        self.image = pygame.image.load('images/ship.bmp')
        # get_rect()获取相应surface的属性rect
        self.rect = self.image.get_rect()      # 飞机所在的矩形
        # 将表示屏幕的矩形存储在self.screen_rect中
        self.screen_rect = screen.get_rect()   # 整个屏幕的矩形

        # 将每艘新飞船放在屏幕底部中央
        # 将self.rect.centerx(飞船中心的x坐标)设置为表示屏幕的矩形的属性centerx
        self.rect.centerx = self.screen_rect.centerx    # 设置飞机所在矩形到中央
        # 将self.rect.bottom(飞船下边缘的y坐标)设置为表示屏幕的矩形的属性bottom
        self.rect.bottom = self.screen_rect.bottom      # 设置飞机所在矩形到底部

        # 移动标志
        self.moving_right = False    # 添加属性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

    # 定义blitme()方法,它根据self.rect指定的位置将图像绘制到屏幕上
    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)    # 两个参数,飞机图片、飞机所在的矩形

game_functions.py

import sys

import pygame

def check_events(ship):   # 加了ship参数
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

        # 每次按键都被注册为一个KEYDOWN事件
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:    # 如果按下的是右键,按下一直为True
                # 向右移动飞船
                ship.moving_right = True       # x坐标加1,ship在主函数实例,最终在ship.py
            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,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中
    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    pygame.display.flip()

alien_invision.py

import pygame   # 需要这个模块开发游戏有需要的功能

from settings import Settings   # 导入settings模块中Settings类
from ship import Ship           # 导入ship模块中Ship类
import game_functions as gf     # 导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    # 对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    # 在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    # display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    # 创建实例
    # 使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  # 赋值给screen
    pygame.display.set_caption("外星人入侵")

    # 创建一艘飞船
    ship = Ship(screen)    # 创建名为ship的Ship实例,实参为前面的screen

    # 开始游戏的主循环
    while True:
        gf.check_events(ship)     # 调用gf模块中的方法check_events(),ship为飞船
        ship.update()
        # 调用gf模块中的方法update_screen(),三个参数
        gf.update_screen(ai_settings, screen, ship)

run_game()

12.6.4 调整飞船的速度

每次执行while循环时,飞船最多移动1像素,这里设置成1.5
settings.py

class Settings():
    """存储《外星人入侵》的所有设置的类"""
    
    def __init__(self):
        """初始化游戏的设置"""
        # 屏幕设置
        self.screen_width = 1200
        self.screen_height = 750
        self.bg_color = (230, 230, 230)

        #飞船的速度
        self.ship_speed_factor = 1.5

ship.py

import pygame

class Ship():
    # 方法__init__接受两个参数,screen是需要外部输入的参数
    def __init__(self, ai_settings, screen):
        """初始化飞船并设置其初始化位置"""
        self.screen = screen   # 外来参数screen赋值给属性
        self.ai_settings = ai_settings   #获得速度设置

        # 加载飞船图像并获取其外接矩形
        # pygame.image.load()加载图片,存储在self.image
        self.image = pygame.image.load('images/ship.bmp')
        # get_rect()获取相应surface的属性rect
        self.rect = self.image.get_rect()      # 飞机所在的矩形
        # 将表示屏幕的矩形存储在self.screen_rect中
        self.screen_rect = screen.get_rect()   # 整个屏幕的矩形

        # 将每艘新飞船放在屏幕底部中央
        # 将self.rect.centerx(飞船中心的x坐标)设置为表示屏幕的矩形的属性centerx
        self.rect.centerx = self.screen_rect.centerx    # 设置飞机所在矩形到中央
        # 将self.rect.bottom(飞船下边缘的y坐标)设置为表示屏幕的矩形的属性bottom
        self.rect.bottom = self.screen_rect.bottom      # 设置飞机所在矩形到底部

        # 在飞船的属性center中存储小数值
        self.center = float(self.rect.centerx)       #转化为小数

        # 移动标志
        self.moving_right = False    # 添加属性self.moving_right,初始值设置为False
        self.moving_left = False

    def update(self):
        """根据移动标志调整飞船的位置"""
        # 更新飞船的center值,而不是rect
        if self.moving_right:        # 为True时
            self.center += self.ai_settings.ship_speed_factor
        if self.moving_left:         # 为True时
            self.center -= self.ai_settings.ship_speed_factor

        #根据self.center更新rect对象
        self.rect.centerx = self.center

    # 定义blitme()方法,它根据self.rect指定的位置将图像绘制到屏幕上
    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)    # 两个参数,飞机图片、飞机所在的矩形

alien_invision.py

import pygame   # 需要这个模块开发游戏有需要的功能

from settings import Settings   # 导入settings模块中Settings类
from ship import Ship           # 导入ship模块中Ship类
import game_functions as gf     # 导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置
    # 创建宽1200像素,高800像素的游戏窗口
    # 对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    # 在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    # display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    # 创建实例
    # 使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  # 赋值给screen
    pygame.display.set_caption("外星人入侵")

    # 创建一艘飞船
    ship = Ship(ai_settings, screen)    # 创建名为ship的Ship实例,实参为前面的screen

    # 开始游戏的主循环
    while True:
        gf.check_events(ship)     # 调用gf模块中的方法check_events(),ship为飞船
        ship.update()
        # 调用gf模块中的方法update_screen(),三个参数
        gf.update_screen(ai_settings, screen, ship)

run_game()

12.6.5 限制飞船的活动范围

玩家按住箭头键的时间朱够长,飞船会到屏幕外面,这里修复这个问题
ship.py

import pygame

class Ship():
    # 方法__init__接受两个参数,screen是需要外部输入的参数
    def __init__(self, ai_settings, screen):
        """初始化飞船并设置其初始化位置"""
        self.screen = screen   # 外来参数screen赋值给属性
        self.ai_settings = ai_settings   #获得速度设置

        # 加载飞船图像并获取其外接矩形
        # pygame.image.load()加载图片,存储在self.image
        self.image = pygame.image.load('images/ship.bmp')
        # get_rect()获取相应surface的属性rect
        self.rect = self.image.get_rect()      # 飞机所在的矩形
        # 将表示屏幕的矩形存储在self.screen_rect中
        self.screen_rect = screen.get_rect()   # 整个屏幕的矩形

        # 将每艘新飞船放在屏幕底部中央
        # 将self.rect.centerx(飞船中心的x坐标)设置为表示屏幕的矩形的属性centerx
        self.rect.centerx = self.screen_rect.centerx    # 设置飞机所在矩形到中央
        # 将self.rect.bottom(飞船下边缘的y坐标)设置为表示屏幕的矩形的属性bottom
        self.rect.bottom = self.screen_rect.bottom      # 设置飞机所在矩形到底部

        # 在飞船的属性center中存储小数值
        self.center = float(self.rect.centerx)       #转化为小数

        # 移动标志
        self.moving_right = False    # 添加属性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:        # 为True时
            self.center += self.ai_settings.ship_speed_factor
        if self.moving_left and self.rect.left > 0:         # 为True时
            self.center -= self.ai_settings.ship_speed_factor

        #根据self.center更新rect对象
        self.rect.centerx = self.center

    # 定义blitme()方法,它根据self.rect指定的位置将图像绘制到屏幕上
    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)    # 两个参数,飞机图片、飞机所在的矩形

12.6.6重构check_events()

函数check_events越来越长,重构,拆出两个
game.functions.py

import sys

import pygame

def check_keydown_events(event, ship):
    """响应按键"""
    if event.key == pygame.K_RIGHT:  # 如果按下的是右键,按下一直为True
        # 向右移动飞船
        ship.moving_right = True  # x坐标加1,ship在主函数实例,最终在ship.py
    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):   # 加了ship参数
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

        # 每次按键都被注册为一个KEYDOWN事件
        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,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中
    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    pygame.display.flip()

12.8 射击

12.8.1 添加子弹设置

settings.py

class Settings():
    """存储《外星人入侵》的所有设置的类"""
    
    def __init__(self):
        """初始化游戏的设置"""
        # 屏幕设置
        self.screen_width = 1200
        self.screen_height = 750
        self.bg_color = (230, 230, 230)
        
        #子弹设置
        self.bullet_speed_factor = 1   #速度比飞船低,飞船1.5
        self.bullet_width = 3       #宽3像素
        self.bullet_height = 15     #高15像素
        self.bullet_color = 60, 60, 60    #深灰色子弹

        #飞船的速度
        self.ship_speed_factor = 1.5

12.8.2 创建Bullet类

import pygame
from pygame.sprite import Sprite

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

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

        # 在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
        self.rect = pygame.Rect(0, 0, ai_settings.bullet_width,
                                ai_settings.bullet_height)
        # 子弹的renterx设置为飞船的rect.centerx
        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   # 向上移动,y坐标不断减少
        # 更新表示子弹的rect的位置
        self.rect.y = self.y

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

12.8.3 将子弹存储在编组中

alien_invision.py

import pygame   # 需要这个模块开发游戏有需要的功能
from pygame.sprite import Group  # 导入pygame.sprite中的Group类

from settings import Settings   # 导入settings模块中Settings类
from ship import Ship           # 导入ship模块中Ship类
import game_functions as gf     # 导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置

    # 创建宽1200像素,高800像素的游戏窗口
    # 对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    # 在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    # display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    # 创建实例
    # 使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  # 赋值给screen
    pygame.display.set_caption("外星人入侵")

    # 创建一艘飞船
    ship = Ship(ai_settings, screen)    # 创建名为ship的Ship实例,实参为前面的screen

    # 创建一个用于存储子弹的编组
    bullets = Group()  #创建实例,命名为bullets

    # 开始游戏的主循环
    while True:
        gf.check_events(ai_settings, screen, ship, bullets)     # 调用gf模块中的方法check_events(),ship为飞船
        ship.update()
        bullets.update()
        # 调用gf模块中的方法update_screen(),三个参数
        gf.update_screen(ai_settings, screen, ship, bullets)


run_game()

12.8.4 开火

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:  # 如果按下的是右键,按下一直为True
        # 向右移动飞船
        ship.moving_right = True  # x坐标加1,ship在主函数实例,最终在ship.py
    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):   # 加了ship参数
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

        # 每次按键都被注册为一个KEYDOWN事件
        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,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中

    # 在飞船和外星人后面绘制所有子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()

    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    pygame.display.flip()

12.8.5 删除消失的子弹

子弹到达顶部后消失,只是无法消失屏幕外的子弹,实际上仍然存在,这里我们删除这些子弹
alien_invision.py

import pygame   # 需要这个模块开发游戏有需要的功能
from pygame.sprite import Group  # 导入pygame.sprite中的Group类

from settings import Settings   # 导入settings模块中Settings类
from ship import Ship           # 导入ship模块中Ship类
import game_functions as gf     # 导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置

    # 创建宽1200像素,高800像素的游戏窗口
    # 对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    # 在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    # display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    # 创建实例
    # 使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  # 赋值给screen
    pygame.display.set_caption("外星人入侵")

    # 创建一艘飞船
    ship = Ship(ai_settings, screen)    # 创建名为ship的Ship实例,实参为前面的screen

    # 创建一个用于存储子弹的编组
    bullets = Group()  # 创建实例,命名为bullets

    # 开始游戏的主循环
    while True:
        gf.check_events(ai_settings, screen, ship, bullets)     # 调用gf模块中的方法check_events(),ship为飞船
        ship.update()
        bullets.update()

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

        # 调用gf模块中的方法update_screen(),三个参数
        gf.update_screen(ai_settings, screen, ship, bullets)


run_game()

12.8.6 限制子弹数量

以鼓励玩家有目的的射击
settings.py

class Settings():
    """存储《外星人入侵》的所有设置的类"""
    
    def __init__(self):
        """初始化游戏的设置"""
        # 屏幕设置
        self.screen_width = 1200
        self.screen_height = 750
        self.bg_color = (230, 230, 230)

        # 子弹设置
        self.bullet_speed_factor = 1   # 速度比飞船低,飞船1.5
        self.bullet_width = 3       # 宽3像素
        self.bullet_height = 15     # 高15像素
        self.bullet_color = 60, 60, 60    # 深灰色子弹
        self.bullets_allowed = 3

        # 飞船的速度
        self.ship_speed_factor = 1.5

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:  # 如果按下的是右键,按下一直为True
        # 向右移动飞船
        ship.moving_right = True  # x坐标加1,ship在主函数实例,最终在ship.py
    elif event.key == pygame.K_LEFT:  # 按下左键
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        if len(bullets) < ai_settings.bullets_allowed:
            # 创建一颗子弹,并将其加入到编组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):   # 加了ship参数
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

        # 每次按键都被注册为一个KEYDOWN事件
        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,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中

    # 在飞船和外星人后面绘制所有子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()

    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    pygame.display.flip()

12.8.7 创建函数update_bullets()

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:  # 如果按下的是右键,按下一直为True
        # 向右移动飞船
        ship.moving_right = True  # x坐标加1,ship在主函数实例,最终在ship.py
    elif event.key == pygame.K_LEFT:  # 按下左键
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        if len(bullets) < ai_settings.bullets_allowed:
            # 创建一颗子弹,并将其加入到编组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):   # 加了ship参数
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

        # 每次按键都被注册为一个KEYDOWN事件
        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,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中

    # 在飞船和外星人后面绘制所有子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()

    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    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))

alien_invasion.py

import pygame   # 需要这个模块开发游戏有需要的功能
from pygame.sprite import Group  # 导入pygame.sprite中的Group类

from settings import Settings   # 导入settings模块中Settings类
from ship import Ship           # 导入ship模块中Ship类
import game_functions as gf     # 导入game_functions模块,模块另命名为gf



def run_game():
    # 初始化游戏并创建一个屏幕对象
    pygame.init()  # 初始化背景设置

    # 创建宽1200像素,高800像素的游戏窗口
    # 对象screen是个surface,在pygame中surface只是屏幕的一部分,用于显示游戏元素
    # 在这个游戏中,每个元素(如外星人和飞船)都是一个surface。
    # display.set_mode()返回的surface表示整个游戏窗口。
    ai_settings = Settings()    # 创建实例
    # 使用ai_settings中的属性screen_width和screen_height
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))  # 赋值给screen
    pygame.display.set_caption("外星人入侵")

    # 创建一艘飞船
    ship = Ship(ai_settings, screen)    # 创建名为ship的Ship实例,实参为前面的screen

    # 创建一个用于存储子弹的编组
    bullets = Group()  # 创建实例,命名为bullets

    # 开始游戏的主循环
    while True:
        gf.check_events(ai_settings, screen, ship, bullets)     # 调用gf模块中的方法check_events(),ship为飞船
        ship.update()
        gf.update_bullets(bullets)     # 调用方法

        # 调用gf模块中的方法update_screen(),三个参数
        gf.update_screen(ai_settings, screen, ship, bullets)


run_game()

12.8.4 创建函数fire_bullet()

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:  # 如果按下的是右键,按下一直为True
        # 向右移动飞船
        ship.moving_right = True  # x坐标加1,ship在主函数实例,最终在ship.py
    elif event.key == pygame.K_LEFT:  # 按下左键
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        fire_bullet(ai_settings, screen, ship, bullets)  # 调用下面的,使得elif语句简单


def fire_bullet(ai_settings, screen, ship, bullets):
    """如果还没有达到限制,就发射一颗子弹"""
    if len(bullets) < ai_settings.bullets_allowed:
        # 创建一颗子弹,并将其加入到编组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):   # 加了ship参数
    """响应按键和鼠标事件"""
    # 监视键盘和鼠标事件
    # 方法pygame.event.get()访问pygame检测到的事件
    # 所有键盘和鼠标事件都将促使for循环运行
    for event in pygame.event.get():
        # 在循环中,编写一系列if语句检测并相应特定的事件。
        if event.type == pygame.QUIT:
            sys.exit()  # 退出游戏

        # 每次按键都被注册为一个KEYDOWN事件
        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,在settings模块内
    screen.fill(ai_settings.bg_color)
    # ship为Ship实例,实例的创建在主模块中

    # 在飞船和外星人后面绘制所有子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()

    ship.blitme()  # 调用,创建实例

    # 让最近绘制的屏幕可见
    # 在每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见,不断更新屏幕
    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))

本文地址:https://blog.csdn.net/qq_39236499/article/details/107067392

《python代码实践编程“武装飞船”.doc》

下载本文的Word格式文档,以方便收藏与打印。