# alien_invasion_python **Repository Path**: luming0/alien_invasion_python ## Basic Information - **Project Name**: alien_invasion_python - **Description**: python项目:外星人入侵 - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-07-24 - **Last Updated**: 2025-07-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 外星人入侵 ## 环境准备 ### 安装pygame #### 默认安装python的方式 ```shell # 指定使用当前 Python 解释器自带的 pip 来安装 pygame python3 -m pip install --user pygame ``` 若出现结果`Successfully installed pygame-2.1.3`,则说明pygame这个库已经安装好了。 #### conda安装pygame的方式 ```shell # 使用 pip 安装 pygame 到当前 Conda 环境中 # pip install pygame # 使用 Conda 官方推荐的渠道 conda-forge 来安装 pygame,确保兼容性和环境隔离管理更友好。 conda install -c conda-forge pygame ``` ## 实现过程 ### 创建游戏窗口 创建一个名为alien_invasion.py的文件,并添加以下内容: ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() # 创建游戏窗口 self.screen = pygame.display.set_mode((1200, 800)) # 设置游戏标题 pygame.display.set_caption("Alien Invasion") # 设置背景颜色 self.bg_color = (230, 230, 230) def run_game(self): """开始游戏的主循环""" while True: # 监听键盘和鼠标事件 for event in pygame.event.get(): # 退出游戏(点击窗口关闭按钮时触发) if event.type == pygame.QUIT: sys.exit() # 每次循环时都重绘屏幕 self.screen.fill(self.bg_color) # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` ### 创建设置文件 存储游戏所有设置的类 创建一个名为settings.py的文件,并添加以下内容: ```python class Settings: """存储游戏《外星人入侵》中所有设置的类""" def __init__(self): """初始化游戏静态设置""" self.screen_width = 1200 self.screen_height = 800 # 设置背景颜色 self.bg_color = (230, 230, 230) ``` 修改[alien_invasion.py](alien_invasion.py)文件内容,从settings.py引入设置 ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame # 导入设置类(语法: from 文件名 import 类名) from settings import Settings class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() self.settings = Settings() # 创建游戏窗口 self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) # 设置游戏标题 pygame.display.set_caption("Alien Invasion") def run_game(self): """开始游戏的主循环""" while True: # 监听键盘和鼠标事件 for event in pygame.event.get(): # 退出游戏(点击窗口关闭按钮时触发) if event.type == pygame.QUIT: sys.exit() # 每次循环时都重绘屏幕 self.screen.fill(self.settings.bg_color) # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` ### 添加飞船 创建飞船类ship.py ```python import pygame class Ship: """管理飞船的类""" def __init__(self, ai_game): """初始化飞船并设置其初始位置""" self.screen = ai_game.screen self.screen_rect = ai_game.screen.get_rect() # 加载飞船图像并获取其外接矩形 self.image = pygame.image.load('images/ship.bmp') self.rect = self.image.get_rect() # 对于每个新飞船,都将其放在屏幕底部的中央 self.rect.midbottom = self.screen_rect.midbottom def blitme(self): """在指定位置绘制飞船""" self.screen.blit(self.image, self.rect) ``` 在[alien_invasion.py](alien_invasion.py)中创建飞船 ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame # 导入设置类(语法: from 文件名 import 类名) from settings import Settings from ship import Ship class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() self.settings = Settings() # 创建游戏窗口 self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) # 设置游戏标题 pygame.display.set_caption("Alien Invasion") self.ship = Ship(self) def run_game(self): """开始游戏的主循环""" while True: # 监听键盘和鼠标事件 for event in pygame.event.get(): # 退出游戏(点击窗口关闭按钮时触发) if event.type == pygame.QUIT: sys.exit() # 每次循环时都重绘屏幕 self.screen.fill(self.settings.bg_color) self.ship.blitme() # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` 重构[alien_invasion.py](alien_invasion.py),使代码更加简洁优雅(最终结果与上面一样) ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame # 导入设置类(语法: from 文件名 import 类名) from settings import Settings from ship import Ship class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() self.settings = Settings() # 创建游戏窗口 self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) # 设置游戏标题 pygame.display.set_caption("Alien Invasion") self.ship = Ship(self) def run_game(self): """开始游戏的主循环""" while True: self._check_events() self._check_update_screen() def _check_events(self): """响应按键和鼠标事件(以下划线开头表示方法为私有方法,不能被外部访问)""" # 监听键盘和鼠标事件 for event in pygame.event.get(): # 退出游戏(点击窗口关闭按钮时触发) if event.type == pygame.QUIT: sys.exit() def _check_update_screen(self): """更新屏幕上的图像,并切换到新屏幕""" # 每次循环时都重绘屏幕 self.screen.fill(self.settings.bg_color) self.ship.blitme() # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` ### 添加飞船控制功能 修改settings.py文件,添加速度属性 ```python class Settings: """存储游戏《外星人入侵》中所有设置的类""" def __init__(self): """初始化游戏静态设置""" self.screen_width = 1200 self.screen_height = 800 # 设置背景颜色 self.bg_color = (230, 230, 230) # 飞船移动的速度 self.ship_speed = 0.8 ``` 修改ship.py文件 ```python import pygame class Ship: """管理飞船的类""" def __init__(self, ai_game): """初始化飞船并设置其初始位置""" self.screen = ai_game.screen self.screen_rect = ai_game.screen.get_rect() self.settings = ai_game.settings # 加载飞船图像并获取其外接矩形 self.image = pygame.image.load('images/ship.bmp') self.rect = self.image.get_rect() # 对于每个新飞船,都将其放在屏幕底部的中央 self.rect.midbottom = self.screen_rect.midbottom # 飞船位置的横坐标 self.x = float(self.rect.x) # 表示飞船是否正在向右移动 self.moving_right = False # 表示飞船是否正在向左移动 self.moving_left = False def blitme(self): """在指定位置绘制飞船""" self.screen.blit(self.image, self.rect) def update(self): """根据移动标志调整飞船的位置""" if self.moving_right and self.rect.right < self.screen_rect.right: self.x += self.settings.ship_speed if self.moving_left and self.rect.left > 0: self.x -= self.settings.ship_speed self.rect.x = self.x ``` 修改alien_invasion.py文件 ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame # 导入设置类(语法: from 文件名 import 类名) from settings import Settings from ship import Ship class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() self.settings = Settings() # 创建游戏窗口 self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) # self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height), pygame.FULLSCREEN) # # 获取游戏窗口的宽高 # self.settings.screen_width = self.screen.get_width() # self.settings.screen_height = self.screen.get_height() # 设置游戏标题 pygame.display.set_caption("Alien Invasion") self.ship = Ship(self) def run_game(self): """开始游戏的主循环""" while True: self._check_events() self.ship.update() self._check_update_screen() 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_events(event) elif event.type == pygame.KEYUP: self._check_keyup_events(event) def _check_keydown_events(self, event): """响应按键按下""" if event.key == pygame.K_RIGHT: self.ship.moving_right = True elif event.key == pygame.K_LEFT: self.ship.moving_left = True # 按Q键退出游戏 elif event.key == pygame.K_q: sys.exit() def _check_keyup_events(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 _check_update_screen(self): """更新屏幕上的图像,并切换到新屏幕""" # 每次循环时都重绘屏幕 self.screen.fill(self.settings.bg_color) self.ship.blitme() # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` ### 创建子弹 实现绘制子弹,子弹的发射,删除消失的子弹,控制子弹最大数量 修改settings.py文件,添加子弹的设置 ```python class Settings: """存储游戏《外星人入侵》中所有设置的类""" def __init__(self): """初始化游戏静态设置""" self.screen_width = 1200 self.screen_height = 800 # 设置背景颜色 self.bg_color = (230, 230, 230) # 飞船移动的速度 self.ship_speed = 0.8 # 子弹的设置 self.bullet_speed = 0.7 self.bullet_width = 3 self.bullet_height = 15 self.bullet_color = (60, 60, 60) # 限制子弹最大数量 self.bullets_allowed = 3 ``` 创建bullet.py文件 ```python import pygame # 该类可以帮助我们将多个游戏元素进行编组 from pygame.sprite import Sprite class Bullet(Sprite): """管理飞船所发射的子弹的类""" def __init__(self, ai_game): """在飞船当前位置创建一个子弹对象""" super().__init__() self.screen = ai_game.screen self.settings = ai_game.settings self.color = self.settings.bullet_color # 在(0,0)处创建一个表示子弹的矩形,再设置正确的位置 self.rect = pygame.Rect(0, 0, self.settings.bullet_width, self.settings.bullet_height) # 子弹的初始位置位置在飞船的正上方 self.rect.midtop = ai_game.ship.rect.midtop # 存储用小数表示的子弹位置 self.y = float(self.rect.y) def update(self): """向上移动子弹""" # 更新表示子弹位置的小数值 self.y -= self.settings.bullet_speed # 更新表示子弹的rect的位置 self.rect.y = self.y def draw_bullet(self): """在屏幕上绘制子弹""" pygame.draw.rect(self.screen, self.color, self.rect) ``` 修改[alien_invasion.py](alien_invasion.py)文件,绘制子弹 ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame # 导入设置类(语法: from 文件名 import 类名) from settings import Settings from ship import Ship # 引入子弹类 from bullet import Bullet class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() self.settings = Settings() # 创建游戏窗口 self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) # self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height), pygame.FULLSCREEN) # # 获取游戏窗口的宽高 # self.settings.screen_width = self.screen.get_width() # self.settings.screen_height = self.screen.get_height() # 设置游戏标题 pygame.display.set_caption("Alien Invasion") self.ship = Ship(self) # 创建一个用于存储子弹的编组 self.bullets = pygame.sprite.Group() def run_game(self): """开始游戏的主循环""" while True: self._check_events() self.ship.update() self._update_bullets() self._check_update_screen() 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_events(event) elif event.type == pygame.KEYUP: self._check_keyup_events(event) def _check_keydown_events(self, event): """响应按键按下""" if event.key == pygame.K_RIGHT: self.ship.moving_right = True elif event.key == pygame.K_LEFT: self.ship.moving_left = True # 按Q键退出游戏 elif event.key == pygame.K_q: sys.exit() # 按空格键发射子弹(按下空格就创建一个子弹) elif event.key == pygame.K_SPACE: self._fire_bullet() def _check_keyup_events(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 _check_update_screen(self): """更新屏幕上的图像,并切换到新屏幕""" # 每次循环时都重绘屏幕 self.screen.fill(self.settings.bg_color) self.ship.blitme() # 绘制子弹(绘制子弹组中的每一个子弹) for bullet in self.bullets.sprites(): bullet.draw_bullet() # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() def _update_bullets(self): """所有与子弹相关的代码""" self.bullets.update() # 删除已经消失的子弹(为什么是迭代bullets.copy(),愿意是python的for循环不允许在迭代过程中,迭代长度有改变的,否则会出现错删,或者遗漏) for bullet in self.bullets.copy(): if bullet.rect.bottom <= 0: self.bullets.remove(bullet) # 验证子弹数量 # print(len(self.bullets)) def _fire_bullet(self): """创建一颗子弹,并将其加入编组bullets中""" # 子弹数量小于子弹运行的最大值时,才创建子弹 if len(self.bullets) < self.settings.bullets_allowed: new_bullet = Bullet(self) self.bullets.add(new_bullet) if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` ### 绘制外星人 目标: - 绘制多行外星人 - 设置自动移动:先向右移动,撞到边缘时,向下移动一个行,再向左移动,如此循环。直到外星人全部被消灭,或者玩家输(外星人撞到飞船、外星人到达屏幕底部) 添加外星人相关设置[settings.py](settings.py) ```python class Settings: """存储游戏《外星人入侵》中所有设置的类""" def __init__(self): """初始化游戏静态设置""" self.screen_width = 1200 self.screen_height = 800 # 设置背景颜色 self.bg_color = (230, 230, 230) # 飞船移动的速度 self.ship_speed = 0.8 # 子弹的设置 self.bullet_speed = 0.7 self.bullet_width = 3 self.bullet_height = 15 self.bullet_color = (60, 60, 60) # 限制子弹最大数量 self.bullets_allowed = 3 # 外星人的设置 self.alien_speed = 0.1 self.fleet_drop_speed = 10.0 # fleet_direction为1表示向右移动,为-1表示向左移动(值可以代表速度) self.fleet_direction = 1 ``` 新建外星人类[alien.py](alien.py) ```python import pygame from pygame.sprite import Sprite class Alien(Sprite): def __init__(self, ai_game): """初始化外星人并设置其起始位置""" super().__init__() self.screen = ai_game.screen self.settings = ai_game.settings # 加载外星人图像并获取其外接矩形rect self.image = pygame.image.load('images/alien.bmp') self.rect = self.image.get_rect() # 设置每个外星人的初始位置(既,外星人图片宽高的位置) self.rect.x = self.rect.width self.rect.y = self.rect.height # 存储外星人的精确水平位置,因为rect.x只能存储整数 self.x = float(self.rect.x) def update(self): """向右移动外星人""" # 每次更新的时候,外星人水平位置加一个移动距离 self.x += self.settings.alien_speed * self.settings.fleet_direction self.rect.x = self.x def check_edges(self): """如果外星人位于屏幕边缘,就返回True""" screen_rect = self.screen.get_rect() if self.rect.right >= screen_rect.right or self.rect.left <= 0: return True ``` 在[alien_invasion.py](alien_invasion.py)文件中绘制外星人 ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame # 导入设置类(语法: from 文件名 import 类名) from settings import Settings from ship import Ship # 引入子弹类 from bullet import Bullet # 引入外星人 from alien import Alien class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() self.settings = Settings() # 创建游戏窗口 self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) # self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height), pygame.FULLSCREEN) # # 获取游戏窗口的宽高 # self.settings.screen_width = self.screen.get_width() # self.settings.screen_height = self.screen.get_height() # 设置游戏标题 pygame.display.set_caption("Alien Invasion") self.ship = Ship(self) # 创建一个用于存储子弹的编组 self.bullets = pygame.sprite.Group() # 创建一个外星人编组 self.aliens = pygame.sprite.Group() # 创建一个外星人 self._create_fleet() def run_game(self): """开始游戏的主循环""" while True: self._check_events() self.ship.update() self._update_bullets() self._update_aliens() self._check_update_screen() 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_events(event) elif event.type == pygame.KEYUP: self._check_keyup_events(event) def _check_keydown_events(self, event): """响应按键按下""" if event.key == pygame.K_RIGHT: self.ship.moving_right = True elif event.key == pygame.K_LEFT: self.ship.moving_left = True # 按Q键退出游戏 elif event.key == pygame.K_q: sys.exit() # 按空格键发射子弹(按下空格就创建一个子弹) elif event.key == pygame.K_SPACE: self._fire_bullet() def _check_keyup_events(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 _check_update_screen(self): """更新屏幕上的图像,并切换到新屏幕""" # 每次循环时都重绘屏幕 self.screen.fill(self.settings.bg_color) self.ship.blitme() # 绘制子弹(绘制子弹组中的每一个子弹) for bullet in self.bullets.sprites(): bullet.draw_bullet() # 绘制外星人(draw方法会将编组中每一个元素都依次绘制到屏幕上面) self.aliens.draw(self.screen) # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() def _update_bullets(self): """所有与子弹相关的代码""" self.bullets.update() # 删除已经消失的子弹(为什么是迭代bullets.copy(),愿意是python的for循环不允许在迭代过程中,迭代长度有改变的,否则会出现错删,或者遗漏) for bullet in self.bullets.copy(): if bullet.rect.bottom <= 0: self.bullets.remove(bullet) # 验证子弹数量 # print(len(self.bullets)) def _fire_bullet(self): """创建一颗子弹,并将其加入编组bullets中""" # 子弹数量小于子弹运行的最大值时,才创建子弹 if len(self.bullets) < self.settings.bullets_allowed: new_bullet = Bullet(self) self.bullets.add(new_bullet) def _create_fleet(self): """创建外星人群""" # 创建一个外星人,并计算一行可容纳多少个外星人 alien = Alien(self) alien_width, alien_height = alien.rect.size # 计算外星人可用宽度(屏幕左右两头分别留出一个外星人的宽度) available_space_x = self.settings.screen_width - (2 * alien_width) # 计算外星人横向可放数量(每个外星人之间隔一个外星人),向下取整的整数除法 number_aliens_x = available_space_x // (2 * alien_width) # 计算外星人可用高度(顶部留出一个外星人高度,底部留出两个外星人高度加飞船高度) ship_height = self.ship.rect.height available_space_y = self.settings.screen_height - (3 * alien_height) - ship_height # 计算外星人行数 number_rows = available_space_y // (2 * alien_height) for row_number in range(number_rows): # 创建每一行外星人 for alien_number in range(number_aliens_x): self._create_alien(alien_number, row_number) def _create_alien(self, alien_number, row_number): """创建一行外星人""" alien = Alien(self) alien_width, alien_height = alien.rect.size # 计算当前外星人的位置(留出一个外星人的宽度 + 一个外星人占用的宽度 * 当前机器人index) alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = alien.x alien.rect.y = alien_height + 2 * alien_height * row_number self.aliens.add(alien) def _update_aliens(self): """更新外星人组中所有外星人的位置""" self._check_fleet_edges() self.aliens.update() 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 if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` ### 击杀外星人 ```python collisions = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True) ``` 修改[alien_invasion.py](alien_invasion.py) ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame # 导入设置类(语法: from 文件名 import 类名) from settings import Settings from ship import Ship # 引入子弹类 from bullet import Bullet # 引入外星人 from alien import Alien class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() self.settings = Settings() # 创建游戏窗口 self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) # self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height), pygame.FULLSCREEN) # # 获取游戏窗口的宽高 # self.settings.screen_width = self.screen.get_width() # self.settings.screen_height = self.screen.get_height() # 设置游戏标题 pygame.display.set_caption("Alien Invasion") self.ship = Ship(self) # 创建一个用于存储子弹的编组 self.bullets = pygame.sprite.Group() # 创建一个外星人编组 self.aliens = pygame.sprite.Group() # 创建一个外星人 self._create_fleet() def run_game(self): """开始游戏的主循环""" while True: self._check_events() self.ship.update() self._update_bullets() self._update_aliens() self._check_update_screen() 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_events(event) elif event.type == pygame.KEYUP: self._check_keyup_events(event) def _check_keydown_events(self, event): """响应按键按下""" if event.key == pygame.K_RIGHT: self.ship.moving_right = True elif event.key == pygame.K_LEFT: self.ship.moving_left = True # 按Q键退出游戏 elif event.key == pygame.K_q: sys.exit() # 按空格键发射子弹(按下空格就创建一个子弹) elif event.key == pygame.K_SPACE: self._fire_bullet() def _check_keyup_events(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 _check_update_screen(self): """更新屏幕上的图像,并切换到新屏幕""" # 每次循环时都重绘屏幕 self.screen.fill(self.settings.bg_color) self.ship.blitme() # 绘制子弹(绘制子弹组中的每一个子弹) for bullet in self.bullets.sprites(): bullet.draw_bullet() # 绘制外星人(draw方法会将编组中每一个元素都依次绘制到屏幕上面) self.aliens.draw(self.screen) # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() def _update_bullets(self): """所有与子弹相关的代码""" self.bullets.update() # 删除已经消失的子弹(为什么是迭代bullets.copy(),愿意是python的for循环不允许在迭代过程中,迭代长度有改变的,否则会出现错删,或者遗漏) for bullet in self.bullets.copy(): if bullet.rect.bottom <= 0: self.bullets.remove(bullet) # 验证子弹数量 # print(len(self.bullets)) self._check_bullet_alien_collisions() def _check_bullet_alien_collisions(self): """ 检测子弹是否击中外星人""" collisions = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True) # 如果外星人组空了 if not self.aliens: # 删除所有子弹,创建一群新的外星人 self.bullets.empty() self._create_fleet() def _fire_bullet(self): """创建一颗子弹,并将其加入编组bullets中""" # 子弹数量小于子弹运行的最大值时,才创建子弹 if len(self.bullets) < self.settings.bullets_allowed: new_bullet = Bullet(self) self.bullets.add(new_bullet) def _create_fleet(self): """创建外星人群""" # 创建一个外星人,并计算一行可容纳多少个外星人 alien = Alien(self) alien_width, alien_height = alien.rect.size # 计算外星人可用宽度(屏幕左右两头分别留出一个外星人的宽度) available_space_x = self.settings.screen_width - (2 * alien_width) # 计算外星人横向可放数量(每个外星人之间隔一个外星人),向下取整的整数除法 number_aliens_x = available_space_x // (2 * alien_width) # 计算外星人可用高度(顶部留出一个外星人高度,底部留出两个外星人高度加飞船高度) ship_height = self.ship.rect.height available_space_y = self.settings.screen_height - (3 * alien_height) - ship_height # 计算外星人行数 number_rows = available_space_y // (2 * alien_height) for row_number in range(number_rows): # 创建每一行外星人 for alien_number in range(number_aliens_x): self._create_alien(alien_number, row_number) def _create_alien(self, alien_number, row_number): """创建一行外星人""" alien = Alien(self) alien_width, alien_height = alien.rect.size # 计算当前外星人的位置(留出一个外星人的宽度 + 一个外星人占用的宽度 * 当前机器人index) alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = alien.x alien.rect.y = alien_height + 2 * alien_height * row_number self.aliens.add(alien) def _update_aliens(self): """更新外星人组中所有外星人的位置""" self._check_fleet_edges() self.aliens.update() 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 if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` ### 记录游戏统计信息 添加游戏结束逻辑,当玩家用完所有飞船时游戏结束 修改[settings.py](settings.py)文件 ```python class Settings: """存储游戏《外星人入侵》中所有设置的类""" def __init__(self): """初始化游戏静态设置""" self.screen_width = 1200 self.screen_height = 800 # 设置背景颜色 self.bg_color = (230, 230, 230) # 飞船移动的速度 self.ship_speed = 0.6 # 子弹的设置 self.bullet_speed = 0.7 self.bullet_width = 3 self.bullet_height = 15 self.bullet_color = (60, 60, 60) # 限制子弹最大数量 self.bullets_allowed = 50 # # 是否开启子弹发射子弹的功能 # self.auto_fire_bullet = False # 是否开启子弹发射子弹的功能 # # 自动发射子弹的速度(时间间隔s) # self.auto_fire_speed = 0.5 # 外星人的设置 self.alien_speed = 0.3 self.fleet_drop_speed = 14.0 # fleet_direction为1表示向右移动,为-1表示向左移动(值可以代表速度) self.fleet_direction = 1 # 设置玩家有三艘飞船(3条命) self.ship_limit = 3 ``` 新增文件game_stats.py, ```python class GameStats: """跟踪游戏的统计信息""" def __init__(self, ai_game): """初始化统计信息""" self.settings = ai_game.settings self.reset_stats() # 游戏刚启动时处于活动状态 self.game_active = True def reset_stats(self): """初始化在游戏运行期间可能变化的统计信息""" self.ships_left = self.settings.ship_limit ``` 修改[ship.py](ship.py)ship.py文件,添加飞船居中的方法 ```python import pygame class Ship: """管理飞船的类""" def __init__(self, ai_game): """初始化飞船并设置其初始位置""" self.screen = ai_game.screen self.screen_rect = ai_game.screen.get_rect() self.settings = ai_game.settings # 加载飞船图像并获取其外接矩形 self.image = pygame.image.load('images/ship.bmp') self.rect = self.image.get_rect() # 对于每个新飞船,都将其放在屏幕底部的中央 self.rect.midbottom = self.screen_rect.midbottom # 飞船位置的横坐标 self.x = float(self.rect.x) # 表示飞船是否正在向右移动 self.moving_right = False # 表示飞船是否正在向左移动 self.moving_left = False def blitme(self): """在指定位置绘制飞船""" self.screen.blit(self.image, self.rect) def update(self): """根据移动标志调整飞船的位置""" if self.moving_right and self.rect.right < self.screen_rect.right: self.x += self.settings.ship_speed if self.moving_left and self.rect.left > 0: self.x -= self.settings.ship_speed self.rect.x = self.x def center_ship(self): """让飞船在屏幕上居中""" self.rect.midbottom = self.screen_rect.midbottom self.x = float(self.rect.x) ``` 修改[alien_invasion.py](alien_invasion.py)文件 ```python # sys提供了一些功能,可以让我们与python解释器进行交互。比如退出程序 import sys # 开发游戏主要使用到的库 import pygame from time import sleep # 导入设置类(语法: from 文件名 import 类名) from settings import Settings from ship import Ship # 引入子弹类 from bullet import Bullet # 引入外星人 from alien import Alien from game_stats import GameStats class AlienInvasion: """管理游戏资源和行为的类""" def __init__(self): """初始化游戏并创建游戏资源""" # 游戏初始化 pygame.init() self.settings = Settings() # 创建游戏窗口 self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) # self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height), pygame.FULLSCREEN) # # 获取游戏窗口的宽高 # self.settings.screen_width = self.screen.get_width() # self.settings.screen_height = self.screen.get_height() # 设置游戏标题 pygame.display.set_caption("Alien Invasion") self.stats = GameStats(self) self.ship = Ship(self) # 创建一个用于存储子弹的编组 self.bullets = pygame.sprite.Group() # 创建一个外星人编组 self.aliens = pygame.sprite.Group() # 创建一个外星人 self._create_fleet() def run_game(self): """开始游戏的主循环""" while True: self._check_events() if self.stats.game_active: self.ship.update() self._update_bullets() self._update_aliens() self._check_update_screen() 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_events(event) elif event.type == pygame.KEYUP: self._check_keyup_events(event) def _check_keydown_events(self, event): """响应按键按下""" if event.key == pygame.K_RIGHT: self.ship.moving_right = True elif event.key == pygame.K_LEFT: self.ship.moving_left = True # 按Q键退出游戏 elif event.key == pygame.K_q: sys.exit() # 按空格键发射子弹(按下空格就创建一个子弹) elif event.key == pygame.K_SPACE: self._fire_bullet() def _check_keyup_events(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 _check_update_screen(self): """更新屏幕上的图像,并切换到新屏幕""" # 每次循环时都重绘屏幕 self.screen.fill(self.settings.bg_color) self.ship.blitme() # 绘制子弹(绘制子弹组中的每一个子弹) for bullet in self.bullets.sprites(): bullet.draw_bullet() # 绘制外星人(draw方法会将编组中每一个元素都依次绘制到屏幕上面) self.aliens.draw(self.screen) # 让最近绘制的屏幕可见(刷新游戏窗口里的内容) pygame.display.flip() def _update_bullets(self): """所有与子弹相关的代码""" self.bullets.update() # 删除已经消失的子弹(为什么是迭代bullets.copy(),愿意是python的for循环不允许在迭代过程中,迭代长度有改变的,否则会出现错删,或者遗漏) for bullet in self.bullets.copy(): if bullet.rect.bottom <= 0: self.bullets.remove(bullet) # 验证子弹数量 # print(len(self.bullets)) self._check_bullet_alien_collisions() def _check_bullet_alien_collisions(self): """ 检测子弹是否击中外星人""" collisions = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True) # 如果外星人组空了 if not self.aliens: # 删除所有子弹,创建一群新的外星人 self.bullets.empty() self._create_fleet() def _fire_bullet(self): """创建一颗子弹,并将其加入编组bullets中""" # 子弹数量小于子弹运行的最大值时,才创建子弹 if len(self.bullets) < self.settings.bullets_allowed: new_bullet = Bullet(self) self.bullets.add(new_bullet) def _create_fleet(self): """创建外星人群""" # 创建一个外星人,并计算一行可容纳多少个外星人 alien = Alien(self) alien_width, alien_height = alien.rect.size # 计算外星人可用宽度(屏幕左右两头分别留出一个外星人的宽度) available_space_x = self.settings.screen_width - (2 * alien_width) # 计算外星人横向可放数量(每个外星人之间隔一个外星人),向下取整的整数除法 number_aliens_x = available_space_x // (2 * alien_width) # 计算外星人可用高度(顶部留出一个外星人高度,底部留出两个外星人高度加飞船高度) ship_height = self.ship.rect.height available_space_y = self.settings.screen_height - (3 * alien_height) - ship_height # 计算外星人行数 number_rows = available_space_y // (2 * alien_height) for row_number in range(number_rows): # 创建每一行外星人 for alien_number in range(number_aliens_x): self._create_alien(alien_number, row_number) def _create_alien(self, alien_number, row_number): """创建一行外星人""" alien = Alien(self) alien_width, alien_height = alien.rect.size # 计算当前外星人的位置(留出一个外星人的宽度 + 一个外星人占用的宽度 * 当前机器人index) alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = alien.x alien.rect.y = alien_height + 2 * alien_height * row_number self.aliens.add(alien) def _update_aliens(self): """更新外星人组中所有外星人的位置""" self._check_fleet_edges() self.aliens.update() # 检查外星人是否碰到屏幕底部 self._check_aliens_bottom() # 检测外星人和飞船之间的碰撞(检查ship有没有与aliens组里任意元素碰撞) if pygame.sprite.spritecollideany(self.ship, self.aliens): self._ship_hit() 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: self.stats.ships_left -= 1 # 清空余下的外星人和子弹 self.aliens.empty() self.bullets.empty() # 创建一群新的外星人,并将飞船放到屏幕底端中央 self._create_fleet() self.ship.center_ship() sleep(0.5) else: self.stats.game_active = False def _check_aliens_bottom(self): """检查是否有外星人到达了屏幕底端""" screen_rect = self.screen.get_rect() for alien in self.aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom: # 像飞船被撞到一样进行处理 self._ship_hit() break if __name__ == '__main__': # 创建游戏实例并运行游戏 ai = AlienInvasion() ai.run_game() ``` ### 添加play按钮 ### 添加提高游戏难度机制 ### 计分 得分、最高分、等级、剩余飞船数