手讲解超详细python入门游戏项目‘打外星飞船’手把(一)
由于内容比较多,这里会分为五篇文章来讲解,从页面的创建、飞船控制、射击、外星人创建、射杀外星人五片来展开。
做一个窗口和设置响应用户
import sys
import pygame
''' '''
""" 我们先创建一个新的文件,保存的名字就叫做主函数吧,main.py。首先我们应该导入两个模块sys和pygame,pygame是用来开发游戏所需要的功能的,sys是我们退出的时候,我们需要用到的 """"
from settings import Settings
#这个是我们在后面创建一个settings用来管理设置,后年会补充
class AlienInvasion:
"""我们先创建一个类,用它来管理游戏资源和行为的类。"""
def __init__(self):
"""这个我们开始游戏的主循环"""
pygame.init()
#在这个类中,我们先定义一个函数,调用函数pygame.init()初始化背景设置,让他能够正常的工作
self.settings = Settings()
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
#在主程序文件中打入settings类调用pygames in it(),创建一个settings实力并付给self.settings,这个时候我们把它的属性宽度和高度复给主函数
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()
#在循环中,如果我们检测到了退出的指令,我们就用 sys.exit()来退出
self.screen.fill(self.settings.bg_color)
#调用方法fill(),用这种背景色填充屏幕。方法fill()用于处理surface只接受一个实参一种颜色
pygame.display.flip()
# 让最近绘制的屏幕可见,在这里我们通过不断的循环都会绘制一个空的屏幕,并且插去就的屏幕,所以让新的屏幕可见就行,成了动画
if __name__ == '__main__':
# 创建游戏实例,并且开始运行游戏
ai = AlienInvasion()
ai.run_game()
这里重新建立一个文件,可以命名为settings.py
class Settings:
"""我们开始编写一个名为settings的模块,在这个模块中,所有的设置都储存在这里,以免在代码中到处添加设置。创建另外一个文件,命名为settings.py。
"""
def __init__(self):
"""这里我们建立一个函数"""
# 如果只是一个默认的屏幕,就太没有意思了,在现在我们把屏幕的颜色改成白色
颜色是由RGB指定的,比如说255,0,0表示红色;0,255,0表示绿色;这里我们把背景色设为白色
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
这里重新建立一个文件,可以命名为ship.py。我们在这里会先创立一ship的模块.,我们用这个模块来管理飞船的大部分行为。
import pygame
class Ship:
"""管理飞船的类"""
def __init__(self, ai_game):
"""初始化飞船并且初始化的他的位置"""
self.screen = ai_game.screen
#在定义这个类之前,我要导入模块pygame
在一处的话,将屏幕付给了sheep的一个属性,方便这个类的所有方法后面的轻松访问
self.screen_rect = ai_game.screen.get_rect()
# 加载飞船图像
self.image = pygame.image.load('images/ship.bmp')
#在这里我们需要把飞船的图像添加进去,一般来说,图像的格式都是JPG和GIF多一点在这里我们用的是bmp的格式. 我把飞船的图片放在下面,注意在你建立文档的时候,一定要把图片放在一个名为images的文件夹下,并且我其他项目是同一个文件夹。
self.rect = self.image.get_rect()
self.rect.midbottom = self.screen_rect.midbottom
#我们都把它放在屏幕底部的中央因为这里我们要把非常放在底部的中央,所以我们应该用的属性叫做 midbottom
def blitme(self):
self.screen.blit(self.image, self.rect)
#现在我们要把这个飞船的图像调用出来,括号里面的是非常的位置
这个是我们要导入的图片
这个是我们最终建立好的游戏界面
手把手讲解超详细python入门游戏项目‘打外星飞船’(二)
上次我们在(一)中创建了游戏的背景,现在我们这里将要实现用键盘控制飞船的移动、射击子弹,但是在此之前我们还有一个非常重要的部分–重构。
重构
在大型项目中,经常需要添加新代码重构旧的代码,简单来说就把一些代码整理成函数,用函数之前的代码就变成了一句函数。这里我们就需要把之前的run_game()拆分成两个辅助方法,基本上辅助方法要以单个下划线打头。
我们直接回顾上此的代码
def run_game(self):
while True:
#这里把管理事件的代码移动到这两个函数里面了,代码在下面
self._check_events()
self._update_screen()
def _check_events(self):
#这个是之前按键和鼠标的代码
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
def _update_screen(self):
#更新图像,切换到新屏幕
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
pygame.display.flip()
飞船的控制
这里我开始把按键链接到电脑,每一次按下一个按键,pygame上都会注册一个事件,这里每次按下都会注册一个KEYDOWN事件,如果检测到这个事件就会移动
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN: #检测到了按键被按下
if event.type == pygame.K_RIGHT:#按下的键是右键
self.ship.rect.x +=1#这里的距离+1,即右边移
左右持续移动
# 添加左右的移动的标志,立flag是好个方法,简化代码过程
self.moving_right = False
self.moving_left = False
但检测到左右移动键按下后,flag变成1
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
这个时候我们在主运行加入移动函数,update()
def run_game(self):
"""Start the main loop for the game."""
while True:
self._check_events()
self.ship.update()#控制移动
self._update_screen()
下面这个就是移动函数
def update(self):
if self.moving_right:
self.ship.rect.x +=1#右移动加一
if self.moving_left:
self.ship.rect.x -=1#左移动减一
调整数独、限制活动范围
这里我们就整体展现下ship加工部分了。
import pygame
class Ship:
def __init__(self, ai_game):
self.screen = ai_game.screen
self.settings = ai_game.settings#这里添加一个settings属性,等会要在update用
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
#这里有个方法是储存小数值,因为飞船移动的是像素,所以这里要要把位置赋给能够储存小数值的变量
self.x = float(self.rect.x)
# 移动的flag
self.moving_right = False
self.moving_left = False
def update(self):
if self.moving_right and self.rect.right < self.screen_rect.right:
#飞船未飞出右边的边缘
self.x += self.settings.ship_speed
#移动的速度会不断地加一个像素的大小,注意:主函数中已经设置了速度为self.ship_speed=1.5
if self.moving_left and self.rect.left > 0:
#如果飞船未飞出左侧,左侧是0
self.x -= self.settings.ship_speed
#根据self.x更新rect对象
self.rect.x = self.x
再次重构
因为一句添加了不少内容,所以
def _check_events(self):
"""Respond to keypresses and mouse events."""
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
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
按Q键退出
def _check_keydown_events(self, event):
"""Respond to keypresses."""
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
#这里我们设置的按键Q退出,接受到Q键反应接受后执行sys模块的退出指令
elif event.key == pygame.K_q:
sys.exit()
全屏运行
def __init__(self):
"""Initialize the game, and create game resources."""
pygame.init()
self.settings = Settings()
#游戏开始时传入的是(0,0)以及参数pygame.FULLSCREEN,这个指令是覆盖整个屏幕
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
#这里使用屏幕的高和宽更新数据
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().height
手把手讲解超详细python入门游戏项目‘打外星飞船’(三)
第三部分我们讲解一下飞船需要射出子弹,那么子弹的部分是怎么操作呢?接下来我直接把项目的四个文件展示出来,以注释的形式在旁边讲解。因为有很多代码在前面都已经打过注释 了,这次我们就只在新加的代码旁边打注释了
任务三:按空格键的时候发射子弹,一个屏幕上最多发射三颗子弹,子弹向上飞行,到屏幕后消失
主文件()
import sys
import pygame
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((0, 0), pygame.FULLSCREEN)
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().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._update_screen()
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#这里是键盘按到空格键会返回KEYDOWN,此时调用开火函数
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
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 _fire_bullet(self):
#这是一个判断语句,如果子弹数小于三,我们就可以执行下面的函数
if len(self.bullets) < self.settings.bullets_allowed:
#创建一个子弹新的bullet,把它加入到编组bullet储存
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _update_bullets(self):
# 更新子弹的位置函数
self.bullets.update()
#不断循环删除子弹,子弹这里是他的y轴超出了屏幕,我们就删除
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
def _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()
if __name__ == '__main__':
ai = AlienInvasion()
ai.run_game()
子弹的控制类
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
# 现在原点处创建一颗子弹,同时子弹的宽高在设置类的参数里引入
self.rect = pygame.Rect(0, 0, self.settings.bullet_width,
self.settings.bullet_height)
#子弹的初始位置设置成了飞船的初始位置
self.rect.midtop = ai_game.ship.rect.midtop
# 用float储存这个位置
self.y = float(self.rect.y)
def update(self):
"""子弹向上飞"""
# 每一次子弹向上移动,y轴在不断地自减
self.y -= self.settings.bullet_speed
# 把最新的位置给子弹
self.rect.y = self.y
def draw_bullet(self):
"""画出子弹,参数是用self里面储存的参数填充的"""
pygame.draw.rect(self.screen, self.color, self.rect)
设置类文件
class Settings:
def __init__(self):
# Screen settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# Ship settings
self.ship_speed = 1.5
# 这里在设置子弹的一系列的参数,等会直接调用这个类
self.bullet_speed = 1.0
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
#最大的子弹数为3
self.bullets_allowed = 3
飞船的参数设置文件
import pygame
class Ship:
def __init__(self, ai_game):
self.screen = ai_game.screen
self.settings = ai_game.settings
self.screen_rect = ai_game.screen.get_rect()
# Load the ship image and get its rect.
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
# Start each new ship at the bottom center of the screen.
self.rect.midbottom = self.screen_rect.midbottom
# Store a decimal value for the ship's horizontal position.
self.x = float(self.rect.x)
# Movement flags
self.moving_right = False
self.moving_left = False
def update(self):
# Update the ship's x value, not the rect.
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
# Update rect object from self.x.
self.rect.x = self.x
def blitme(self):
self.screen.blit(self.image, self.rect)
手把手讲解超详细python入门游戏项目‘打外星飞船’(四)
在经过创立屏幕、飞船移动和设置子弹,我们这里开始设置外形人的创建和移动。我们这里主要的任务是:创建一众外星人让它们充满屏幕,让他们向下和两边移动,这里继承了上面四个文件外我们还多键一个文件来管理外星人的类,也就是五个文件。这里后三个文件没有太大的变化,我们主要调整了前两个文件
主文件
import sys
import pygame
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((0, 0), pygame.FULLSCREEN)
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().height
pygame.display.set_caption("Alien Invasion")
self.ship = Ship(self)
self.bullets = pygame.sprite.Group()
self.aliens = pygame.sprite.Group()
self._creat_fleet()
def run_game(self):
while True:
self._check_events()
self.ship.update()
self._update_bullets()
#这里多加了外星人的运动函数
self._update_aliens()
self._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
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 _fire_bullet(self):
if len(self.bullets) < self.settings.bullets_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _update_bullets(self):
self.bullets.update()
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
def _update_aliens(self):
"""
判断外星人有没有到边,到了就调整位置
"""
self._check_fleet_edges()
self.aliens.update()
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
#总宽度是所有外星人的宽度加间隔,间隔也取外星人的宽度乘上总行数
alien.x = alien_width + 2 * alien_width * alien_number
#要创建的外星人的数
alien.rect.x = alien.x
#总高度是所有外星人的高加间隔,间隔也取外星人的宽度,乘上总列数
alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
self.aliens.add(alien)
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 _update_screen(self):
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
pygame.display.flip()
if __name__ == '__main__':
# Make a game instance, and run the game.
ai = AlienInvasion()
ai.run_game()
外星人控制
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
# 记录下外星人的位置
self.x = float(self.rect.x)
def check_edges(self):
#判断是否超过屏幕
"""看看飞船有没有超过屏幕,如果屏幕大于右边的屏幕的数后者小于零是超越屏幕的左边"""
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right or self.rect.left <= 0:
return True
def update(self):
"""这里用乘积的办法,每次就是用所在的x坐标减去方向*1or-1"""
self.x += (self.settings.alien_speed *
self.settings.fleet_direction)
self.rect.x = self.x
子弹管理类
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
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):
# Update the decimal position of the bullet.
self.y -= self.settings.bullet_speed
# Update the rect position.
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect)
总设置参数
class Settings:
"""这个类用于储存一些参数"""
def __init__(self):
# 屏幕参数
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# 飞船参数
self.ship_speed = 1.5
# 子弹参数
self.bullet_speed = 1.0
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
self.bullets_allowed = 3
# 外星人左右移动的速度1,向下移动的速度10
self.alien_speed = 1.0
self.fleet_drop_speed = 10
# 这里其实是在设置每次外形人飞船的位置,1为右移一位,-1为左移
self.fleet_direction = 1
飞船设置
import pygame
class Ship:
"""飞船参数"""
def __init__(self, ai_game):
self.screen = ai_game.screen
self.settings = ai_game.settings
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
self.x = float(self.rect.x)
self.moving_right = False
self.moving_left = False
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 blitme(self):
self.screen.blit(self.image, self.rect)
手把手讲解超详细python入门游戏项目‘打外星飞船’(五)
这是最后一个项目了,前面我们讲了整个游戏页面的控制、飞船、子弹、外星人的创建,这里我们讨论一下子弹射杀外星人和整个游戏的结束,我们这里的文件一共有六个:主函数、飞船、外星飞船、子弹、设置参数、跟踪游戏统计信息六个文件。在这里我们要实现的任务是:子弹碰到外形飞船是让飞船消失,同时飞船碰到外星人飞船或者外星人飞船碰到屏幕低端结束游戏。
主函数
import sys
from time import sleep
import pygame
from settings import Settings
#我们需要创建一个文件去储存游戏统计信息,这里引入主函数
from game_stats import GameStats
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((0, 0), pygame.FULLSCREEN)
self.settings.screen_width = self.screen.get_rect().width
self.settings.screen_height = self.screen.get_rect().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._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
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 _fire_bullet(self):
"""创键一个新的子弹并把他加入子弹组"""
if len(self.bullets) < self.settings.bullets_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _update_bullets(self):
"""变换子弹的位置并且删除旧的子弹"""
#变换位置
self.bullets.update()
# 删除旧的子弹
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
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 _update_aliens(self):
"""
判断是否是已经到了边缘,同时更新飞船的位置
"""
self._check_fleet_edges()
self.aliens.update()
# 检查是否飞船和外星人飞船是否相碰
if pygame.sprite.spritecollideany(self.ship, self.aliens):
self._ship_hit()
#检查外星人飞船是否到了底部
self._check_aliens_bottom()
def _check_aliens_bottom(self):
"""Check if any aliens have reached the bottom of the screen."""
screen_rect = self.screen.get_rect()
for alien in self.aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
# Treat this the same as if the ship got hit.
self._ship_hit()
break
def _ship_hit(self):
"""响应飞船被外星人撞到时候"""
if self.stats.ships_left > 0:
# Decrement ships_left.
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 _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
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
self.aliens.add(alien)
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 _update_screen(self):
"""更新屏幕上的图片"""
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
pygame.display.flip()
if __name__ == '__main__':
# Make a game instance, and run the game.
ai = AlienInvasion()
ai.run_game()
外星人文件
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
#下载图片
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
# 储存飞船的位置.
self.x = float(self.rect.x)
def check_edges(self):
"""返回flag如果飞船到达边缘"""
screen_rect = self.screen.get_rect()
if self.rect.right >= screen_rect.right or self.rect.left <= 0:
return True
def update(self):
"""向左或者向右移动飞船"""
self.x += (self.settings.alien_speed *
self.settings.fleet_direction)
self.rect.x = self.x
子弹文件
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
# 现在原点创建一个矩形然后移动到飞船头部
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):
"""子弹超过屏幕后移除子弹"""
# Update the decimal position of the bullet.
self.y -= self.settings.bullet_speed
# Update the rect position.
self.rect.y = self.y
def draw_bullet(self):
"""在屏幕上画出子弹"""
pygame.draw.rect(self.screen, self.color, self.rect)
参数设置类文件
class Settings:
"""设置一系列参数"""
def __init__(self):
"""初始化游戏的参数"""
# 屏幕的大小
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# 飞船的速度等参数
self.ship_speed = 1.5
self.ship_limit = 3
# 子弹的设置
self.bullet_speed = 1.5
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
self.bullets_allowed = 3
# 外星人飞船的设置
self.alien_speed = 1.0
self.fleet_drop_speed = 10
# fleet_direction of 1 represents right; -1 represents left.
self.fleet_direction = 1
飞船文件
import pygame
class Ship:
"""管理飞船的类"""
def __init__(self, ai_game):
"""初始化飞船并且调动他的位置."""
self.screen = ai_game.screen
self.settings = ai_game.settings
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
self.x = float(self.rect.x)
# 移动flag
self.moving_right = False
self.moving_left = False
def update(self):
"""移动飞船根据flag"""
# Update the ship's x value, not the rect.
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 blitme(self):
"""在目前位置画出飞船"""
self.screen.blit(self.image, self.rect)
def center_ship(self):
"""把飞船放在屏幕中央"""
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
跟踪游戏统计文件
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
这个是最后的配置的外星人和飞船图片