一、pygame模块
pygame
模块,转为电子游戏设计
1、安装:
$ sudo pip3 install pygame
windows:pip install pygame
2、使用pygame创建图形窗口
(1)新建项目飞机大战
(2)新建文件pygame.py
(3)建立游戏窗口:
①pygame的初始化和退出
pygame.init()
:导入并初始化所有pygame模块,使用其他模块之前,必须先调用init方法。pygame.quit()
:卸载所有pygame模块,在游戏结束之前调用。
代码框架:
import pygame
pygame.init()
print("游戏的代码")
pygame.quit()
②pygame的坐标系
原点在左上角(0, 0)
x轴水平方向向右,逐渐增加
y轴垂直方向向下,逐渐增加
在游戏中,所有可见的元素都是以 矩形区域来描述位置的。四要素(x, y)(width, height)
。(x, y) 指定矩形的左上角位置,(width, height) 指定矩形区域的大小。
pygame专门提供了一个类pygame.Rect
用于描述矩形区域,【其中,size表示(width, height)】:
Rect(x, y, width, height)
import pygame
hero_rect = pygame.Rect(100, 500, 120, 125)
print("hero的原点%d %d" % (hero_rect.x, hero_rect.y))
print("hero的尺寸%d %d" % (hero_rect.width, hero_rect.height))
print("hero的size%d %d" % hero_rect.size )
输出:
③创建游戏主窗口pygame.display
pygame.diaplay.set_mode()
:初始化游戏显示窗口
set_mode
方法:det_mode(resolution = (0, 0), flags = 0, depth = 0)
参数:(因为每个参数都有=
,也就是都有默认值,因此调用时不需要指定值)resolution:指定屏幕的 宽、高,默认创建的窗口大小和屏幕大小一致
flags:参数指定屏幕的附加选项,例如是否全屏等等,默认不需要传递
depth:参数表示颜色的位数,默认自动匹配返回值:
暂时可以理解为游戏的屏幕,游戏的元素都需要被绘制到游戏的屏幕上。
例如:指定screen接收返回值。
screen = pygame.display.set_mode((480, 700))。
pygame.display.update()
:刷新屏幕内容显示,稍后使用
④导入游戏背景图片
1、将图片加载到内存中。
pygame.image.load()
加载图像的数据
注:(./images/1.jpg)其中的.
表示当前目录
bg = pygame.image.load("D:/My life/music/some photos/sunrise.jpg")
2、使用 游戏屏幕对象,调用
bilt(图像,位置)
方法将图像绘制到指定位置
screen.blit(bg, (0, 0)) # (0, 0)表示从屏幕左上角开始绘制
3、调用
pygame.display.update()
方法更新整个屏幕的显示。
注:如果想在屏幕上看到绘制的结果,一定要调用这个方法
pygame.display.update()
运行结果:
⑤把一些精致的图像绘制到游戏窗口中
1、加载hero_plane图像
png格式是支持透明的。在绘制图像时,透明区域不会显示任何内容。如果下方有内容,会透过透明区域显示出来
hero = pygame.image.load("D:/My life/music/some photos/plane.png")
2、将其绘制在屏幕的(150, 500)位置
screen.blit(hero, (150, 500))
3、调用屏幕更新显示飞机图像
pygame.diaplay.update()
输出:
注:screen.blit
方法可以在屏幕上绘制很多图像,这些图像之间可能会彼此重叠。编程时可以在screen对象完成所有bilt之后,统一执行一次 display.update()
。而不是每执行一步update一次,可以减少程序的繁琐。
3、游戏循环
将while True:称为游戏循环(无限循环、死循环)。进入游戏循环,意味着游戏正式开始。
设置刷新频率
检测用户交互
更新所有图像位置
更新屏幕显示
①动画效果——游戏时钟
根据 用户的交互 或者其他情况,快速移动 这些图像,产生动画效果。一般在电脑上 每绘制60次,就能够达到非常 连续 高品质的效果。每次绘制的结果被称为 帧Frame。
pygame专门提供了一个类pygame.time.Clock
可以非常方便地设置屏幕绘制速度。
1、在游戏初始化 创建一个时钟对象
2、在游戏循环中让时钟对象调用tick(频率)
方法。如:
clock.tick(20)
表示每秒20次tick方法会根据上次被调用的时间,自动设置 游戏循环中的延时。
代码示例:
i = 0
while True:
clock.tick(60)
print(i)
②动画的简单实现
每次调用update()
之前,需要把所有的游戏图像都重新绘制一遍,而且 最先 重新绘制 背景图像
clock = pygame.time.Clock()
plane_rect = pygame.Rect(250, 500, 107, 113) # 107和113表示所插入的飞机图片的宽度和高度
#死循环,确保上方执行的游戏界面不会退出
while True:
# 1、指定循环体内部代码执行的频率
clock.tick(60)
# 2、修改飞机的位置
plane_rect.y -= 1
# 如果移出顶部,就从底部重新开始移动
if plane_rect.y <= -113: # -113表示导入飞机图片的高度
plane_rect.y = 700
# 3、调用blit方法绘制图像
screen.blit(bg, (0, 0))# 先绘制背景图像,再绘制飞机,这样就可以遮住上一次飞机的残影
screen.blit(plane, plane_rect)
# 4、调用update方法更新显示
pygame.display.update()
③在游戏循环中监听事件
监听:在 游戏循环 中,判断用户 具体的操作(也称为“事件”)。只有 捕获 到用户的具体操作,才能有针对性地作出相应。
pygame中通过pygame.event.get()
可以获得 用户当前所做的动作 的 事件列表 ,用户可以同一时间做很多事情。
下面这段代码非常固定,几乎所有的pygame游戏都大同小异。
#游戏循环
while True:
#设置屏幕刷新频率
clock.tick(60)
#事件监听
for event in pygame.event.get():
#判断用户是否点击了关闭按钮
if event.type == pygame.QUIT:
print("退出游戏...")
#卸载所有的模块
pygame.quit()
#直接退出系统,终止当前正在执行的程序
exit()
④精灵sprite.Sprite和精灵组sprite.Group
为了简化开发步骤,pygame提供了两个类:
pygame.sprite.Sprite——存储 图像数据image 和 位置Rect 的 对象
pygame.sprite.Group
⑤派生精灵子类
从本节开始,面向对象开发:
新建plane_sprites.py文件
定义GameSprite继承自pygame.sprite.Sprite
注意:
如果一个类的父类不是object,在重写 初始化方法 时,一定要先super()一下父类的初始化__init__
方法,保证父类中实现的__init__
代码能够被正常执行。
属性:image
精灵图像,使用image_name
加载rect
精灵大小,默认使用图像大小speed
精灵移动速度,默认为1
方法:update
每次更新屏幕时在游戏循环内调用。
让精灵self,rect.y += self.speed
提示:image
的get_rect()
方法,可以返回 **pygame.Rect(0, 0, 图像宽,图像高)**的对象。
import pygame
class GameSprite(pygame.sprite.Sprite):
#飞机大战游戏精灵
def __init__(self, image_name, speed = 1):
#调用父类的初始化方法
super().__init__()
#定义对象的属性
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()
self.speed = speed
def update(self):
#在屏幕的绘制方向移动
self.rect.y += self.speed
⑥使用 游戏精灵 和 精灵组 创建敌机
需求:
使用刚刚派生的 游戏精灵 和 精灵组 创建敌机 并且 实现敌机动画。
步骤:
1、使用from
导入plane_sprite
模块
from
导入的模块可以 直接使用import
导入的模块需要通过模块名.
来使用
from plane_sprites import *
# 可以直接使用模块的工具,而不用模块名.
2、在游戏初始化 创建 精灵对象 和 精灵组对象
#创建敌机的精灵
enemy = GameSprite("D:/My life/music/some photos/enemyplane.png")
enemy1 = GameSprite("D:/My life/music/some photos/enemyplane.png", 2)
# 第二架敌机的速度是2#创建敌机的精灵组
enemy_group = pygame.sprite.Group(enemy, enemy1)
3、在 游戏循环中 让 精灵组 分别调用update()
和draw(screen)
方法
#1、update
enemy_group.update()
#2、draw 在screen上绘制所有的精灵
enemy_group.draw(screen)
职责:
精灵
封装 图像image、位置rect 和速度speed
提供update()
方法、根据游戏需求、更新位置rect
精灵组
包含 多个 精灵对象
update
方法,让精灵组中的所有精灵各自调用各自的update
方法更新位置;draw(screen)
方法,在screen
上绘制精灵组中的所有精灵
4、游戏框架搭建
目标——使用 面向对象 设计 飞机大战游戏类。
(1)明确主程序职责
一个游戏的主程序有两个职责:
游戏初始化
游戏循环
根据 职责 封装 私有方法,可以避免某一个方法的代码写得太冗长。如果某一个方法编写得太长,不方便阅读。
(2)实现飞机大战主游戏类
明确文件职责
plane_main
封装 主游戏类
创建 游戏对象
启动游戏
plane_sprites
封装游戏中 所有 需要使用的 精灵子类
提供游戏的 相关工具
常量
变量:可以变化的量
常量:不变化的量。
在开发时,可能会需要使用 固定的值,这个时候,建议 不要 直接使用固定的数值,而应该使用 常量。这样也可以保证代码的可维护性。
常量的定义定义常量的语法与定义变量一样,都是使用 赋值语句。
常量的命名应该 所有字母都使用大写,单词与单词之间使用下划线连接。常量的好处
阅读代码时,通过 常量名 见名知意,不用猜测数字的含义。
如果需要调整值,只需要 修改常量定义 就可以实现 统一修改
#屏幕大小的常量
SCREN_RECT = pygame.Rect(0, 0, 480, 700)
使用时仅需要SCREN_RECT.size
就可以表示(480, 700)
#刷新的帧率
FRAME_PER_SECOND = 60
(3)游戏背景
①背景交替滚动的思路
在游戏启动后,背景图像 会连续不断地 向下方 移动,游戏主角的位置始终保持不变,在 视觉上 产生英雄的飞机不断向上飞行的 错觉——在很多跑酷类游戏的套路。
解决办法:
1、创建2张背景图像精灵:第1张完全和屏幕重合,第2张在屏幕的正上方。
2、两张图像 一起向下运动self.rect.y += self.speed
。
3、当任意背景精灵的rect.y >= 屏幕的高度
说明已经移动到屏幕下方。
4、当移动到屏幕下方的这张图像 设置到 屏幕的正上方rect.y = -rect.height
update()方法:
判断 是否移出屏幕,如果是,将图像设置到 屏幕的正上方,从而实现 交替滚动
背景精灵的代码实现:
class Background(GameSprite):
"""游戏背景精灵"""
def update(self):
# 1、调用父类的方法实现
super().update()
# 2、判断是否移出屏幕,如果移出屏幕,将图片移动到正上方
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
②在plane_main.py中显示背景精灵
在__creat_sprites
方法中创建 精灵 和 精灵组
def __create_sprites(self):
# 创建背景精灵和精灵组
bg1 = Background("D:/My life/music/some photos/sunrise.jpg")
bg2 = Background("D:/My life/music/some photos/sunrise.jpg")
bg2.rect.y = -bg2.rect.height
self.back_group = pygame.sprite.Group(bg1, bg2)
在__update_sprites
方法中,让 精灵组 调用 update()和draw()方法
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
③简化背景精灵的创建
精灵的 初始位置的设置,由 精灵自己 负责,不由主程序负责。
初始化方法:
直接指定背景图片
is_alt
判断是否是另一张图像
Flase
表示 第一张图像,需要与屏幕重合True
表示 另一张图像,在屏幕的正上方
继承:
如果父类提供的方法不能满足子类的需求:
派生一个子类
在子类中针对特有的需求,重写父类方法,并且进行扩展
def __init__(self, is_alt = False): # 默认alt为False
#1、调用父类方法实现精灵的创建(image / rect / speed)
super().__init__("D:/My life/music/some photos/sunrise.jpg")
#2、判断是否是交替图像,如果是,需要设置初始位置
if is_alt:
self.rect.y = -self.rect.height
由此一来,主程序的代码就可以简化为:
def __create_sprites(self):
# 创建背景精灵和精灵组
bg1 = Background()
bg2 = Background(True)
self.back_group = pygame.sprite.Group(bg1, bg2)
(4)敌机
设计Enemy类
①使用定时器添加敌机
在pygame中,可以使用pygame.time.set_timer()
来添加 定时器(每隔一段时间,去执行一些动作)。
set_timer(eventid, milliseconds)
。set_timer
可以创建一个事件,可以在 游戏循环 的事件监听方法中捕获到该事件。
第一个参数 事件代号需要基于常量pygame.USEREVENT
来指定。USERENEVT是一个整数,再增加的事件可以使用
USEREVENT + 1
指定,以此类推…第2个参数是 事件触发 间隔的 毫秒值
通过pygame.event.get()
获取当前时刻所有的 事件列表;
遍历列表 并且判断event.type
是否等于eventid
,如果相等,表示 定时器事件 发生。
pygame的定时器使用套路非常固定:
1、定义 定时器常量——
eventid
2、在初始化方法中,调用set_timer
方法设置定时器事件
3、在游戏循环中,监听定时器事件。
定义事件:
在plane_sprites.py
的顶部定义 事件常量
#创建敌机的定时器常量
CREATE_ENEMY_EVENT = pygame.USEREVENT
②设计Enemy类
游戏启动后,每隔1秒 会 出现一架敌机
每架敌机 向屏幕下方飞行,飞行的 速度各不相同
没架敌机出现的 水平位置 也不尽相同
当敌机 从屏幕下方飞出,不会再飞回屏幕中
初始化方法:
指定 敌机图片
随机 敌机的初始位置和初始速度
重写update()方法
判断是否飞出屏幕,如果是,从 精灵组 删除
③创建敌机
1、在__creat_sprites
添加敌机精灵组。
敌机是 定时被创建的,因此在初始化方法中,不需要创建敌机
self.enemy_group = pygame.sprite.Group()
2、在__event_handler
创建敌机,并且添加到精灵组
调用 精灵组的
add
方法,可以向精灵组添加精灵#创建敌机
enemy = Enemy()
#将敌机精灵添加到精灵组
self.enemy_group.add(enemy)
3、在__update_sprites
让 敌机精灵组调用update
和draw
方法
self.enemy_group.update()
self.enemy_group.draw(self.screen)
可以看到敌机一架架陆续出现
④ 随机 敌机位置和速度
导入模块时,建议按照以下顺序导入
官方标准模块导入
第三方模块导入
应用程序模块导入
修改plane_sprites.py
增加random
的导入
import random # 官方标准模块
随机化敌机初始速度
self.speed = random.randint(1, 3) # (随机数的最小值,随机数的最大值)
敌机从屏幕顶部缓缓进入
self.rect.bottom = 0
随机化敌机出现的水平位置
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
#水平位置最小值为0,最大位置为“屏幕宽度-飞机宽度”
⑤移出屏幕销毁敌机
敌机移出屏幕后,如果没有撞到飞机,敌机的历史生命已经终结。需要从 敌机组 删除,否则会造成 内存浪费
检测敌机被销毁:__del__
内置方法会在对象被销毁前调用。在开发中,可以用于 判断对象是否被销毁
def __del__(self):
print("敌机销毁%s" %self.rect)
判断敌机是否飞出屏幕,如果是,调用kill()
方法将精灵精灵组中移出,敌机自动销毁
def update(self):
super().update(args)
#判断敌机是否移出屏幕
if self.rect.y >= SCREEN_RECT.height:
#将精灵从精灵组中删除
self.kill()
(5)英雄飞机
游戏启动后,飞机出现在屏幕的 水平中间 位置,距离 屏幕底部120
像素。
飞机每隔0.5
秒发射一次子弹,每次 连发三枚子弹。
飞机默认不会移动,需要通过 左 / 右
方向键,控制 英雄 在水平方向移动。
(6)子弹需求
子弹 从 英雄飞机的正上方发射 沿直线 向 上方 飞行
飞出屏幕后,需要从 精灵组 中删除
在plane_sprites
新建Hero
类
初始化方法
指定 英雄图片
初始速度=0——英雄默认静止不动
定义bullets
子弹精灵组 保存子弹精灵重写update()方法
英雄需要 水平移动
并且需要保证不能 移出屏幕
增加bullets
属性,记录所有 子弹精灵
增加file
方法,用于发射子弹
center
centerx = x + 0.5 * width # x的中心点
centery = y + 0.5 * height # y的中心点
bottom = y + height
①绘制英雄
在__creat_sprites
添加 英雄精灵 和 英雄精灵组
英雄需要单独定义成属性,因为后续要针对 英雄 做 碰撞检测 以及发射子弹
#创建英雄的精灵和 英雄精灵组
self.hero = Hero()
self.hero_group = pygame.sprite.Group(self.hero)
在__update_sprites
,让 英雄精灵组 调用 update和 draw 方法。
self.hero_group.update()
self.hero_group.draw(self.screen)
②移动英雄位置
在pygame中针对 键盘按键的捕获,有两种方式:
第一种方式:
判断
event.type == pygame.KEYDOWN
elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
print("向右移动...")
缺点:如果用户按住不放,默认只按了一次。
第二种方式:
首先使用
pygame.key.get_pressed()
返回 所有 按键元组
通过 键盘常量,判断元组中某一个键是否被按下——如果被按下,对应数值为1
keys_pressed = pygame.key.get_pressed()
#判断是否按下了方向键
if keys_pressed[pygame.K_RIGHT]:
print("持续向右移动...")
优点:可以 按住键盘不放,实现 持续移动。
在Hero
类中重写 update
方法
用速度
speed
和英雄rect.x
进行叠加
不需要调用父类方法——父类方法只是实现了单纯的垂直运动
def update(self):
self.rect.x += self.speed
在__event_handler
方法中根据 左右方向键 设置英雄的 速度
向右 =>
speed = 2
self.hero.speed = 2
向左 => speed = -2
elif keys_pressed[pygame.K_LEFT]:
self.hero.speed = -2
其他 => speed = 0
else:
self.hero.speed = 0
③控制英雄的移动边界
right = x + width
,利用right
属性可以非常容易地针对右侧设置精灵位置。
#控制英雄的移动边界
if self.rect.x < 0:
self.rect.x = 0
elif self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
④发射子弹
回顾 “四(4)①”的知识点pygame
的定时器使用套路非常固定:
1、定义 定时器常量——
eventid
2、在初始化方法中,调用set_timer
方法设置定时器事件
3、在游戏循环中,监听定时器事件。
第一步:
在Hero
中定义fire
方法
def fire(self):
print("发射子弹")
第二步:
#英雄发射子弹事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1
第三步:
pygame.time.set_timer(HERO_FIRE_EVENT, 500) # 500ms
第四步:
elif event.type == HERO_FIRE_EVENT:
self.hero.fire()
⑤定义子弹类
Bullet
初始化方法:
指定子弹图片
初始速度 = -2——实现子弹向 上方 飞行
重写update()方法
判断是否飞出屏幕,如果是,从 精灵组 删除
定义子弹类
在plane_sprites
新建Bullet
继承自GameSprite
重写 初始化方法,直接指定 图片名称,并且设置初始速度
重写update()
方法,判断子弹 飞出屏幕从精灵组删除
class Bullet(GameSprite):
"""子弹精灵"""
def __init__(self):
# 调用父类方法,指定 图片名称,并且设置初始速度
super().__init__("D:/My life/music/some photos/bullet.png", -2)
def update(self):
# 调用父类方法,让子弹沿垂直方向飞行
super().update()
# 判断子弹是否飞出屏幕
if self.rect.bottom < 0:
self.kill()
def __del__(self):
print("子弹被销毁...")
⑥发射子弹
1、在Hero
的 初始化方法 中创建 子弹精灵组 属性
#3、创建子弹精灵组
self.bullets = pygame.sprite.Group()
2、修改plane_main.py
的__update_sprites
方法,让 子弹精灵组 调用update
和draw
方法
self.hero.bullets.update()
self.hero.bullets.draw(self.screen)
3、实现fire()
方法
# 1、创建子弹精灵
bullet = Bullet()
# 2、设置初始位置——在英雄的正上方
bullet.rect.bottom = self.rect.y - 20
bullet.rect.centerx = self.rect.centerx
# 3、将 **子弹** 添加到精灵组
self.bullet.add(bullet)
⑦一次发射三枚子弹
修改fire
,一次发射三枚子弹
for i in (0, 1, 2):
# 1、创建子弹精灵
bullet = Bullet()
# 2、设置初始位置——在英雄的正上方
bullet.rect.bottom = self.rect.y - i * 20
bullet.rect.centerx = self.rect.centerx
# 3、将 子弹 添加到精灵组
self.bullets.add(bullet)
⑧碰撞检测
了解碰撞检测的方法:
方法一:pygame.sprite.groupcollide()
两个精灵组 中 所有的精灵 的 碰撞检测
groupcollide(group1, group2, dokill1, dokill2, collided = None)
如果将
dokill
设置为True
,则 发生碰撞的精灵将被自动移除。collided
参数是用于 计算碰撞的回调函数。如果没有指定,则每个精灵必须有一个rect
属性。
方法二:pygame.sprite.spritecollie()
判断 某个精灵 和 指定精灵组 中的精灵的碰撞
spritecollide(sprite, froup, dokill, collided = None)
如果将
dokill
设置为True
,则 指定精灵组 中 发生碰撞的精灵将被自动移除。collided
参数是用于 计算碰撞的回调函数。如果没有指定,则每个精灵必须有一个rect
属性。
返回 精灵组 中 跟 精灵 发生碰撞的 精灵列表
def __check_collide(self):
#1、子弹摧毁敌机
pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
#2、敌机撞毁英雄
enemies = pygame.sprite.spritecollide(self.hero, self.enemyy_group, True)
#判断列表是否有内容
if len(enemies) >0:
#让英雄牺牲
self.hero.kill()
#结束游戏
PlaneGame.__game_over()
五、游戏设计完成,运行图片
飞机大战游戏共包含两个python文件:plane_main.py
和plane_sprites.py
文章来源:https://www.toymoban.com/news/detail-474191.html
附录一:plane_main.py
import pygame
pygame.init() # 这行代码可以解决“pygame is not initialized”问题
from plane_sprites import *
class PlaneGame(object):
def __init__(self):
print("游戏初始化")
# 1、创建游戏的窗口
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 2、创建游戏的时钟
self.clock = pygame.time.Clock()
# 3、调用私有方法,精灵和精灵组的创建
self.__create_sprites()
# 4、设置定时器事件-创建敌机 1s
pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000) # 1000ms
pygame.time.set_timer(HERO_FIRE_EVENT, 500) # 500ms
def __create_sprites(self):
# 创建背景精灵和精灵组
bg1 = Background()
bg2 = Background(True)
self.back_group = pygame.sprite.Group(bg1, bg2)
# 创建敌机的精灵组
self.enemy_group = pygame.sprite.Group()
# 创建英雄的精灵和 英雄精灵组
self.hero = Hero()
self.hero_group = pygame.sprite.Group(self.hero)
def start_game(self):
print("游戏开始")
while True:
# 1、设置刷新频率
self.clock.tick(FRAME_PER_SECOND)
# 2、事件监听
self.__event_handler()
# 3、碰撞检测
self.__check_collide()
# 4、更新 / 绘制精灵组
self.__update_sprites()
# 5、更新显示
pygame.display.update()
# 事件监听
def __event_handler(self):
for event in pygame.event.get():
# 判断是否退出游戏
if event.type == pygame.QUIT:
PlaneGame.__game_over()
elif event.type == CREATE_ENEMY_EVENT:
# print("敌机出场...")
# 创建敌机
enemy = Enemy()
# 将敌机精灵添加到精灵组
self.enemy_group.add(enemy)
elif event.type == HERO_FIRE_EVENT:
self.hero.fire()
# elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
# print("向右移动...")
# 首先使用`pygame.key.get_pressed()`返回所有按键元组
# 通过键盘常量,判断元组中某一个键是否被按下——如果被按下,对应数值为`1`
keys_pressed = pygame.key.get_pressed()
# 判断是否按下了方向键
if keys_pressed[pygame.K_RIGHT]:
# print("持续向右移动...")
self.hero.speed = 2
elif keys_pressed[pygame.K_LEFT]:
self.hero.speed = -2
else:
self.hero.speed = 0
# 碰撞
def __check_collide(self):
# 1、子弹摧毁敌机
pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
# 2、敌机撞毁英雄
enemies = pygame.sprite.spritecollide(self.hero, self.enemy_group, True)
# 判断列表是否有内容
if len(enemies) > 0:
# 让英雄牺牲
print("英雄牺牲了")
self.hero.kill()
# 结束游戏
PlaneGame.__game_over()
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
self.enemy_group.update()
self.enemy_group.draw(self.screen)
self.hero_group.update()
self.hero_group.draw(self.screen)
self.hero.bullets.update()
self.hero.bullets.draw(self.screen)
@staticmethod
def __game_over():
print("游戏结束")
pygame.quit()
exit()
if __name__ == '__main__':
# 创建游戏对象
game = PlaneGame()
# 启动游戏
game.start_game()
附录二:plane_sprites.py
import random # 官方标准模块
import pygame
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
FRAME_PER_SECOND = 60
# 创建敌机的定时器常量
CREATE_ENEMY_EVENT = pygame.USEREVENT
# 英雄发射子弹事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1
class GameSprite(pygame.sprite.Sprite):
# 飞机大战游戏精灵
def __init__(self, image_name, speed=1):
# 调用父类的初始化方法
super().__init__()
# 定义对象的属性
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=False): # 默认alt为False
# 1、调用父类方法实现精灵的创建(image / rect / speed)
super().__init__("D:/My life/music/some photos/sunrise.jpg")
# 2、判断是否是交替图像,如果是,需要设置初始位置
if is_alt:
self.rect.y = -self.rect.height
def update(self):
# 1、调用父类的方法实现
super().update()
# 2、判断是否移出屏幕,如果移出屏幕,将图片移动到正上方
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
class Enemy(GameSprite):
"""敌机精灵"""
def __init__(self):
# 1、调用父类方法,创建敌机精灵,同时指定敌机图片
super().__init__("D:/My life/music/some photos/enemyplane.png")
# 2、指定敌机的初始位置
self.speed = random.randint(1, 3) # (随机数的最小值,随机数的最大值)
# 3、指定敌机的初始速度
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
def update(self):
# 1、调用父类方法,保持垂直方向的飞行
super().update()
# 2、判断是否飞出屏幕,如果是,从 **精灵组** 删除
if self.rect.y >= SCREEN_RECT.height:
# print("飞出屏幕,需要从精灵组中删除...")
# 调用kill()方法将精灵精灵组中移出,敌机自动销毁
self.kill()
def __del__(self):
# print("敌机销毁成功%s" % self.rect)
pass
class Hero(GameSprite):
"""英雌精灵"""
def __init__(self):
# 1、调用父类方法,设置image和速度
super().__init__("D:/My life/music/some photos/plane.png", 0)
# 2、设置英雌的初始位置
self.rect.centerx = SCREEN_RECT.centerx
self.rect.bottom = SCREEN_RECT.bottom - 120
# 3、创建子弹精灵组
self.bullets = pygame.sprite.Group()
def update(self):
self.rect.x += self.speed
# 控制英雄的移动边界
if self.rect.x < 0:
self.rect.x = 0
elif self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
def fire(self):
print("发射子弹")
for i in (0, 1, 2):
# 1、创建子弹精灵
bullet = Bullet()
# 2、设置初始位置——在英雄的正上方
bullet.rect.bottom = self.rect.y - i * 20
bullet.rect.centerx = self.rect.centerx
# 3、将 子弹 添加到精灵组
self.bullets.add(bullet)
class Bullet(GameSprite):
"""子弹精灵"""
def __init__(self):
# 调用父类方法,指定 图片名称,并且设置初始速度
super().__init__("D:/My life/music/some photos/bullet.png", -2)
def update(self):
# 调用父类方法,让子弹沿垂直方向飞行
super().update()
# 判断子弹是否飞出屏幕
if self.rect.bottom < 0:
self.kill()
def __del__(self):
# print("子弹被销毁...")
pass
附录三:飞机大战设计图片
“英雄”“敌机”“子弹”均为PNG格式——便于设置透明背景。
英雄:
敌机:
子弹:
背景图片:
文章来源地址https://www.toymoban.com/news/detail-474191.html
到了这里,关于python | 基础学习(六)pygame游戏开发:飞机大战的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!