用pygame写一款飞船游戏(笔记)

pygame为创建一款游戏提供了很多方便地操作,下面将会用此写一款打飞机游戏。使用的版本为python3。笔记可能有些许错误,请见谅。
最后游戏界面如下:
在这里插入图片描述
游戏大致想法:外星人水平移动,碰到左右边缘x轴的速度方向改变,同时y轴会运动。当外星人碰到飞船或到达边缘时,扣除生命值,重置外星人和飞船位置。每清除完一波外星人,游戏难度提升。

1.整体模块大致介绍

一共有9个模块,如下图
在这里插入图片描述

设置类模块:我们可以将游戏基本设置属性放在里面,例如窗口的宽和长,背景颜色,又例如飞船速度,外星人运动速度等游戏难度相关的属性

功能函数模块:里面装着显示窗口,更新飞船位置等等函数,在主模块中通过调用功能函数模块便基本实现游戏

飞船类模块:定义了一个飞船类,在这里存储着飞船的图片,以及通过飞船图片获取得来的飞船矩形。还有更新飞船位置的函数,在pygame中,可以通过更新矩形位置,来实现物体的移动

子弹类模块:我们用创建有色矩形的方式来创建子弹,类中存储着子弹颜色,子弹速度,子弹宽度,其中一部分可以从设置类对象中获取。还有更新子弹位置的函数,绘制子弹的函数

外星人类模块:定义一个外星人类,里面包含着外星人的图片,代表外星人的矩形,更新外星人位置的函数等

游戏统计类模块:存储着游戏进程中,玩家得分,历史高分记录,当前生命值等

按钮类模块:可用于生成开始按钮的类,类中存储着显示的字体,将文字渲染后的图片等

显示板类:可用于生成显示的分数,生命条,历史高分条

2.模块详细介绍

游戏功能函数模块几乎包含运行整个游戏所需的函数,我们可以先完善其他模块的内容,最后再完善游戏功能模块。

2.1游戏设置类模块

class Settings():
	def __init__(self):
		self.bgc = (230,230,230)		#背景颜色
		self.screen_width = 1200
		self.screen_height = 700		#屏幕大小
		self.ship_hp = 3				#飞船血条
				
		self.bullet_width = 20
		self.bullet_height = 3
		self.bullet_color = (0x66,0xcc,0xff)	#子弹大小颜色
		self.bullet_max = 5		#允许射出的子弹最大数目
		
		self.alien_yspeed = 10	#外星人y轴移动速度
		self.alien_xdirection = 1	#外星人x轴移动方向
		
		self.speedup_scale = 1.1	#速度提升倍率和分数提升倍率
		self.initial_speed()#初始化飞船,子弹,外星人水平速度。
		
	def speed_up(self):
		self.alien_xspeed *= self.speedup_scale
		self.ship_speed *= self.speedup_scale
		self.bullet_speed *= self.speedup_scale
		self.alien_score += 20
	
	def initial_speed(self):
		'''初始化设置'''
		self.alien_xspeed = 1
		self.ship_speed = 3
		self.bullet_speed = 1.5
		self.alien_score = 50	#射杀一个外星人后有50分
		
	def initial_ship_life(self):
		self.ship_hp = 3		#重置飞船生命值

在游戏设置类模块中,我们编写了游戏很多的参数。如果想改变窗口大小,游戏难度可以通过游戏设置类来改变。
考虑玩法,因为会有难度提升的元素,所以我们需要有一个速度提升速率,然后在一个函数中调节游戏难度相关元素,在清除一波外星人后调用。同时如果生命值全用掉,需要重来,我们需要初始化这些设置,于是便有初始速率的函数。

2.2飞船类模块

import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
	def __init__(self,screen,ai_settings):
		super().__init__()
		self.image = pygame.image.load('bship.png') #加载图形
		self.screen = screen #获取屏幕的surface
		self.screen_rect = self.screen.get_rect()		#获取屏幕矩形边框
		self.ship_rect = self.image.get_rect()	#获取飞船初始边框
		self.ship_rect.centerx = self.screen_rect.centerx
		self.ship_rect.bottom = self.screen_rect.bottom #将飞船位置移动到屏幕底部终点
		self.rect = self.ship_rect
		self.ship_width = self.rect.width
		
		self.left_flag = False
		self.right_flag = False		#飞船的移动标志
		
		self.settings = ai_settings		#引入系统设置
		
	def blitme(self):
		'''绘制飞船的函数'''
		self.screen.blit(self.image,self.ship_rect)  #绘制飞船
	
	def update(self):
		'''更新飞船移动标志的函数'''
		if self.left_flag and self.ship_rect.left > 0:
			self.rect.centerx -=	self.settings.ship_speed
		if self.right_flag and self.ship_rect.right < self.screen_rect.right:
			self.rect.centerx +=	self.settings.ship_speed
			
	def reset_ship(self):
		self.ship_rect.centerx = self.screen_rect.centerx	
		#重新放置飞船
		

游戏的一帧就是一幅图像,我们绘制一幅图像会有图层叠放顺序,而一个图层在pygame里面就是一个surface

函数功能
pygame.image.load(图片路径)返回一个对应的surface
surface.get_rect()返回surface对应的矩形

rect的相关参数

参数意义
rect.centerrect的中心
rect.centerxrect的中心x坐标
rect.centeryrect的中心y坐标
rect.bottom/top/left/rightrect的各边界
rect.width矩形的宽度
rect.height矩形的高度
rect.x矩形左上角x坐标
rect.y矩形左上角y坐标

在上面的飞船类模块中,有两个移动标志,是为了在游戏功能函数模块中检测按钮事件,改变移动标志,让飞船移动的。

Sprite是从pygame.sprite引入的一个类,主要方便对继承该类的类对象进行编组,进行多元素管理。飞船类继承Sprite类是为了制作左上方的血条。

2.3子弹类模块

import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
	def __init__(self,ai_setting,screen,ship):
		super().__init__()
		self.screen = screen		#获取当前屏幕
		self.rect = pygame.Rect(0,0,ai_setting.bullet_width,ai_setting.bullet_height)		#新建代表子弹的矩形
		self.rect.centerx = ship.ship_rect.centerx
		self.rect.top = ship.ship_rect.top			#将位置调整至飞船顶部
		self.color = ai_setting.bullet_color	#设置子弹颜色
		self.speed = ai_setting.bullet_speed	#设置子弹速度

		
	def update(self):
		self.rect.y -= self.speed
		
	def draw_bullet(self):
		pygame.draw.rect(self.screen,self.color,self.rect)		#绘制子弹	
函数功能
pygame.Rect(x,y,width,height)以(x,y)作为将创作矩形的左上角坐标,创建一个宽为width,高为height的矩形
pygame.draw.rect(surface,颜色,rect)在surface中绘制指定颜色的矩形

子弹类模块中,用pygame绘制一个简单的矩形来代表子弹。

在update()函数中,通过更改子弹代表矩形的左上角y坐标来让其移动。另外,子弹类要继承Sprite类,是为了对其进行编组,其必要性比飞船类继承Sprite类更大。后面通过向编组中添加元素,调用编组.update()就能对里面的元素全部调用update函数。以及检测碰撞可以使用。update()函数有点类似C++中的虚函数,名字不能变。

2.4外星人类模块

import pygame
from pygame.sprite import Sprite

class Alien(Sprite):
	def __init__(self,ai_settings,screen):
		super().__init__()
		self.ai_settings = ai_settings
		self.screen = screen
		self.image = pygame.image.load("aship.png")		#加载敌人图片
		self.rect = self.image.get_rect()				#获取矩形
		self.rect.x = self.rect.width
		self.rect.y = self.rect.height		#开始矩形默认坐标位左上角,移动一个身位
		
	def check_edge(self):
		screen_rect = self.screen.get_rect()
		if self.rect.right >= screen_rect.right or self.rect.left <=0:
			return True		#检测是否到达边界
			
	def update(self):
		'''向左或向右移动外星人'''
		self.rect.x += (self.ai_settings.alien_xspeed * 
								self.ai_settings.alien_xdirection)

外星人类同样要继承Sprite类,方便后面编组。

update()函数用来更新其x坐标,因为update()函数几乎每一帧都会调用,而y轴的移动只有外星人碰到边缘后才会调用。

类中还有一个检查是否碰到窗口左右两边的函数,返回bool型值。从而在游戏功能函数模块中的函数调用检测是否到达边缘并改变alien_xdirection即外星人的x轴移动方向。

2.5游戏统计类模块

import json
class Game_stats():
	'''跟踪游戏的统计信息'''
	def __init__(self,ai_settings):
		self.ai_settings = ai_settings
		self.ship_hp = ai_settings.ship_hp		#获取飞船血条个数
		self.score = 0							#统计得分
		self.game_active = False
		self.level = 1							#统计等级	
		with open("high_score.json",'r') as score_file:
			self.high_score = json.load(score_file)
		
	def reset_ship_hp(self):
		self.ship_hp = self.ai_settings.ship_hp	#重新设置生命
		self.score = 0							#重新设置得分
		
	def update_high_score(self):
		if self.score > self.high_score:
			self.high_score = self.score	#更新最高分
			with open("high_score.json",'w') as score_file:
				json.dump(self.high_score,score_file)

该类的主要操作就是统计生命值,分数等等。

有个重置生命值的函数,在生命值耗尽重新开始游戏时调用,更新最高分函数,可以在每击杀一个外星人时调用一次,里面还会判断是否更新。

这里用了json文件来存储高分记录。我们可以先在当前文件夹创建一个json文件,并写入0值,什么都不写会报错。

2.6游戏按钮类模块

import pygame.font

class Button():
	def __init__(self,ai_settings,screen,msg):
		'''创建对应文本msg的按钮'''
		self.screen = screen
		self.screen_rect = screen.get_rect()		#获取窗口矩形
		
		self.width,self.height = 200,50			#设定按钮矩形长宽
		self.button_color = (0,255,0)			#设定按钮背景颜色
		self.text_color =  (255,255,255)		#设定按钮字体颜色
		self.font = pygame.font.SysFont(None,48)#设定按钮字体字号
		
		self.rect = pygame.Rect(0,0,self.width,self.height)
		self.rect.center = self.screen_rect.center#设定按钮矩形,并移动到屏幕中心
		
		self.msg_image = self.font.render(msg,True,self.text_color,self.button_color)	#将文字渲染成图片
		self.msg_image_rect = self.msg_image.get_rect()
		self.msg_image_rect.center = self.rect.center		#设定图片的矩形,并移动中心
				
	def draw_button(self):
		self.screen.fill(self.button_color,self.rect)
		self.screen.blit(self.msg_image,self.msg_image_rect)
函数功能
pygame.font.SysFont(字体,字号,bool1,bool2)创建字体,bool1为是否粗体,bool2为是否斜体,默认False。字体None为默认字体。
Font对象.render(文本,bool,c1,c2)将文本以对应字体渲染成图片,bool型值为是否开启抗锯齿功能,c1为文本颜色,c2为背景颜色。返回surface
surface1.fill(color,rect)在surface1上的rect填充颜色
surface1.blit(surface2,rect)在surface1上对应矩形处绘制surface2

font模块详细:https://blog.csdn.net/qq_41556318/article/details/86303502

在这里我们主要是对play按钮的新建,先用pygame.font.SysFont(None,48)创建字体,然后用font.render(...)来得到文本的surface。最后绘制时先绘制背景矩形,在背景surface上绘制文本的surface。绘制背景矩形也可以用子弹类用的pygame.draw.rect()。这里要先绘制背景矩形是因为,文本surface的矩形往往事前较难知道多大。可能偏大,可能偏小。
下面第一幅图为不绘制按钮背景矩形,第二幅为绘制后。
在这里插入图片描述
在这里插入图片描述

2.7 显示板类模块

from Ship import Ship
import pygame
from pygame.sprite import Group

class Show_board():
	def __init__(self,ai_settings,screen,stats):
		self.screen = screen
		self.screen_rect = screen.get_rect()
		self.ai_settings = ai_settings
		
		self.text_color = (30,30,30)
		self.font = pygame.font.SysFont(None,48)	#设置字体字号
		self.prep(stats)
		
	def prep_score(self,stats):
		'''准备当前得分文本surface'''
		self.score = int(round(stats.score,-1))	#精确分数到十位
		self.total_score = "{:,}".format(self.score)#数字格式化,每隔三位加一个逗号
		self.total_score_image = self.font.render(self.total_score,
								True,self.text_color,self.ai_settings.bgc)	#将分数渲染成图片
		self.total_score_image_rect = self.total_score_image.get_rect()	#获取图片矩形
		self.total_score_image_rect.right = self.screen_rect.right -20	
		self.total_score_image_rect.top = self.screen_rect.top			#设置矩形位置
		
	def prep_high_score(self,stats):
		'''准备最高得分文本surface'''
		self.high_score = int(round(stats.high_score,-1))
		self._high_score = "{:,}".format(self.high_score)
		self.high_score_image = self.font.render(self._high_score,True,
									self.text_color,self.ai_settings.bgc)
		self.high_score_image_rect = self.high_score_image.get_rect()	#获取矩形
		self.high_score_image_rect.centerx = self.screen_rect.centerx	
		self.high_score_image_rect.top = self.screen_rect.top			#设置矩形位置
	
	def prep_level(self,stats):
		'''准备当前难度文本surface'''
		self.level = stats.level
		self.level_str = "level:" + str(self.level)
		self.level_image = self.font.render(self.level_str,True,
								self.text_color,self.ai_settings.bgc)	
		self.level_image_rect = self.level_image.get_rect()				#获取矩形
		self.level_image_rect.right = self.screen_rect.right-20
		self.level_image_rect.top = self.screen_rect.top + 32			#设置矩形位置
		
	def prep_hp(self,stats):
	'''准备生命值的图像'''
		self.hp = stats.ship_hp
		self.ships = Group()
		for number in range(self.hp):
			ship = Ship(self.screen,self.ai_settings)					#新建一个飞船图标
			ship.rect.x = 10 + number * ship.ship_width
			ship.rect.y = 10											#设置图标位置
			self.ships.add(ship)
			
	def prep(self,stats):
		self.prep_score(stats)
		self.prep_high_score(stats)
		self.prep_level(stats)
		self.prep_hp(stats)
		
	def draw_board(self):
		'''绘制文本的函数'''
		self.screen.blit(self.total_score_image,self.total_score_image_rect)
		self.screen.blit(self.high_score_image,self.high_score_image_rect)
		self.screen.blit(self.level_image,self.level_image_rect)
		self.ships.draw(self.screen)
函数功能
round(number,精确位数)返回number对应精确位数的float型数,1位小数点后一位,-1为精确到十位,-2为百位,以此类推。
“:,”.format(number)返回字符串,内容为number每隔3位加逗号。如1000000会变成1,000,000

显示板类只要是在屏幕上显示生命值,当前分数,最高分数,当前游戏难度。做法都是得到渲染文本后的surface,然后进行绘制,这里文本背景颜色用一开始设置类中的窗口背景颜色就可以了。

很多模块都需要读取窗口的surface,来根据surface的某些参数确定自己的位置。

2.8主模块

import pygame

from Settings import Settings
from Ship import Ship
import GameFunction as gf
from pygame.sprite import Group
from Alien import Alien
from Game_stats import Game_stats
from button import Button
from Show_board import Show_board


def run_game():
	'''运行游戏'''
	settings = Settings()		#新建设置类对象
	pygame.init()	#初始化
	screen = pygame.display.set_mode((settings.screen_width,settings.screen_height))	#新建一个屏幕并设置屏幕宽和高度
	pygame.display.set_caption("打飞机")		#设置窗口标题
	ship = Ship(screen,settings)		#新建飞船对象
	bullets = Group()					#创建存储子弹的编组
	aliens = Group()					#创建存储外星人的编组
	gf.create_aliens(settings,screen,ship,aliens)		#添加元素
	stats = Game_stats(settings)		#新建统计类
	play_button = Button(settings,screen,"PLAY")	#新建play按钮
	show_board = Show_board(settings,screen,stats)		#新建显示面板
	
	while True:
		gf.check_event(settings,screen,ship,bullets,stats,play_button)#检查按键事件
		if stats.game_active == True:
			ship.update()				#更新飞船位置
			gf.update_bullets(bullets,aliens,settings,screen,ship,stats,show_board)#更新和绘画子弹的函数
			gf.update_aliens(settings,screen,bullets,aliens,ship,stats,show_board)#更新外星人位置并检查碰撞
		gf.update_Screen(settings,screen,ship,bullets,aliens,stats,play_button,
										show_board)#更新屏幕
		
run_game()
	
函数功能
pygame.display.set_mode((width,height))设置主窗口大小,返回surface
pygame.display.set_caption(标题)设置标题

Group()为新建一个编组,可以往编组里面添加元素

函数功能
group.update()对里面的每个精灵调用update(),精灵的update()需要自己定义
group.draw(surface)在surface中自动调用surface.blit(…)函数
group.add(a)添加元素a
group.remove(a)删除元素a
group.sprites()以列表形式返回编组中的精灵
group.empty()判断编组中是否含有元素

update(),draw()相关定义:https://www.cnblogs.com/huwt/p/10333500.html

在主模块中我们会做一下事情:
1.创建主窗口
2.创建飞船对象
3.创建子弹空编组
4. 创建外星人空编组
5. 调用创建一波外星人函数
6. 创建统计类对象
7. 创建play按钮
8. 创建显示板类对象
9. 主循环:

1.检查事件按钮函数
2.如果游戏状态活跃,执行更新飞船,子弹,外星人的函数
3.更新屏幕内容函数

创建一波外星人的函数,及主循环的函数都存储在游戏功能函数模块中。

我们在游戏设置类会有个游戏状态的变量,开始时为False,要允许窗口有内容显示及点击退出,检查事件按钮函数和更新屏幕内容函数不检测游戏状态。其他则未点击play时不执行。

3.游戏功能类模块

引入模块:
import pygame
import sys
from Bullets import Bullet
from Alien import Alien
from time import sleep

3.1 检查事件按钮函数

def check_event(ai_setting,screen,ship,bullets,stats,play_button):
	'''按钮事件检查'''
	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.right_flag = True
			elif event.key == pygame.K_LEFT:
				ship.left_flag = True			#按钮按下相关操作
			elif event.key == pygame.K_SPACE:
				new_bullet = Bullet(ai_setting,screen,ship)
				if len(bullets) < ai_setting.bullet_max:
					bullets.add(new_bullet)			#按下空格添加子弹
		elif not stats.game_active and event.type == pygame.MOUSEBUTTONDOWN:
			mouse_x,mouse_y = pygame.mouse.get_pos()	#获取鼠标位置
			flag = play_button.rect.collidepoint(mouse_x,mouse_y)	#检测鼠标是否在矩形中
			if not stats.game_active and flag:
				stats.game_active = True		#将游戏状态设置为可以开始
				pygame.mouse.set_visible(False)	#隐藏鼠标
				
		elif event.type == pygame.KEYUP:
			if event.key == pygame.K_RIGHT:
				ship.right_flag = False
			if event.key == pygame.K_LEFT:
				ship.left_flag = False			#松开按钮相关操作
函数功能
pygame.event.get()获取键盘和鼠标的所有事件
sys.exit()程序终止
rect.collidepoint(x,y)检查(x,y)点是否在rect中
pygame.mouse.get_pos()获取当前鼠标的x,y值
pygame.mouse.get_visible(bool)设置鼠标在窗口内可见或不可见

event.type 事件类型

事件类型意义
pygame.QUIT点击窗口关闭按钮
pygame.KEYDOWN按钮按下
pygame.KEYUP按钮松开
pygame.MOUSEBUTTONDOWN鼠标点击(左/右键)

event.key按钮类型

按钮类型意义
pygame.K_RIGHT方向右键
pygame.K_LEFT方向左键
pygame.K_SPACE空格键

在这个检测按钮事件的函数中,我们先用for event in pygame.event.get()来获取全部事件,然后先判断event.type,如果是游戏非活跃状态下点击鼠标,则先用pygame.mouse.get_pos()获取鼠标坐标检测play_button.rect.collidepoint(x,y)来检测是否有点击到正确的矩形,如果有则设置游戏活跃状态为True

如果是按下键盘按钮,则检测是按下哪个按钮,如果是方向键则设置飞船的允许移动标志为True,如果是空格键,我们限定最多射出5发子弹,满足条件时,才往子弹编组中添加新的子弹。

如果是松开键盘按钮,则检测是松开哪个按钮,这时我们只用考虑方向键,并将对应的移动标志设置为False就可以了。

3.2 更新绘制屏幕的函数

def  update_Screen(ai_settings,screen,ship,bullets,aliens,stats,play_button,
											show_board):
	'''绘制屏幕内容的函数'''
	screen.fill(ai_settings.bgc)		#先图刷背景颜色
	ship.blitme()						#画好飞船位置
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	aliens.draw(screen)					#对编组每一个元素进行绘制
	if not stats.game_active:
		play_button.draw_button()
	show_board.draw_board()
	pygame.display.flip()				#显示出来
函数功能
pygame.display.flip()更新待显示的surface到屏幕上

这个函数里面,我们如同将各个图层组合起来形成一幅图像。
我们先用screen.fill(...)来填充背景颜色,然后调用ship.blitme()函数来绘制飞船,因为子弹我们是通过绘制矩形的方式来呈现,没有image这个属性,所以我们不能直接用bullets.draw(screen)函数而需要逐个绘制子弹。接着直接aliens.draw(screen)就能直接绘制外星人,相当于调用了screen.blit(alien.image,alien.rect),所以类定义时需要有这两个数据成员。

接着,在游戏活跃状态为False时调用play_button.draw_button绘制PLAY按钮,接着则是调用show_boadrd.draw_board()将显示板的其他元素显示出来。最后则是调用pygame.display.flip()来让所有surface显示

3.3 创建外星人及群的函数

def create_alien(ai_settings,screen,aliens,number_x,number_y):
	'''创建一个外星人的函数'''
	alien = Alien(ai_settings,screen)
	alien.rect.x = alien.rect.width + 2 * alien.rect.width * number_x
	alien.rect.y = alien.rect.height + 2 * alien.rect.height * number_y
	#计算这个外星人的坐标
	aliens.add(alien)		#将该外星人添加进编组中

def get_alien_numberx(ai_settings,alien_width):
	'''计算一行能有多少个外星人的函数'''
	total_space_x = ai_settings.screen_width - 2 * alien_width #一行总长度
	number = int(total_space_x/(2 * alien_width))		#一行外星人个数
	return number

def get_alien_numbery(ai_settings,ship_height,alien_height):
	'''计算一列能有多少个外星人的函数'''
	total_space_y = ai_settings.screen_height - ship_height - 3*alien_height
	number = int(total_space_y/(2 * alien_height))
	return number

def create_aliens(ai_settings,screen,ship,aliens):
	'''创建外星人群的函数'''
	alien = Alien(ai_settings,screen)
	alien_width = alien.rect.width
	alien_height = alien.rect.height	#获取一个外星人的宽度与高度
	total_number_x = get_alien_numberx(ai_settings,alien_width)
	total_number_y = get_alien_numbery(ai_settings,ship.ship_rect.height,alien_height)
	#获取行和列
	for number_y in range(total_number_y):
		for number_x in range(total_number_x):
			create_alien(ai_settings,screen,aliens,number_x,number_y)
	#创建外星人	

在创建一个外星人的函数中,我们用了alien.rect.x = alien.rect.width + 2 * alien.rect.width * number_x这样的语句来创建对应位置的外星人,这里2*...可以改变,这里主要是为了在两个外星人之间留着一个外星人的空隙。
在这里插入图片描述

在计算外星人一行,一列有多少个外星人的函数中,我们想让一行中左右两边各差一个外星人才到达窗口左右边缘。一列中应考虑与飞船的距离及与窗口上边界差多少个外星人。这些可以自己调整。在计算number时都是2*...则是考虑两个外星人之间差一个外星人的身位。

在创建外星人群的函数中,我们先创建一个临时用的外星人,但不添加进编组以获取一个外星人的长和宽。接着调用计算一列、一行中有多少个外星人函数,最后用循环一个个创建外星人便可。

3.4 更新子弹位置的函数

def update_bullets(bullets,aliens,ai_settings,screen,ship,stats,show_board):
	'''更新子弹显示的函数'''
	bullets.update()			#调用编组中元素的所有update函数
	for bullet in bullets.copy():
		if bullet.rect.bottom <= 0:
			bullets.remove(bullet)		#将超出屏幕边界的子弹删除
	collision = pygame.sprite.groupcollide(bullets,aliens,True,True)
	if collision:
		for alien in collision.values():
			stats.score += ai_settings.alien_score	#射中后加分
		stats.update_high_score()					#检查是否需要更新最高分
		show_board.prep_score(stats)						#更新分数显示
		show_board.prep_high_score(stats)					#更新最高分显示
		
	if len(aliens) == 0:
		bullets.empty()
		ai_settings.speed_up()
		create_aliens(ai_settings,screen,ship,aliens)
		stats.level += 1
		show_board.prep_level(stats)
		#射杀完外星人后重新新建
函数功能
pygame.sprite.groupcollide(g1,g2,bool1,bool2)检查g1和g2之间是否有碰撞,如果有则根据布尔型值来确定是否删除编组对应发生碰撞的sprite,bool1对应g1,返回字典。

在更新子弹位置的函数中,我们先调用bullets.update()来更新每颗子弹的位置,然后检查是否有超出边界的,如果有则从编组中删除。接着我们调用pygame.sprite.groupcollide(...)来检查子弹和外星人两个编组间是否有碰撞,如果有碰撞删除对应的子弹和外星人,并且实现加分,判断是否超过历史高分,更新需要分数显示等等的功能。最后用len(aliens)判断是否击杀全部外星人,没有了则调用创建外星人群函数,并且调用ai_settings.speed_up()来提升难度并修改stats.level,最后更新游戏等级显示。

3.5 改变外星人群运动状态函数

def change_aliens_move(ai_settings,aliens):
	'''改变外星人群x轴移动方向,并让其在y轴移动一段距离'''
	for alien in aliens.sprites():
		alien.rect.y += ai_settings.alien_yspeed
	ai_settings.alien_xdirection *= -1

在这个函数中我们改变alien.rect.y并且改变外星人的x轴移动方向,在下一个检测左右边缘函数中,如果碰到左右边缘我们调用这个上面的函数。

3.6 检测外星人碰到左右边缘函数

def check_aliens_edge(ai_settings,aliens):
	'''检查外星人群是否有接触边缘的现象并改变运动方向'''
	for alien in aliens.sprites():
		if alien.check_edge():
			change_aliens_move(ai_settings,aliens)		#确一改变一群
			break

在这里我们遍历编组的sprite,并且调用alien.check_edge()来检测是否到达边缘,如果有一个到达则改变一整群的运动状态。

3.7 飞船被击中后的函数

def after_ship_hit(ai_settings,screen,bullets,aliens,ship,stats,show_board):
	'''飞船被击中后的函数'''
	stats.ship_hp -= 1		#减少生命值
	ship.reset_ship()		#重新放置飞船位置
	bullets.empty()			
	aliens.empty()			#清空外星人和子弹
	create_aliens(ai_settings,screen,ship,aliens)#重新放置子弹
	show_board.prep_hp(stats)	#更新生命值显示
	sleep(0.5)

在这里我们定义了外星人碰到飞船或到达屏幕底部后的行为,扣除生命值,重置飞船位置,清空当前外星人和子弹,再新建一群外星人,然后调用show_board.prep_hp(stats)来更新生命值面板,前面已有from time import sleep,最后我们调用sleep(0.5)来使其停顿一会。

3.8 检查外星人是否到达底部的函数

def check_aliens_bottom(ai_settings,screen,bullets,aliens,ship,stats):
	'''检查外星人是否到达底部'''
	for alien in aliens.sprites():
		screen_rect = screen.get_rect()
		if alien.rect.bottom >= screen_rect.bottom:
			after_ship_hit(ai_settings,screen,bullets,aliens,ship,stats)
			break

3.9 更新外星人位置的函数

def update_aliens(ai_settings,screen,bullets,aliens,ship,stats,show_board):
	'''检查是否有外星人处于屏幕边缘并更新位置的函数'''
	check_aliens_edge(ai_settings,aliens)
	aliens.update()
	if pygame.sprite.spritecollideany(ship,aliens):
		after_ship_hit(ai_settings,screen,bullets,aliens,ship,stats,show_board)
	check_aliens_bottom(ai_settings,screen,bullets,aliens,ship,stats)

	if stats.ship_hp < 1 :
		stats.game_active = False
		ai_settings.initial_speed()		#重置速度
		ai_settings.initial_ship_life()	#重置飞船生命
		stats.level = 1					#重置等级

函数功能
pygame.sprite.spritecollideany(sprite,group)检测sprite和group之间的碰撞,返回布尔值

pygame中的碰撞检测:https://www.cnblogs.com/msxh/p/5027688.html
在这个函数中,我们先调用检查外星人碰到左右边缘的函数,然后调用aliens.update()来更新外星人的水平位置,接着通过pygame.sprite.spritecollideany(...)来检测飞船和外星人是否有碰撞(这里飞船类中如果没有继承Sprite也是可以的。可能在类属性定义中包含需要的标识符)如果有碰撞调用飞船被击中的函数,然后再检测外星人是否到达底部,如果这里有到达,在函数中也会调用飞船被击中的函数。最后则是判断生命值是否小于1,小于则重置游戏。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值