目录

  • 安装Pygame
    • 创建Pygame窗口以及响应用户输入
    • 设置背景色
    • 创建设置类
    • 添加飞船图像
    • 创建ship类
  • 重构:模块game_functions
    • 函数check_events()
    • 函数update_screen()
    • 驾驶飞船
    • 响应按键
    • 允许不断移动
    • 左右移动
    • 调整飞船的速度
    • 限制飞船的活动范围
    • 重构check_events()
  • 射击
    • 添加子弹设置
    • 创建bullet类
    • 将子弹存储到编组中
    • 开火
    • 删除已经消失的子弹
    • 限制子弹的数量
    • 创建函数update_bullets()
    • 创建函数fire_bullet()
  • 外星人
    • 创建Alien类
    • 创建Alien实例
    • 让外星人出现在屏幕上
    • 创建一群外星人
      • 确定一行可容纳多少个外星人
      • 创建多行外星人
      • 重构create_fleet()
    • 添加行
    • 让外星人群移动
      • 向右移动的外星人
      • 创建表示外星人移动方向的设置
      • 检查外星人是否撞到屏幕边缘
      • 向下移动外星人群并改变移动方向
    • 射杀外星人
      • 检测外星人与子弹的碰撞
      • 生成新的外星人群
      • 重构update_bullets()
    • 结束游戏
      • 检测外星人和飞船碰撞
      • 响应外星人和飞船碰撞
      • 有外星人到达屏幕底部
      • 游戏结束
    • 确定应运行游戏的那些部分
  • 后记

安装Pygame

终端输入:
pip install Pygame
#开始游戏项目

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

首先:创建一个空的Pygame窗口。

import sys
import pygamedef run_game():pygame.init()screen = pygame.display.set_mode((1200, 800))pygame.display.set_caption("Alien Invasion")while True:for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()pygame.display.flip()run_game()

理解:

  1. pygame.init()初始化背景设置,让Pygame能够正确地工作。
  2. Pygame.display.set_mode()来创建一个名为screen的显示窗口。每经过一次循环都将自动重绘这个surface(游戏中的元素,外星人,飞船等。)
  3. while循环包含一个事件循环以及管理屏幕更新的代码。事件是用户玩游戏时的操作,如按键或移动鼠标。为让程序响应事件,我们编写一个事件循环,用于监听事件,并根据发生的事件执行相应的任务。
  4. Pygame.QUIT,用于检测当用户单击关闭按钮时,调用sys.exit()来退出程序。
  5. pygame.display.flip(),命令pygame让最近绘制的屏幕可见。在这里,它在每次执行while循环时都绘制一个空屏幕,并擦去旧屏幕,使只有新屏幕可见。在我们移动游戏元素时,pygame.display.flip()将不断更新屏幕,以显示元素的新位置,并在原来的位置隐藏元素,从而营造平滑移动的效果。

设置背景色

alien_invasion.pyimport sys
import pygamedef run_game():pygame.init()screen = pygame.display.set_mode((1200, 800))pygame.display.set_caption("Alien Invasion")bg_color = (230,230,230)# 开始游戏主循环while True:for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()screen.fill(bg_color)# 让最近绘制的屏幕可见pygame.display.flip()run_game()

添加了一个screen.fill(bg_color),用于填充颜色

创建设置类

每次给游戏添加新功能时,通常也将引入一些新设置。下面编写一个名为settings的模块,其中包含一个名为settings的类,用于将所有设置存储在一个地方,以免在代码中到处添加设置。
这样我们就能传递一个设置对象,而不是众多不同的设置。
另外,这让函数调用更简单,且在项目增大时修改游戏的外观更容易:要修改游戏,只需要修改settings.py中的一些值。

settings.pyclass Settings():def __init__(self):self.screen_width = 1200self.screen_height = 800self.bg_color = (230, 230, 230)

修改原来的alien_invasion.py文件为:

alien_invasion.pyimport sys
import pygame
from settings import Settingsdef run_game():pygame.init()ai_settings = Settings()screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))pygame.display.set_caption("Alien Invasion")# 开始游戏主循环while True:for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()screen.fill(ai_settings.bg_color)# 让最近绘制的屏幕可见pygame.display.flip()run_game()

添加飞船图像

在网站http://pixabay.com/中下载飞船图像,使用.bmp结尾的图像,(这样的图片不用下载图像库便可以使用)。
大多图片为.jpg,.png,.gif格式。但可以使用Photoshop,GIMP和paint等工具将其转换为位图。
在项目的文件夹下创建一个images的文件夹,并将图片ship.bmp放进去。

创建ship类

选择用于表示飞船的图像后,需要将其显示到屏幕上。我们将创建一个名为ship的模块,其中包含ship类,它负责管理飞船的大部分行为。

ship.pyimport pygame
class Ship():def __init__(self, screen):self.screen = screenself.image = pygame.image.load('images/ship.png')self.rect = self.image.get_rect()self.screen_rect = screen.get_rect()self.rect.centerx = self.screen_rect.centerxself.rect.bottom = self.screen_rect.bottomdef blitme(self):self.screen.blit(self.image, self.rect)

重构:模块game_functions

在大型项目中,经常需要在添加新代码前重构既有代码。重构旨在简化既有代码的结构,使其更容易扩展。
在本节中,我们将创建一个名为game_functions的新模块,它将存储大量让游戏运行的函数。通过创建模块game_functions,可避免alien_invasion.py太长,使其逻辑混乱。

函数check_events()

我们首先把管理事件的代码移到一个名为check_events()的函数中,以简化run_game()并隔离事件管理循环。通过隔离事件循环,可将事件管理与游戏的其他方面(如更新屏幕)分离。
将check_events()放在一个名为game_functions的模块中。

import sys
import pygamedef check_events():for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()

更改alien_invasions.py为:

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gfdef run_game():pygame.init()ai_settings = Settings()screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))pygame.display.set_caption("Alien Invasion")pygame.display.set_caption('Alien Invasion')ship = Ship(screen)# 开始游戏主循环while True:gf.check_events()screen.fill(ai_settings.bg_color)ship.blitme()# 让最近绘制的屏幕可见pygame.display.flip()run_game()

把循环部分更改了即可。

函数update_screen()

为了进一步简化run_game(),下面将更新屏幕的代码移到一个名为update_screen()的函数中,并将这个函数放在模块game_functions.py中:

def update_screen(ai_settings, screen, ship):screen.fill(ai_settings.bg_color)ship.blitme()pygame.display.flip()

再将alien_invasion.py中的部分替换即可:

    while True:gf.check_events()gf.update_screen(ai_settings, screen, ship)

驾驶飞船

下面让玩家可以左右移动飞船。为此,我们将编写代码,在用户按左或右箭头时做出响应。
我们先专注于向右移动。

响应按键

每当用户按键时,都将在pygame中注册一个事件。事件是通过方法pygame.event.get()获取的,因此在函数check_events()中,我们需要指定要检查那些类型的事件。
每次按键都被注册为一个KEYDOWN事件。
检测到KEYDOWN事件时,我们需要检查按下的键是否为特定的键。例如,如果按下的时右箭头,就增大飞船的rect.centrx值。
在game_functions.py中添加以下函数:

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_PIGHT: # ②ship.rect.centerx += 1

解释:①处用于在pygame检测到KEYDOWN事件时作出响应。
②处在检测到按下为右箭头时将飞船向右移动。
修改对应的alien_invasion.py模块:传参ship

    while True:gf.check_events(ship)gf.update_screen(ai_settings, screen, ship)

允许不断移动

玩家按住右箭头不放时,我们希望飞船不断地向右移动,直到玩家松开为止。
思路:

  1. 检测pygame.KEYUP事件,以便玩家松开右箭头时我们能够知道这一点;然后,我们将结合使用KEYDOWN和KEYUP事件,以及一个名为moving_right的标志来实现持续移动。
  2. 飞船不动时,标志moving_right将为False。玩家按下右箭头时,我们将这个标志设为True,而玩家松开时,我们将这个标志重新设置为Falsh

飞船的属性由ship类控制,因此我们给这个类添加一个名为moving_right的属性和一个名为update()的方法。方法update()检查标志moving_right的状态,如果这个标志为True,就调整飞船的位置。

import pygame
class Ship():--snip--def __init__(self, screen):self.moving_right = Falsedef update(self):if self.moving_right:self.rect.centerx += 1

接下来更改game_functions.py中的check_events()函数,让玩家按下右箭头时将moving_right设置为True,并在玩家松开时将moving_right设置为false:

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 = Trueelif event.type == pygame.KEYUP:if event.key == pygame.K_RIGHT:ship.moving_right = False

最后,在alien_invasion.py中的while循环,以便每次执行循环时都要调用飞船的方法update()。

    while True:gf.check_events(ship)ship.update()gf.update_screen(ai_settings, screen, ship)

左右移动

飞船能够不断地向右移动后,添加向左移动地逻辑很容易。我们将再次修改ship类和函数check_events().

ship.pyimport pygame
class Ship():def __init__(self, screen):--snip--self.moving_right = Falseself.moving_left = Falsedef update(self):if self.moving_right:self.rect.centerx += 1elif self.moving_left:self.rect.centerx -= 1--snip--
game_functions.py # 中的check_events()修改。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 = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.type == pygame.KEYUP:if event.key == pygame.K_RIGHT:ship.moving_right = Falseif event.key == pygame.K_LEFT:ship.moving_left = False

调整飞船的速度

接下来我们将进一步优化飞船的移动方式:调整飞船的速度;限制飞船的移动距离,以免它移到屏幕外面去。
每次执行while循环时,飞船最多移动1像素,但我们可以在Settings类中添加属性ship_speed_factor,用于控制飞船的速度。我们将根据这个属性决定飞船在每次循环时最多移动多少距离。

class Settings():def __init__(self):--snip--self.ship_speed_factor = 1.5

通过将速度设置为小数值,可在后面加快游戏的节奏时更细致地控制飞船的速度。然而,rect的centerx等属性只能存储整数值,因此我们需要对ship类作修改:

import pygame
class Ship():def __init__(self, ai_settings, screen):--snip--self.center = float(self.rect.centerx)self.moving_right = Falseself.moving_left = Falsedef update(self):if self.moving_right:self.center += self.ai_settings.ship_speed_factorelif self.moving_left:self.center -= self.ai_settings.ship_speed_factorself.rect.centerx = self.centerdef blitme(self):--snip--

最后更改alien_invasion.py

def run_game():--snip--ship = Ship(ai_settings, screen)--snip--

限制飞船的活动范围

当玩家按住箭头的时间足够长,飞船将移动到屏幕外面,消失得无影无踪。下面来修复这种问题。为此,我们将修改ship类的方法update():

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("Alien Invasion")ship = Ship(ai_settings, screen)

重构check_events()

随着游戏的开发,函数check_events()将越来越长,我们将其部分代码放在两个函数中:一个处理KEYDOWN事件,一个处理KEYUP事件。

import sys
import pygamedef check_keydown_events(event, ship):if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Truedef check_keyup_events(event, ship):if event.key == pygame.K_RIGHT:ship.moving_right = Falseelif event.key == pygame.K_LEFT:ship.moving_left = Falsedef 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)ship.blitme()pygame.display.flip()

射击

下面来添加射击设置。我们将编写玩家按空格键时发射子弹(小矩形)的代码。子弹将在屏幕中向上穿行,抵达屏幕边缘后消失。

添加子弹设置

class Settings():def __init__(self):--snip--# 子弹设置self.bullet_speed_factor = 1self.bullet_width = 3self.bullet_height = 15self.bullet_color = 60, 60, 60

创建bullet类

创建存储Bullet类的文件bullet.py。

import pygame
from pygame.sprite import Spriteclass Bullet(Sprite):def __init__(self, ai_settings, screen, ship):super(Bullet, self).__init__()self.screen = screenself.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height)self.rect.centerx = ship.rect.centerxself.rect.top = ship.rect.topself.y = float(self.rect.y)self.color = ai_settings.bullet_colorself.speed_factor = ai_settings.bullet_speed_factordef update(self):self.y -= self.speed_factorself.rect.y = self.ydef draw_bullet(self):pygame.draw.rect(self.screen, self.color, self.rect)

将子弹存储到编组中

定义Bullet类和必要的设置后,就可以编写代码了,在玩家每次按空格键时都发射出一发子弹。首先,我们将在alien_invasion.py中创建一个编组(group),用于存储所有有效的子弹,以便能够管理发射出去的子弹。
这个编组将是pygame.sprite.Group类的一个实例;pygame.sprite.Group类,类似于列表,但提供了有助于开发游戏的额外功能。我们将在主循环中,使用这个编组在屏幕上绘制子弹,以及更新子弹的位置。

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Groupdef run_game():--snip--bullets = Group()# 开始游戏主循环while True:gf.check_events(ship)ship.update()bullets.update()gf.update_screen(ai_settings, screen, ship)run_game()

开火

在game_functions.py中,我们需要修改check_keydown_events(),以便在玩家按空格键时发射一颗子弹。我们无需修改check_keyup_events(),因为玩家松开空格键时什么都不会发生。我们还需要修改update_screen(),确保在调用flip()前在屏幕上重新绘制每颗子弹:

import sys
import pygame
from bullet import Bulletdef check_keydown_events(event,ai_settings , screen, ship, bullets):if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_SPACE:new_bullet = Bullet(ai_settings, screen, ship)bullets.add(new_bullet)--snip--def check_events(ai_settings, screen, ship, bullets):for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()--snip--elif event.type == pygame.KEYDOWN:check_keydown_events(event, ai_settings, screen, ship, bullets)def update_screen(ai_settings, screen, ship, bullets):screen.fill(ai_settings.bg_color)for bullet in bullets.sprites():bullet.draw_bullet()ship.blitme()pygame.display.flip()

删除已经消失的子弹

当前,子弹抵达屏幕顶端后消失,这仅仅是因为Pygame无法在屏幕外面绘制它们。这些子弹实际上依旧存在。这是个问题,因为它们会继续消耗内存。
为此,我们要检测这样的条件,即表示子弹的rect的bottom属性为零,它表明子弹已穿过屏幕顶端。

# alien_invasion.pywhile 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)

在for循环中,不应从列表或编组中删除条目,因此必须遍历编组中的副本。我们使用了方法copy()来设置for循环,这让我们能够在循环中修改bullets。

限制子弹的数量

我们可以对可同时出现在屏幕上的子弹数量进行限制,以鼓励玩家有目的的射击。
首先,在settings.py中存储允许的最大子弹数量。

class Settings():def __init__(self):--snip--# 允许的子弹数量self.bullets_allowed = 3

在创建新子弹前检查未消失得子弹数量是否小于该设置。

# game_functions.pydef check_keydown_events(event,ai_settings , screen, ship, bullets):if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_SPACE:if len(bullets) < ai_settings.bullets_allowed: # 判断是否满足子弹数量的限制new_bullet = Bullet(ai_settings, screen, ship)bullets.add(new_bullet)

创建函数update_bullets()

编写并检查子弹管理代码后,可将其移到模块game_functions中,让主程序文件alien_invasion.py尽可能的简单。
创建一个名为update_bullets()的函数:

# game_functions.py 底部增加def update_bullets(bullets):bullets.update()for bullet in bullets.copy():if bullet.rect.bottom <= 0:bullets.remove(bullets)

更改alien_invasion.py中的while循环:

# game_invasion.pywhile True:gf.check_events(ai_settings, screen, ship, bullets)ship.update()bullets.update()gf.update_bullets(bullets)gf.update_screen(ai_settings, screen, ship, bullets)

创建函数fire_bullet()

将发射子弹的代码移到一个独立的函数中,这样,在check_keydown_events()中只需要使用一行代码来发射子弹,让elif代码块简单。

# game_functions.pyimport sys
import pygame
from bullet import Bulletdef check_keydown_events(event, ai_settings, screen, ship, bullets):--snip--elif event.key == pygame.K_SPACE:fire_bullet(ai_settings, screen, ship, bullets)def fire_bullet(ai_settings, screen, ship, bullets):if len(bullets) < ai_settings.bullets_allowed:new_bullet = Bullet(ai_settings, screen, ship)bullets.add(new_bullet)

外星人

接下来,我们将在游戏中添加外星人。首先,我们在屏幕边缘附近添加一个外星人,然后生成一群外星人向两边和下面移动,并删除被子弹击中的外星人。最后,我们将显示玩家拥有的飞船属性,并在玩家的飞船用完后结束游戏。
在给项目添加新功能前,还应审核既有代码。每进一个阶段,通常项目都会更复杂,因此最好度混乱或低效的代码进行审计。
由于每次测试时,都要点击关闭来关闭游戏,很麻烦,下面添加一个结束游戏的快捷键Q:

# game_functions.pydef check_keydown_events(event, ai_settings, screen, ship, bullets):--snip--elif event.key == pygame.K_q:sys.exit()

创建Alien类

# alien.pyimport pygame
from pygame.sprite import Spriteclass Alien(Sprite):def __init__(self, ai_settings, screen):super(Alien, self).__init__()self.screen = screenself.ai_settings = ai_settingsself.image = pygame.load('images/alien.png')self.rect = self.image.get_rect()self.rect.x = self.rect.widthself.rect.y = self.rect.heightself.x = float(self.rect.x)def blitme(self):self.screen.blit(self.image, self.rect)

创建Alien实例

在alien_invasion.py中创建一个Alien实例:

# alien_invasion.pyimport sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from alien import Aliendef run_game():pygame.init()ai_settings = Settings()screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))pygame.display.set_caption("Alien Invasion")ship = Ship(ai_settings, screen)bullets = Group()alien = Alien(ai_settings, screen)

让外星人出现在屏幕上

在update_screen()中调用方法blitme()。

# game_functions.pydef update_screen(ai_settings, screen, ship, alien, bullets):screen.fill(ai_settings.bg_color)for bullet in bullets.sprites():bullet.draw_bullet()ship.blitme()alien.blitme() # 显示外星人pygame.display.flip()

创建一群外星人

首先确认一行可以容纳多少个外星人。

确定一行可容纳多少个外星人

为确定一行可容纳多少外星人,我们可以看看可用的水平空间有多大。并在屏幕左右各留出一个外星人的距离;最后用剩下的距离除以一个外星人的距离。
公式:
available_space_x=ai_settings.screen_width-(2* alien_width)
number_aliens_x=available_space_x / (2* alien_width)

创建多行外星人

为创建一行外星人,首先在alien_invasion.py中创建一个名为aliens的空编组,用于存储全部外星人,再调用game_functions.py中的创建外星人群的函数。

import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from alien import Aliendef run_game():--snip--bullets = Group()aliens = Group()# alien = Alien(ai_settings, screen)gf.create_fleet(ai_settings, screen, aliens)# 开始游戏主循环--snip--

修改update_screen():

# game_functions.pydef update_screen(ai_settings, screen, ship, aliens, bullets):screen.fill(ai_settings.bg_color)for bullet in bullets.sprites():bullet.draw_bullet()ship.blitme()aliens.draw(screen)    # 添加# alien.blitme()pygame.display.flip()

增加新函数:create_fleet(),放在game_functions.py

def create_fleet(ai_settings, screen, aliens):alien = Alien(ai_settings, screen)alien_width = alien.rect.widthavailable_space_x = ai_settings.screen_width - 2 * alien_widthnumber_aliens_x = int(available_space_x / (2 * alien_width))for alien_number in range(number_aliens_x):alien = Alien(ai_settings, screen)alien.x = alien_width + 2 * alien_width * alien_numberalien.rect.x = alien.xaliens.add(alien)

重构create_fleet()

下面是create_fleet()和两个新函数,get_number_aliens_x()和create_alien():

# game_function.pydef get_number_aliens_x(ai_settings, alien_width):available_space_x = ai_settings.screen_width - 2 * alien_widthnumber_aliens_x = int(available_space_x / (2 * alien_width))return number_aliens_xdef create_alien(ai_settings, screen, aliens, alien_number):alien = Alien(ai_settings, screen)alien_width = alien.rect.widthalien.x = alien_width + 2 * alien_width * alien_numberalien.rect.x = alien.xaliens.add(alien)def create_fleet(ai_settings, screen, aliens):alien = Alien(ai_settings, screen)number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)for alien_number in range(number_aliens_x):create_alien(ai_settings, screen, aliens, alien_number)

添加行

# game_functions.pydef get_number_rows(ai_settings, ship_height, alien_height):available_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height)number_rows = int(available_space_y / (2 * alien_height))return number_rowsdef create_alien(ai_settings, screen, aliens, alien_number, row_number):--snip--alien.x = alien_width + 2 * alien_width * alien_numberalien.rect.x = alien.xalien.rect.y = alien.rect.height + 2 * alien.rect.height * row_numberaliens.add(alien)def create_fleet(ai_settings, screen, ship, aliens):alien = Alien(ai_settings, screen)number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)for row_number in range(number_rows):for alien_number in range(number_aliens_x):create_alien(ai_settings, screen, aliens, alien_number, row_number)

让外星人群移动

下面来让外星人移动,在屏幕上向右移动,撞到屏幕边缘后向下移动一定的距离,再沿反方向移动。

向右移动的外星人

为移动外星人,我们将使用方法alien.py中的方法update(),且对外星人群中的每个外星人都调用它。
首先在settings.py中添加控制外星人的速度

# settings.pyclass Settings():def __init__(self):--snip--# 外星人设置self.alien_speed_factor = 1

alien.py中添加update()函数:

alien.pydef update(self):self.x += self.ai_settings.alien_speed_factorself.rect.x = self.x

更新while循环中的更新子弹和飞船的方法

alien_invasion.pywhile True:gf.check_events(ai_settings, screen, ship, bullets)ship.update()bullets.update()gf.update_bullets(bullets)gf.update_aliens(aliens)gf.update_screen(ai_settings, screen, ship, aliens, bullets)

最后在game.functons.py末尾添加新函数:update_aliens()

game_functions.pydef update_aliens(aliens):aliens.update()

创建表示外星人移动方向的设置

下面来创建让外星人撞到屏幕右边缘后向下移动,再向左移动的设置。

settings.pyclass Settings():def __init__(self):--snip--# 外星人设置self.alien_speed_factor = 1self.fleet_drop_speed = 10self.fleet_direction = 1

检查外星人是否撞到屏幕边缘

现在需要编写一个方法来检查是否有外星人撞到屏幕边缘,还需要修改update(),以让每个外星人都沿正确的方法移动。

alien.pydef check_edges(self):screen_rect = self.screen.get_rect()if self.rect.right >= screen_rect.right:return Trueelif self.rect.left <= 0:return Truedef update(self):self.x += (self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction)self.rect.x = self.x

向下移动外星人群并改变移动方向

game_functions.pydef update_aliens(ai_settings, aliens):check_fleet_edges(ai_settings, aliens)aliens.update()def check_fleet_edges(ai_settings, aliens):for alien in aliens.sprites():if alien.check_edges():change_fleet_direction(ai_settings, aliens)breakdef change_fleet_direction(ai_settings, aliens):for alien in aliens.sprites():alien.rect.y += ai_settings.fleet_drop_speedai_settings.fleet_direction *= -1

更改alien_invasion.py

alien_invasion.pywhile True:gf.check_events(ai_settings, screen, ship, bullets)ship.update()bullets.update()gf.update_bullets(bullets)gf.update_aliens(ai_settings, aliens)gf.update_screen(ai_settings, screen, ship, aliens, bullets)

射杀外星人

我们创建了飞船和外星人群,但子弹射击中外星人时,将穿过外星人,因为我们还没有检查碰撞。我们将使用sprite.groupcollide()检测编组成员之间的碰撞。

检测外星人与子弹的碰撞

方法sprite.groupcollide()将每颗子弹的rect同每个外星人的rect进行比较,并返回一个字典,其中包含发生了碰撞的子弹和外星人。
在函数update_bullets()中,使用下面的代码来检测碰撞:

# game_functions.pydef update_bullets(aliens,bullets):bullets.update()for bullet in bullets.copy():if bullet.rect.bottom <= 0:bullets.remove(bullets)print(len(bullets))collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)

update_bullets()的调用传递了实参,aliens:

alien_functions.pywhile True:gf.check_events(ai_settings, screen, ship, bullets)ship.update()bullets.update()gf.update_bullets(aliens, bullets)gf.update_aliens(ai_settings, aliens)gf.update_screen(ai_settings, screen, ship, aliens, bullets)

生成新的外星人群

这个游戏的一个重要特点就是外星人无穷无尽,一个外星人被消灭后,又会出现一群新的外星人。
首先就要检查编组aliens是否为空。如果为空,就调用create_fleet()。

game_functions.pydef update_bullets(ai_settings, screen, ship, aliens, bullets):--snip--collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)if len(aliens) == 0:bullets.empty()create_fleet(ai_settings, screen, ship, aliens)

更改alien_invasion.py

    while True:gf.check_events(ai_settings, screen, ship, bullets)ship.update()bullets.update()gf.update_bullets(ai_settings, screen, ship, aliens, bullets)gf.update_aliens(ai_settings, aliens)gf.update_screen(ai_settings, screen, ship, aliens, bullets)

重构update_bullets()

game_functions.pydef check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets):collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)if len(aliens) == 0:bullets.empty()create_fleet(ai_settings, screen, ship, aliens)def update_bullets(ai_settings, screen, ship, aliens, bullets):bullets.update()for bullet in bullets.copy():if bullet.rect.bottom <= 0:bullets.remove(bullets)print(len(bullets))check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets)

结束游戏

检测外星人和飞船碰撞

game_functions.pydef update_aliens(ai_settings, ship, aliens):check_fleet_edges(ai_settings, aliens)aliens.update()if pygame.sprite.spritecollideany(ship, aliens):print("ship hit !!!")

将ship传给update_aliens():

# alien_invasion.pywhile True:gf.check_events(ai_settings, screen, ship, bullets)ship.update()bullets.update()gf.update_bullets(ai_settings, screen, ship, aliens, bullets)gf.update_aliens(ai_settings, ship, aliens)   # 加入shipgf.update_screen(ai_settings, screen, ship, aliens, bullets)

响应外星人和飞船碰撞

通过跟踪游戏的统计信息来记录飞船被撞了多少次。(有助于计分)
编写一个用于跟踪游戏统计信息的新类:GameStarts放在game_starts.py中

class GameStats():def __init__(self, ai_settings):self.ai_settings = ai_settingsself.reset_stats()def reset_stats(self):self.ships_left = self.ai_settings.ship_limit

飞船数存储在settings.py中:

class Settings():def __init__(self):--snip--# 飞船设置self.ship_speed_factor = 1.5self.ship_limit = 3

在alien_invasion.py中创建一个GameStats实例:

--snip--
from alien import Alien
from game_stats import GameStatsdef run_game():--snip--pygame.display.set_caption("Alien Invasion")stats = GameStats(ai_settings)--snip--while True:--snip--gf.update_bullets(ai_settings, screen, ship, aliens, bullets)gf.update_aliens(ai_settings, stats, screen, ship, aliens, bullets)--snip--run_game()

最后将实现这些功能的大部分代码放到函数ship.hit()中:

# game_functions.pydef ship_hit(ai_settings, stats, screen, ship, aliens, bullets):stats.ships_left -= 1aliens.empty()bullets.empty()create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()sleep(0.5)def update_aliens(ai_settings, stats, screen, ship, aliens, bullets):check_fleet_edges(ai_settings, aliens)aliens.update()if pygame.sprite.spritecollideany(ship, aliens):ship_hit(ai_settings, stats, screen, ship, aliens, bullets)

将center_ship()方法,添加到ship.py末尾:

    def center_ship(self):self.center = self.screen_rect.centerx

有外星人到达屏幕底部

如果有外星人到达屏幕底端,我们想有外星人撞到飞船那样做出反应。
创建一个新函数,check_aliens_bottom():

# game_functions.pydef update_aliens(ai_settings, stats, screen, ship, aliens, bullets):--snip--check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets)def check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets):screen_rect = screen.get_rect()for alien in aliens.sprites():if alien.rect.bottom >= screen_rect.bottom:ship_hit(ai_settings, stats, screen, ship, aliens, bullets)break

游戏结束

ships_left会不断变成更小的负数。下面在GameStats中添加一个作为标志的属性game_active,以便玩家在用完飞船后结束游戏。

# game_stats.pyclass GameStats():def __init__(self, ai_settings):--snip--self.game_active = True

在玩家所有飞船用完后,将game_active设置为False:

# game_functions.pydef ship_hit(ai_settings, stats, screen, ship, aliens, bullets):if stats.ships_left > 0:stats.ships_left -= 1sleep(0.5)else:stats.game_active = False--snip--

确定应运行游戏的那些部分

# alien_invasion.pywhile True:gf.check_events(ai_settings, screen, ship, bullets)if stats.game_active:ship.update()gf.update_bullets(ai_settings, screen, ship, aliens, bullets)gf.update_aliens(ai_settings, stats, screen, ship, aliens, bullets)bullets.update()gf.update_screen(ai_settings, screen, ship, aliens, bullets)

后记

如果有机会,下次再完善计分和开始结束让玩家可以持续玩这个游戏的功能。

python项目-飞机大战相关推荐

  1. Python项目——飞机大战!

    文章目录 一.项目介绍--飞机大战 实战步骤 确认模块 -- pygame 安装 pygame 验证安装 二.pygame 快速入门 项目准备 1. 使用 `pygame` 创建图形窗口 小节目标 1 ...

  2. python项目:飞机大战(爆炸效果,血条,音效,buff加成,boss,菜单,完整详细注释的源码)

    文章目录 一. 总体概览 基本功能 细节部分(全部可以自定义) 可增添需求 二,技术框架 核心技术概述 1.游戏的初始化和退出 2 理解游戏中的坐标系 3 创建游戏主窗口 4. 理解 **图像** 并 ...

  3. python项目飞机大战

    实现步骤 1.创建窗口 2.创建一个玩家飞机,按方向键可以左右移动 3.给玩家飞机添加按空格键发射子弹功能 4.创建一个敌机 5.敌机自动左右移动 6.敌机自动发射子弹 1.创建窗口 import p ...

  4. python实现飞机大战游戏

    python实现飞机大战小游戏(含源码+视频资源) 导语: 正文: 1.开发工具 2.环境搭建 3.效果如下 Step1:定义精灵类 Step2:实现游戏主循环 Step3:制作简易的游戏开始和结束界 ...

  5. 用python做飞机大战打到不同部位扣分不同_python制作飞机大战需要哪些python术语...

    怎么样用Python写飞机大战游戏 为什么写出来一直都是未响应,哪里写错了吗?就算小编们没能走到最后,小编也不会心存遗憾,你有你的苦辣酸甜,小编有小编的喜怒哀乐,如果小编们不曾相遇,就没有那些美好记忆 ...

  6. python写飞机大战游戏_python实现飞机大战游戏

    飞机大战(Python)代码分为两个python文件,工具类和主类,需要安装pygame模块,能完美运行(网上好多不完整的,调试得心累.实现出来,成就感还是满满的),如图所示: 完整代码如下: 1.工 ...

  7. Python项目-----外星人大战

    Python项目-----外星人大战 alien_invasion.py import sys from time import sleep import pygame from settings i ...

  8. 小甲鱼python游戏代码_【小甲鱼】零基础学习python pygame 飞机大战可执行源代码...

    [实例简介] [小甲鱼]零基础学习python pygame 飞机大战可执行源代码,觉得挺有意思,故此分享. [实例截图] [核心代码] 飞机大战 └── 飞机大战 ├── bullet.py ├── ...

  9. python的飞机大战

    python的飞机大战的完整代码 alien.py import pygame from pygame.sprite import Sprite class Alien(Sprite):"& ...

最新文章

  1. Java的内存回收机制
  2. Laravel 事件侦听的几个方法 [Trait, Model boot(), Observer Class]
  3. 好记性不如烂笔头:会议纪要本
  4. c语言pID程序怎么设计,51单片机PID的算法实现程序C语言
  5. 10亿个字符串的排序问题
  6. [蓝桥杯][历届试题]回文数字-暴力枚举
  7. 计算机网络自顶向下方法实验报告,计算机网络自顶向下方法试验三报告.doc
  8. java学习(64):类访问私有内部内部类方法
  9. 1025. 反转链表 (25)
  10. 第一次java怎么创建一class_Java:如何创建Class参数?
  11. 在PKM2 / CyberArticle / MetaProducts Inquiry / 网博士 中选择了网博士。 :)
  12. 声纹识别应用:除了人脸识别,声纹识别技术也能帮警察抓逃犯!
  13. Android 加载SDCard中so库
  14. 插上u盘 计算机无响应,U盘插电脑没反应是不是坏了
  15. tai game java hay,GGame - Kho tai Game, tin Game
  16. java 生成 checksum
  17. 【信息系统项目管理师】2018下半年信息系统项目管理师考试案例分析
  18. spss安装剩下一个python_SPSSPython脚本在spss命令内部时停止并出现错误spss.提交()将创建一个警告...
  19. 机器学习从零到入门 集成学习
  20. Docker三剑客docker-machine ,docker-compose,docker-swam

热门文章

  1. 企业微信小程序_集成腾讯地图实现精准定位考勤打卡
  2. 【Java练手项目七】Java项目实战之天天酷跑
  3. 如何使用 YOLOv5 训练自己的数据集
  4. 《javaEE 开发的颠覆者,Spring boot实战》
  5. 我家有台智能模仿太阳光灯—“Ario”智能落地台灯
  6. 连接mongodb提示目标计算机拒绝,无法建立连接,因为目标计算机主动拒绝它(尽管mongod正在运行),并且无法将数据插入MongoDB...
  7. Python fractions 模块介绍
  8. 宁波大学计算机考研资料汇总
  9. 10分钟教你手写8个常用的自定义hooks
  10. 海外社媒营销该怎么做?