目录
如果你掌握了这几个方法,那么你离做出来属于自己的游戏不远了,让我们一起实现游戏自由吧!!!有想更深入了解Pygame 让我们一起讨论一下吧 !!!下一篇更新飞机大战游戏~~~
介绍:pygame
首先我们先来讨论一下pygame!!!
Pygame是一个用于开发2D图形和游戏的Python库。它建立在SDL(Simple DirectMedia Layer)库之上,提供了一系列用于处理图形、声音、输入和事件等功能的工具和方法。
Pygame具有简单易用的接口,使得游戏开发者能够快速构建各种类型的游戏,包括平台游戏、动作游戏、迷宫游戏等。它提供了一个图形引擎,可以处理图像、文本和几何形状,并支持各种特效和动画。
Pygame还提供了音频功能,可播放音乐和音效。它支持各种音频格式,并具有音量控制、音效合成和混音等功能,让开发者能够为游戏添加丰富的声音效果。
此外,Pygame还支持用户输入和事件处理。开发者可以轻松地获取鼠标和键盘输入,以及处理游戏中发生的各种事件,如碰撞、按键和时间等。
Pygame是一个跨平台的库,可以在多个操作系统上运行,包括Windows、macOS和Linux。它是使用Python开发游戏的常用工具,因为它易于学习、灵活且强大。
总的来说,Pygame是一个功能丰富、易用的Python游戏开发库,适合初学者和有经验的开发者使用,使他们能够快速开发出自己的2D游戏作品。
下载 :pygame
打开pygame的终端 输入命令 : pip install pygame (前提是没有下载pygame)
当出现
表示下载成功
接下来我们来实现一些基本的功能,之后会来写我们的一个小游戏。
一 一个可以关闭的空白窗体
首先我们要导包
import pygame
之后再来实现其功能
初始化pygame 一般情况下pygame中只要初始化字体
pygame.init()
然后设置一个窗口 我这边是800x600的窗口 单位是像素
screen = pygame.display.set_mode((800,600))
给窗口设置一个题目
pygame.display.set.caption("窗口")
最后一步也是最重要的
因为我们刚才设置的窗口运行过后 会闪一下就会关闭 所以现在我们来设置一个死循环不让窗体关闭
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
whileTrue 死循环 for event in pygame.event.get() 来获取窗口里面发生的任何事情 其中get 在整个游戏中只能出现一次 死循环就是一直循环 所以目前窗体是关不了的 所以要用到pygame.quit() 和sys.exit()(要导入sys包) 关闭
最后更新一下窗体就可以实现了
pygame.display.flip()
代码:
# 游戏管理类
class GameManage:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((1500, 900))
pygame.display.set_caption("飞机")
self.bg_manage.update()
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.flip()
gm = GameManage()
gm.run()
二 使用精灵显示背景, 背景的循环展示
步骤和上面的基本一样 要写一个窗口 背景循环就是让一张背景重复出现 当一张背景向下移动时 上面的背景跟着第一张背景移动 形成一个循环
代码实现:
# 游戏管理类
class GameManage:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((1500, 900))
pygame.display.set_caption("飞机")
self.bg_manage.update()
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.flip()
gm = GameManage()
gm.run()
# 要写一个精灵 必须要有基本精灵类
# BaseSprite 基本精灵类 继承pygame.sprite.Sprite
class BaseSprite(pygame.sprite.Sprite):
# 初始化name
def __init__(self, name):
# 继承父类
super().__init__()
# 加载一个背景图片name
self.image = pygame.image.load(name)
# 获取背景的大小 位置
self.rect = self.image.get_rect()
#再写一个背景精灵 背景管理 一般情况下一个精灵类 要有它对应的管理类 去管理这个精灵类
class BGSprite(BaseSprite):
def __init__(self, name, topleft):
super().__init__(name)
self.rect.topleft = topleft
def update(self):
# 背景移动的方向 与速度
self.rect.top += 2
# 这两句话实现了背景的循环 需要两张背景图 当一张背景图下来的时候 另一张背景图跟着下来 当背景都移动出窗口的时候 新的背景就会出现
if self.rect.top >= 900:
# 这句 实现了 新的背景就会出现
self.rect.top = -900
class BGManage:
def __init__(self, gm):
#背景管理类与游戏管理类取得关联 从而更容易实现功能
self.gm = gm
# 创建一个精灵组 用来装精灵
self.bg_group = pygame.sprite.Group()
#调用BGSprite 加载图片
BGSprite("img/gaming_bg.jpg", (0, 0)).add(self.bg_group)
BGSprite("img/gaming_bg.jpg", (0, -900)).add(self.bg_group)
#更新精灵组 将精灵组绘制到 窗口上
def update(self):
self.bg_group.update()
self.bg_group.draw(self.gm.screen)
三 使用精灵玩家,玩家可以移动
想要玩家移动 要有玩家 所以可以来一个 玩家精灵PlayerSprite 玩家类PlayerManage 玩家类去管理玩家精灵
想要玩家移动 我们知道我们用电脑的键盘上下左右去控制
我们就要了解到pygame中的 pygame.key.get_pressed()
移动代码 实现:
key_presses = pygame.key.get_pressed()
if key_presses[pygame.K_a] and self.rect.left > 0:
self.rect.left -= self.speed
if key_presses[pygame.K_d] and self.rect.right < 1500:
self.rect.right += self.speed
if key_presses[pygame.K_w] and self.rect.top > 0:
self.rect.top -= self.speed
if key_presses[pygame.K_s] and self.rect.bottom < 900:
self.rect.bottom += self.speed
具体代码:后面会有全部代码
四 使用精灵显示道具,玩家与道具碰撞检测
使用精灵显示道具 要写一个道具精灵类 与一个道具管理类 道具管理类用于管理道具精灵类的
代码实现 :
#道具精灵类
class PropSprite(BaseSprite):
def __init__(self, name, centerx, y, speed, type):
#继承父类 初始化
super().__init__(name)
self.rect.centerx = centerx
self.rect.top = y
self.speed = speed
self.time_count3 = 2
self.type = type
# update 用于更新道具精灵组的基本属性
比如 移动 或者 自己的属性
def update(self):
self.time_count3 -= 2
if self.time_count3 <= 0:
self.time_count3 = 2
self.rect.top += self.speed
if self.rect.y > 900:
self.kill()
# 道具精灵类 每一个time_count 都代表的是一个计时器 用于调节执行程序的快慢
class PropManage:
def __init__(self, gm):
self.gm = gm
# 创建道具精灵组 精灵组一般都在管理类的初始化中去初始化
self.prop_group = pygame.sprite.Group()
self.time_count4 = 6
# 这里面是生成道具的函数
def generate(self):
value = random.random()
if value > 0.9:
PropSprite("img/daojubaozha.png", random.randrange(50, 1450, 25), 0, 8, 1).add(self.prop_group)
elif value > 0.5:
PropSprite("img/jiaxie.png", random.randrange(75, 1450, 25), 0, 8, 2).add(self.prop_group)
else:
PropSprite("img/player1(1).png", random.randrange(50, 1450, 25), 0, 8, 3).add(self.prop_group)
# 这里面的update 不同于前方的update 这里面的是用于更新道具精灵组的 然后将道具精灵组绘制到窗口上
def update(self):
self.time_count4 -= 0.2
if self.time_count4 <= 0:
self.time_count4 = 6
self.generate()
self.prop_group.update()
self.prop_group.draw(self.gm.screen)
玩家与道具碰撞检测 这个很简单 实质就是玩家组 与 道具组 碰撞 用到groupcollider方法
# 玩家与道具
player_prop_collider = pygame.sprite.groupcollide(self.player_manage.player_group, self.prop_manage.prop_group,
False, True)
if player_prop_collider:
for props in player_prop_collider.values():
for prop in props:
if prop.type == 1:
self.enemy_manage.enemy_group.empty()
if prop.type == 2:
self.player_manage.player.hp += 1
if self.player_manage.player.hp > self.player_manage.player.max_hp:
self.player_manage.player.hp = self.player_manage.player.max_hp
if prop.type == 3:
value = random.random()
if value > 0.5:
self.player_manage.player.super_bullet_num1 = 20
else:
self.player_manage.player.super_bullet_num2 = 20
看 我这边是三种道具 分别为道具类型1 道具类型2 道具类型3 玩家与道具碰撞会让道具消失 所以 第二个为True 玩家组与道具组碰撞 道具组中每一个道具都对应不同的功能 所以才会分三种情况考虑
五 UI的使用 (字体,鼠标点击检测)
我们首先要创建一个UI精灵类 然后有对应的精灵管理类去管理
自己写的代码 纯手工
在Pygame中,可以使用字体和鼠标点击检测来创建用户界面(UI)。下面是一些关于如何使用字体和鼠标点击检测的基本示例:
1. 字体的使用:
首先,需要导入pygame和pygame.font模块:
import pygame
from pygame import font
然后,选择并加载你喜欢的字体:
pygame.init()
font_name = pygame.font.match_font('arial')
my_font = font.Font(font_name, font_size)
在此示例中,我们选择使用arial字体,可以根据需要更改字体名称和大小。
接下来,可以使用所选的字体来渲染文本:
text_surface = my_font.render('Hello, Pygame!', True, (255, 255, 255))
这将创建一个包含指定文本的Surface对象,第一个参数是文本内容,第二个参数表示是否开启反锯齿效果,第三个参数是文本颜色。
最后,将渲染好的文本Surface绘制到屏幕上:
screen.blit(text_surface, (x, y))
pygame.display.update()
其中,(x, y)是文本绘制的坐标位置。需要确保在调用显示更新函数前绘制文本。
2. 鼠标点击检测:
要检测鼠标点击事件,可以使用pygame.mouse.get_pressed()函数。该函数返回一个包含三个元素的元组,对应左键、中键和右键是否按下,元素值为1表示按下,为0表示未按下。
在游戏循环中的事件处理部分,可以使用如下代码检测鼠标点击事件:
class Util:
@staticmethod
def click_check(sprite):
if pygame.mouse.get_pressed()[0]:
if sprite.rect.collidepoint(pygame.mouse.get_pos()):
return True
return False
在这个示例中,我们检测到鼠标的按下事件后,获取当前鼠标的位置pygame.mouse.get_pos(),然后使用collidepoint()方法检测其是否在按钮的矩形范围内。如果是,则可以执行相应的逻辑。
注意,sprite_rect是按钮的矩形对象,可以使用pygame.rect()函数创建矩形并设置其位置和尺寸。
这只是一种简单的鼠标点击检测方式,你可以根据自己的需求进行修改和扩展。
六 Pygame Draw绘图函数详解
Pygame 中提供了一个draw
模块用来绘制一些简单的图形状,比如矩形、多边形、圆形、直线、弧线等。
Pygame.draw 模块的常用方法如下表所示:
|
表格中的函数使用方法大同小异,它们都可以在 Surface 对象上绘制一些简单的形状,返回值是一个 Rect 对象,表示实际绘制图形的矩形区域。上述绘图函数都提供了一个 color 参数,我们可以通过以下三种方式来传递 color 参数值:
- 使用 pygame.color 对象
- RGB 三元组
- RGBA 四元组
下面通对上述一些方法的参数进行详细说明:
1)绘制矩形
绘制矩形的语法格式如下
pygame.draw.rect(surface, color, rect, width)
参数说明如下:
- surface:指主游戏窗口,无特殊情况,一般都会绘制在主屏幕上;
- color:该参数用于该图形着色;
- rect:绘制图形的位置和尺寸大小;
- width:可选参数,指定边框的宽度,默认为 0,表示填充该矩形区域
注意,当 width > 0 时,表示线框的宽度;而 width < 0 时,此时不会绘制任何图形。
2)绘制圆形
pygame.circle(surface, color, pos, radius, width=0)
上述参数的含义如下:
-
pos:该参数用来指定的圆心位置;
-
radius:用来指定圆的半径;
目前就说明两个 其他的都不怎么用!!!!!
七 精灵的检测碰撞
在开始学习相关知识点之前,我们有必要先学习精灵和碰撞检测的含义。
精灵(英文译为 Sprite),其实在一个游戏程序中,精灵本质指的是一张张小尺寸的图片,比如游戏中的各种道具、人物、场景装饰等,它们都可以看做成一张张小的“精灵”图。除此之外,人物的移动也可以看做是一系列小精灵图构成的序列(按帧组成的序列),如下图所示:
动作逐帧分解图
如果将逐帧分解后的动作,按照一定的频率播放,那么就形成了动画精灵,您将会看到雄鹰展翅高飞、人在策马奔腾、运动员奋力跳远。
精灵有个特点就是允许精灵之间进行交互,也称之为碰撞,而碰撞检测,指的就是检测两个精灵之间是否发生了碰撞。比如在贪吃蛇游戏中蛇的头部是否与食物发生了碰撞,或者飞机大战游戏中子弹是否击中了外星人等等。当检测到碰撞发生后,接下来会触发某些事件,比如子弹击中外星人,外星人就会消失,玩家的得分也会随之增加,并且在游戏屏幕上又会出现一个外星人。
Pygame 专门提供了一个处理精灵的模块,也就是 sprite(pygame.sprite)模块。通常情况下,我们使用该模块的基类 Sprite 来创建一个子类,从而达到处理精灵的目的,该子类提供了操作精灵的常用属性和方法,如下所示:
属性&方法 | 说明 |
---|---|
self.image | 加载要显示的精灵图片,控制图片大小和填充色 |
self.rect | 精灵图片显示在哪个位置 |
Sprite.update() | 刷新精灵图,使其相应效果生效 |
Sprite.add() | 添加精灵图到精灵组中(groups) |
Sprite.remove() | 从精灵组中删除选中的精灵图 |
Sprite.kill() | 删除精灵组中全部的精灵 |
Sprite.alive() | 判断某个精灵是否属于精灵组 |
注意,当游戏中有大量的精灵时,操作它们将变得复杂,此时通过构建精灵容器(group 类)也就是精灵组来统一管理这些精灵。构建方法如下:
# 创建精灵组
group = pygame.sprite.Group()
# 向组内添加一个精灵
group.add(sprite_one)
于此同时pygame.sprite
模块也提供了多种检测精灵是否碰撞的方法,如下所示:
方法 | 说明 |
---|---|
pygame.sprite.collide_rect() | 两个精灵之间的矩形检测,即矩形区域是否有交汇,返回一个布尔值。 |
pygame.sprite.collide_circle() | 两个精灵之间的圆形检测,即圆形区域是否有交汇,返回一个布尔值。 |
pygame.sprite.collide_mask() | 两个精灵之间的像素蒙版检测,更为精准的一种检测方式。 |
pygame.sprite.spritecollide() | 精灵和精灵组之间的矩形碰撞检测,一个组内的所有精灵会逐一地对另外一个单个精灵进行碰撞检测,返回值是一个列表,包含了发生碰撞的所有精灵。 |
pygame.sprite.spritecollideany() | 精灵和精灵组之间的矩形碰撞检测,上述函数的变体,当发生碰撞时,返回组内的一个精灵,无碰撞发生时,返回 None。 |
pygame.sprite.groupcollide() | 检测在两个组之间发生碰撞的所有精灵,它返回值是一个字典,将第一组中发生碰撞的精灵作为键,第二个组中发生碰撞的精灵作为值。 |
现在给大家实现具体的代码(以飞机大战为例):
def check_collider(self):
# 玩家与道具
player_prop_collider = pygame.sprite.groupcollide(self.player_manage.player_group, self.prop_manage.prop_group,
False, True)
if player_prop_collider:
for props in player_prop_collider.values():
for prop in props:
if prop.type == 1:
self.enemy_manage.enemy_group.empty()
if prop.type == 2:
self.player_manage.player.hp += 1
if self.player_manage.player.hp > self.player_manage.player.max_hp:
self.player_manage.player.hp = self.player_manage.player.max_hp
if prop.type == 3:
value = random.random()
if value > 0.5:
self.player_manage.player.super_bullet_num1 = 20
else:
self.player_manage.player.super_bullet_num2 = 20
# 玩家子弹与敌人
player_bullet_enemy_collider = pygame.sprite.groupcollide(self.player_manage.player.bullet_group,
self.enemy_manage.enemy_group, True, False)
if player_bullet_enemy_collider:
for enemys in player_bullet_enemy_collider.values():
for enemy in enemys:
enemy.hp -= 2
if enemy.hp <= 0:
self.player_manage.score += 1
enemy.kill()
# 玩家子弹与boss
player_bullet_boss_collider = pygame.sprite.groupcollide(self.player_manage.player.bullet_group,
self.boss_manage.boss_group, True, False)
if player_bullet_boss_collider:
self.boss_manage.boss.hp -= 2
if self.boss_manage.boss.hp <= 0:
self.die()
self.ui_manage.is_victory = True
self.state = "end"
# 玩家与敌人子弹
for enemy in self.enemy_manage.enemy_group.sprites():
player_enemy_bullet_collider = pygame.sprite.groupcollide(self.player_manage.player_group,
enemy.bullet_group, False, True)
if player_enemy_bullet_collider:
self.player_manage.player.hp -= 1
if self.player_manage.player.hp <= 0:
self.ui_manage.is_victory = False
self.die()
self.state = "end"
# 玩家子弹与敌人子弹
for enemy in self.enemy_manage.enemy_group.sprites():
player_bullet_enemy_bullet_collider = pygame.sprite.groupcollide(self.player_manage.player.bullet_group,
enemy.bullet_group, True, True)
# 玩家与敌人
player_enemy_group_collider = pygame.sprite.groupcollide(self.player_manage.player_group,
self.enemy_manage.enemy_group,
False, True)
if player_enemy_group_collider:
self.player_manage.player.hp -= 2
if self.player_manage.player.hp <= 0:
self.ui_manage.is_victory = False
self.die()
self.state = "end"
# 玩家子弹与boss子弹
player_bullet_boss_bullet_collider = pygame.sprite.groupcollide(self.player_manage.player.bullet_group,
self.boss_manage.boss.bullet_group, True, True)
# 玩家与boos子弹
player_boos_bullet_collider = pygame.sprite.groupcollide(self.player_manage.player_group,
self.boss_manage.boss.bullet_group, False, True)
if player_boos_bullet_collider:
self.player_manage.player.hp -= 1
if self.player_manage.player.hp <= 0:
self.ui_manage.is_victory = False
self.die()
self.state = "end"
# 玩家与boss
player_boss_body_collider = pygame.sprite.groupcollide(self.player_manage.player_group,
self.boss_manage.boss_group, False, False)
if player_boss_body_collider:
self.player_manage.player.hp -= 1
if self.player_manage.player.hp <= 0:
self.ui_manage.is_victory = False
self.die()
self.state = "end"
套路都是一样的 要用到pygame.sprite.groupcollide(group,group,True,True) 这个是精灵组与精灵组 碰撞 所以里面都是精灵组 后面的True 代表着第一个消失 False代表不消失 根据自己的情况设定 后面也可以进行扩展自己的思路。