飞机大战游戏---Pygame

一、基础知识

pygame安装

pygame就是一个Python模块,专为店子游戏设计

安装pygame(Windows):

pip install pygame

验证安装

python -m pygame.examples.aliens

会出现一个游戏界面,则表示安装成功。

pygame快速入门

1、使用pygame创建图形窗口

1.1游戏的初始化和退出

要使用pygame提供的所有功能之前,需要调用init方法
在游戏结束前需要调用quit方法

方法说明
pygame.init()导入并初始化所有pygame模块,使用其他模块之前,必须先调用init方法
pygame.quit()卸载所有pygame模块,在游戏结束之前调用!

在这里插入图片描述

1.2理解游戏中的坐标

坐标系:
 原点在左上角(0,0)
 x轴水平方向向右,逐渐增加
 y轴垂直方向向下,逐渐增加
在这里插入图片描述
 在游戏中,所有可见的元素都是以矩形区域来描述位置的:
  要描述一个矩形区域有四个要素:(x,y)(width,height)

pygame专门提供了一个类pygame.Rect用于描述矩形区域

Rect(x, y , width , height )  --->Rect

在这里插入图片描述
提示:
pygame.Rect 是一个比较特殊的类,内部只是封装了一些数字计算
 不执行pygame.init()方法同样能够直接使用

例子:

import pygame
first_rect = pygame.Rect(100,500,120,125)
print(' 第一个矩形区域的原点为: %d %d' %(first_rect.x , first_rect.y))
print(' 第一个矩形区域的尺寸为:%d %d' %(first_rect.width , first_rect.height))
print('尺寸:',first_rect.size)
1.3创建游戏主窗口
  • pygame专门提供了一个模块pygame.display用于创建、管理游戏窗口
方法说明
pygame.display.set_mode()初始化游戏显示窗口
pygame.display.update()刷新屏幕内容显示

set_mode 方法:

set_mode(resolution=(0,0),flags=0) -->Surface
  • 作用 —创建游戏显示窗口
  • 参数:
    resolution 指定屏幕的宽和高,默认创建的窗口大小和屏幕大小一致
    flags 参数指定屏幕的附加选项,例如是否全屏等等,默认不需要传递
    depth 参数表示颜色的位数,默认自动匹配
  • 注意:必须使用变量记录set_mode方法的返回结果。因为:后续所有的图像绘制都基于这个返回结果
#创建游戏主窗口
screen = pygame.display.set_mode((480,700))
1.4简单的游戏循环
  • 为了做到游戏程序启动后,不会立即退出,通常会在游戏程序中添加一个游戏循环
  • 游戏循环就是一个无限循环
  • 在创建游戏串口代码下方,增加一个无限循环(使用 while true)
  •   注意:游戏窗口不需要重复创建

2、理解图像并实现图像绘制

  • 在游戏中,能够看到的游戏元素大多都是图像
  •   图像文件初始是保存在磁盘上的,如果需要使用,第一步就需要被加载到内存中。
  • 要在屏幕上看到某一个图像的内容,需要按照三个步骤:
  • 1、使用pygame.image.load()加载图像的数据
  • 2、使用游戏屏幕对象,调用blit方法,将图像绘制到指定位置
  • 3、调用pygame.display.update()方法更新整个屏幕的显示
    在这里插入图片描述
    提示:要想在屏幕上看到绘制的结果,就一定要调用pygame.display.update()方法
    例子:
# 绘制背景图像
# 加载图像数据
bg=pygame.image.load("./images/background.png")
hero=pygame.image.load("./images/me1.png")
# blit绘制图像
screen.blit(bg,(0,0))
screen.blit(hero,(200,500))
# update更新屏幕显示
pygame.display.update()
理解update()方法的作用
  • 使用display.set_mode()创建的screen对象是一个内存中的屏幕数据对象
  • screen.blit方法可以在画布上绘制很多图像
  • display.update()会将画布的最终结果绘制在屏幕上,这样可以提高屏幕绘制效率,增加游戏的流畅度。

3、理解游戏循环和游戏时钟

3.1游戏中动画实现原理
  • 通过在电脑上每秒绘制60次,就能够到大非常连续高品质的动画效果。每次绘制的结果被成为帧Frame
3.2游戏循环

游戏的两个组成部分:

游戏循环的开始就意味着游戏的正式开始

在这里插入图片描述
游戏循环的作用:
1、保证游戏不会直接退出
2、变化图像位置—动画效果
 每个1/60 秒移动一下所有图像的位置
 调用pygame.display.update()更新屏幕显示
3、检测用户交互 —按键、鼠标等

3.3游戏时钟
  • pygame专门提供了一个类pygame.time.Clock可以非常方便的设置屏幕绘制速度—刷新帧率。
  • 要使用时钟对象需要两步:
  • 1)在游戏初始化创建一个时钟对象
  • 2)在游戏循环中让时钟对象调用tick(帧率)方法
  • tick方法会根据上次被调用的时间,自动设置游戏循环中的延时
# 创建时钟对象
clock = pygame.time.Clock()
# tick参数可以指定循环体内部循环的频率
clock.tick(60)  #在循环体内部使用
3.4简单动画实现

需求:
 1、在游戏初始化定义一个pygame.Rect的变量记录英雄的初始位置
 2、在游戏循环中每次让英雄的y-1 ----向上移动
 3、当y<=0时,将英雄丕东到屏幕的底部

提示:
每一次调用update()方法之前,需要把所有的游戏图像都重新绘制一边
而且应该最先重新绘制背景图像

3.5在游戏循环中监听事件

事件event

  • 就是启动游戏后,用户针对游戏所做的操作

  • 例如:点击关闭按钮,点击鼠标,按下键盘…
    监听

  • 在游戏循环中,判断用户具体操作

  • 只有捕获到用户具体的操作,才能针对性的做出响应

pygame中通过pygame.event.get()可以获得用户当前所做动作的事件列表
 用户可以同一时间做很多事情
提示:这段代码非常固定,几乎所有的pygame游戏都大同小异。

例子:

for event in pygame.event.get():
	#判断用户是否点击了关闭按钮
	if event.type == pygame.QUIT:
		print("退出游戏...")
		pygame.quit()
		#直接退出系统
		exit()

理解精灵和精灵组

在之前写的案列中,图像加载、位置变化、绘制图像都需要程序员编写代码分别处理。

为了简化开发步骤,pygame提供了两个类

  • pygame.sprite.Sprite —存储图像数据image和位置rect对象
  • pygame.sprite.Group
精灵(需要派生子类
image 记录图像数据
rect 记录在屏幕上的位置
update(*args):更新精灵位置
kill():从所有组中删除
精灵组
init(self , *精灵):
add(*sprites):向组中添加精灵
update(*args):让组中所有精灵调用update方法
sprites():返回所有精灵列表
draw(Surface):将组中所有精灵的image,绘制到Surface的rect位置

在这里插入图片描述

4.1创建游戏精灵:

新建一个plane_sprites.py文件
定义GameSprite类继承自pygame.sprite.Sprite

注意:

  • 如果一个类的父类不是object
  • 在重写初始化方法时,一定要先super()一下父类的__init__方法
  • 保证父类中实现的__init__代码能够被正常执行
    在这里插入图片描述
    属性:
  • image精灵图像,使用image_name加载
  • rect精灵大小,默认使用图像大小
  • speed精灵移动速度,默认为1
    方法:
    update每次更新屏幕时在游戏循环内调用
    让精灵的self.rect.x+=self.speed
    提示:
    image的get_rect()方法,可以返回pygame.Rect(0,0,图像宽,图像高)的对象

实现代码:

class GameSprite(pygame.sprite.Sprite):
	"""飞机大战游戏的精灵"""
	def __init__(self,image_name,speed=1):
	#调用父类的初始化方法
		super().__init__()
	#定义对象属性:
		#这里的image_name是图片的存放路径
		self.image = pygame.image.load(image_name)
		self.rect = self.image.get_rect()
		self.speed = speed
	#定义更新
	def update(self):
	#在屏幕的垂直方向上移动
		self.rect.y += self.speed
		
4.2使用游戏精灵和精灵组创建敌机

步骤
1、使用from导入plane_sprites模块

  • from导入的模块可以直接使用
  • import 导入的模块需要通过模块名来使用
    2、在游戏初始化创建精灵对象和精灵组对象
    3、在游戏循环中让精灵组分别调用update()和draw(screen)方法
    职责
  • 精灵
  • 封装图像image、位置rect和速度speed
  • 提供update()方法,根据游戏需求,更新位置rect
  • 精灵组
  • 包含多个精灵对象
  • update方法,让精灵组中的所有精灵调用update方法更新位置
  • draw(screen)方法,在screen上绘制精灵组中的所有精灵
    代码
#创建敌机的精灵
enemy = GameSprite("./images/enmey1.png")
#创建敌机的精灵组
enemy_group = pygame.sprite.Group(enemy)

#游戏循环
while True#tick参数可以指定循环体内部循环的频率,记得import time模块
	clock.tick(60# 捕获事件
    for event in pygame.event.get():
        # 判断事件类型是否是退出事件
        if event.type == pygame.QUIT:
            print('游戏退出...')
            # quit卸载所有模块
            pygame.quit()
            # exit() 直接终止当前正在执行的程序
            exit()
	#让精灵组调用两个方法
	#update --让组中的所有精灵更新位置
	enemy_group.update()
	#draw --在screen上绘制所有的精灵
	enemy_group.draw(screen)
	#screen是最开始创建的游戏窗口
	#screen = pygame.display.set_mode((480,700))
	

游戏框架搭建

目标—使用面向对象设计飞机大战游戏类

目标:

  • 明确主程序职责
  • 实现主程序类
  • 准备游戏精灵组

01.明确主程序职责

一个游戏程序的职责可以分为两个部分:

  • 游戏初始化
  • 游戏循环
    根据明确的职责,设计PlaneGame类如下:
    |PlaneGame|
    |:–|
    |screen |
PlaneGame
screen
clock
精灵或精灵组…
__init__(self):
__create_sprites(self):

start_game(self):
__event_handler(self):
__update_sprites(self):
__game_over():

在这里插入图片描述

提示:根据职责封装私有方法,可以避免某一个方法的代码写得太过冗长,如果某一个方法编写的太长,及不好阅读,也不好维护

方法职责
__event_handler(self)事件监听
__check_collide(self)碰撞检测—子弹销毁敌机、敌机撞毁英雄
__update_sprites(self)精灵组更新和绘制
__game_over()游戏结束

02.明确文件职责

在这里插入图片描述

  • plane_main:
    1、封装主游戏类
    2、创建游戏对象
    3、启动游戏
  • plane_sprites
    1、封装游戏中所有需要使用的精灵子类
    2、提供游戏的相关工具
    代码实现
  • 新建plane_main.py文件,并设置为可执行
  • 编写基础代码
import pygame
from plane_sprites import *

class PlaneGame(object):
	"""飞机大战主游戏"""
	def __init__(self)
		print("游戏初始化")
	def start_game(self):
		print("游戏开始")
		#游戏循环体
		while True:
			pass

if __name__=='__main__':
	#创建游戏对象
	game = PlaneGame()
	#启动游戏
	game.start_game()

在游戏初始化中需要设置游戏窗口、创建游戏时钟、创建精灵、精灵组。
在PlaneGame类中的__init__函数中进行这些操作:

def __init__(self):
	print("游戏初始化")
	#1.设置游戏窗口
	self.screen = pygame.display.set_mode(SCREEN_RECT.size)
	#SCREEN_RECT是定义在plane_sprites.py中的屏幕大小的常量。
	#通过设置次常量,当我们需要修改屏幕大小时,直接在plane_spriyes.py文件定义常量的位置修改即可,不需要在主函数中一个一个的去找和去修改值。
	#提示:python中并没有真正意义的常量,只是通过命名的约定---所有字母都是大写的就是常量,开发时不要轻易修改。
	#2.创建游戏时钟
	self.clock = pygame.time.Clock()
	#3.调用私有方法,创建精灵和精灵组
	self.__create_sprites()

#私有方法,创建精灵和精灵组
def __create_sprites(self):
	pass

在游戏循环中需要:设置刷新帧率、事件监听、碰撞检测、更新/绘制精灵组,更新屏幕显示。
代码如下:

def start_game(self):
	print("游戏开始")
	#游戏循环
	while True:
	#1.设置刷新帧率
		self.clock.tick(FRAME_PRE_SEC) 
		#这里的FRAME_PRE_SEC同上屏幕大小
	#2.事件监听:
		self.__event_handle()
	#3.碰撞检测:
		self.__check_collide()
	#4.更新/绘制精灵
		self.__update_sprites()
	#5.更新显示
		pygame.display.update()

#以下是游戏循环中函数的定义
#暂时只定义,不实现,稍后一个一个实现
def __event_handle(self):
	#使用pygame.event.get()获得操作事件
	#使用for循环遍历获得的操作事件
	for event in pygame.event.get():
		#判断是否退出游戏
		if event.type == pygame.QUIT:
			#定义的静态私有方法,不需要创建对象,直接就可以使用
			PlaneGame.__game_over()
		elif:
			pass

def __check_collide(self):
	pass

def __update_sprites(self):
	pass

#定义退出游戏的静态私有方法
@staticmethod
def __game_over():
	print("游戏结束")
	pygame.quit()
	exit()

03.设计背景类

背景交替滚动的思路

游戏启动后,背景图像会连续不断地向下方移动
在视觉上产生飞机不断向上飞行的错觉:
 游戏背景不断变化
 游戏的主角位置保持不变

解决方法:
1.创建两张背景图像精灵
  第1张完全和屏幕重合
  第2张在屏幕的正上方
2.两张图像一起向下方运动
  self.rect.y +=self.speed
3.当任意背景精灵的 rect.y >= 屏幕的高度,说明移动到屏幕下方
4.将移动到屏幕下方的这张图像设置到屏幕的正上方
  rect.y = -rect.height
在这里插入图片描述
设计一个背景类Background,继承于GameSprite类,并且有自己的方法。

  • 初始化方法

  • 直接指定背景图片

  • is_alt判断是否是另一张图像

  •   False表示第一张图像,需要与屏幕重合

  •   True表示另一张图像,在屏幕的正上方。

  • update()方法

  •   判断是否移动出屏幕,如果是,将图像设置到屏幕的正上方,从而实现交替滚动。

提示:
继承如果父类提供的方法,不能满足子类的需求:
派生一个子类
在子类中针对特有的需求,重写父类方法,并且进行扩展

实现代码
plane_sprites.py

import pygame

#定义屏幕大小的常量
SCREEN_RECT = pygame.Rect(0,0,480,700)
#定义屏幕刷新率
FRAME_PRE_SEC = 60

class GameSprite(pygame.sprite.Sprite):
	"""飞机大战游戏精灵"""
	def __init__(self,image_name,speed=1):
	#调用父类的初始化方法
		super().__init__()
	#定义对象属性:
		#这里的image_name是图片的存放路径
		self.image = pygame.image.load(image_name)
		self.rect = self.image.get_rect()
		self.speed = speed
	#定义更新
	def update(self):
	#在屏幕的垂直方向上移动
		self.rect.y += self.speed

#背景图片类
class Background(GameSprite):
	"""游戏背景精灵"""
	def __init__(self,is_alt=Flase):
		#1.调用父类方法实现精灵的创建
		super().__init__("./images/background.png")
		#2.判断是否是交替图像,如果是,需要设置初始位置
		if is_alt:
			self.rect.y = self.rect.height
	def update(self):
		#调用父类的方法实现
		super().update()
		#判断背景是否溢出屏幕,如果移出屏幕,将图像设置到屏幕的上方
		if self.rect.y>=SCREEN_RECT.height:
			self.rect.y = -self.rect.height

在plane_main.py中显示背景精灵

1、在__create_sprites方法中创建精灵和精灵组
2、在__update_sprites方法中,让精灵组调用update()draw()方法

#plane_main.py模块
class PlaneGame(object):
	"""飞机大战主游戏"""
	def __create_sprites(self):
		bg1 = Background()
		bf2 = Background(True)
		self.back_group = pygame.sprite.Group(bg1,bg2)

	def __update_sprites(self):
		self.back_group.update()
		self.back_group.draw(self.screen)

04敌机出场

01使用定时器添加敌机

1、游戏启动后,每隔1s会出现一架敌机
2、每架敌机向屏幕下方飞行,飞行速度各不相同
3、每架敌机出现的水平位置也不尽相同
4、当敌机从屏幕下方飞出,不会再飞回到屏幕中

1.1定时器
  • 在pygame中可以使用pygame.time.set_time()来添加定时器
  • 所谓定时器,就是每隔一段事件,去指定一些动作
set_timer(eventid,milliseconds) --->None
  • set_timer可以创建一个事件
  • 可以在游戏循环的事件监听方法中捕获到该事件
  • 第1个参数事件代号需要基于常量pygame.USEREVENT来指定
    USEREVENT是一个整数,再增加的事件可以使用USEREVENT+1指定,一次类推…
  • 第二个参数是事件触发间隔的毫秒值

定时器事件的监听

  • 通过pygame.event.get()可以获取当前时刻所有的事件列表
  • 遍历列表并且判断event.type是否等于eventid,如果相等,表示定时器事件发生。
1.2定义并监听创建敌机事件

pygame的定时器使用套路非常固定:
1、定义定时器常量—eventid
2、在初始化方法中,调用set_timer方法设置定时器事件
3、在游戏循环中,监听定时器事件

1)定义事件
在plane_sprites.py的顶部定义事件常量

#敌机出现
CREATE_ENEMY_EVENT = pygame.USEREVENT

2)在初始化方法中,调用set_timer方法设置定时器事件

#plane_main.py文件
class PlaneGame(object):
	def __ini__(self):
		#前面不再赘述
		#4.设置定时器事件 --创建敌机,每1s出现
		pygame.time.set_timer(CREATE_ENEMY_EVENT,1000)

3)在游戏循环中,监听定时器事件

def __event_handler(self):
	for event in pygame.event.get():
		if event.type == pygame.QUIT():
			PlaneGame.__game_over()
		elif event.type == CREATE_ENEMY_EVENT:
			#创建敌机精灵
			enemy = Enemy()
			#将敌机精灵添加到敌机精灵组
			self.enemy_group.add(enemy)
			

02设计Enemy类

在这里插入图片描述

  • 初始化方法
    指定敌机图片
    随机敌机的初始位置和初始速度
  • 重写update()方法
    判断是否飞出屏幕,如果是,从精灵组删除
    代码
class Enemy(GameSprite):
	"""敌机精灵"""
	def __init__(self):
		#1.调用父类方法实现精灵的创建,同时指定敌机图片
		super().__init__("./images/enemy1.png")
		#2.指定敌机的初始随机速度1~3
		self.spedd = random.randint(1,3)

		#3.指定敌机的初始随机位置
		#self.rect.y = -self.rect.height
		self.rect.bottom = 0
		self.rect.x = random.randint(0,SCREEN_RECT.width-self.rect.width)

	def update(self):
		#1.调用父类方法,保持垂直方向的飞行
		super().update()
		#2.判断是否飞出屏幕,如果是,需要从精灵组删除敌机
		if self.rect.y >= SCREEN_RECT.height:
			self.kill()
	def __del__(self):
		print("敌机挂了 %s"%self.rect)

创建好敌机类后,在plane_main.py文件中创建精灵并加入到精灵组。创建精灵在监听定时器事件中已完成
加入精灵组

def __create_sprites(self):
	self.enemy_group = pygame.sprite.Gruop()
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值