本章,你将学习如何使用 Pygame 中的精灵。
导航
上一章:监测游戏时间
精灵
当游戏对象变得繁多的时候,把所有游戏对象的处理存放在一个个函数中,虽然是一种可行的方法,但是会使代码逻辑比较混乱,难以维护。这时,精灵(sprite) 应运而生。使用精灵,可以将游戏对象封装到一个个类当中,以将处理游戏对象的逻辑与主代码逻辑分离开,使代码架构更加清晰明了。
Pygame 中,通过pygame.sprite
模块使用精灵。该模块定义了Sprite
类(用于定义精灵)和Group
类(用于管理精灵的容器)以及一些继承于这两个类的拓展类和检测精灵碰撞的函数。
下面将主要介绍Sprite
和Group
类,以及常用的检测碰撞的函数。
Sprite
pygame.sprite.Sprite
通常作为可见游戏对象的基类。构造函数Sprite(*groups) -> Sprite
接受任意数量的Group
容器以添加到这些容器中。
继承它的子类需要为image
和rect
属性赋值。image
属性是一个pygame.Surface
对象,指定该游戏对象的图像。rect
属性是一个pygame.Rect
对象,用于指定该游戏对象的位置,也用于检测精灵碰撞而使用。
Sprite
类中定义的方法如下表(详见官方文档):
方法定义 | 方法作用 |
---|---|
update(*args, **kwargs) -> None |
用于控制精灵行为的方法,通常子类需要重写该方法。当调用了Group.update 方法时,组中的所有精灵都会被调用Sprite.update 方法,如果在Group.update 方法中传入了参数,参数也将被传入Sprite.update 方法中。 |
add(*groups) -> None |
任意数量的Group 对象作为参数传递,精灵将被添加到尚未成为成员的组中。 |
remove(*groups) -> None |
任意数量的Group 对象作为参数传递,精灵将从它所在的组中移除。 |
kill() -> None |
将精灵从所有包含它的组中移除,这并不会改变本身的状态,之后也可以继续使用该精灵。 |
alive() -> bool |
判断此精灵是否属于1个或多个组。 |
groups() -> group_list |
返回包含此精灵的Group 对象的列表。 |
Group
pygame.sprite.Group
类通常作为用于管理多个Sprite
对象的容器。此类也可以被继承以创建有更具体行为的容器。构造函数Group(*sprites) -> Group
接受任意数量的Sprite
对象作为参数以添加到容器中。Group
类还支持以下标准的 Python 操作:
-
in
,判断是否包含了某个精灵。 -
len
,获取组中的精灵总数。 -
bool
,判断组中是否包含任何精灵。 -
iter
,迭代组中所有的精灵。
Group
类中定义的方法如下表(详见官方文档):
方法定义 | 方法作用 |
---|---|
sprites() -> sprite_list |
返回组中包含的所有精灵的列表。 |
copy() -> Group |
创建该组的副本。 |
add(*sprites) -> None |
向组中添加任意数量的精灵,只添加尚未成为改组成员的精灵。 |
remove(*sprites) -> None |
从组中删除任意数量的精灵。只删除是该组成员的精灵。 |
has(*sprites) -> bool |
判断组中是否包含给定的所有精灵。 |
update(*args, **kwargs) -> None |
对组中所有的精灵调用Sprite.update 方法,被传入Group.update 方法的参数也将传入Sprite.update 方法中。 |
draw(Surface) -> List[Rect] |
将组中包含的所有精灵绘制到给定的图像上,使用每个精灵的image 属性作为源图像,rect 属性作为位置。Group 并不保存精灵的顺序,所以绘制顺序是任意的。 |
clear(Surface_dest, background) -> None |
在给定的图像上清除上次调用Group.draw 方法所使用的精灵,通过在对应精灵的位置上进行填充来清除。参数background 通常是一个Surface 图像,要求尺寸与目标图像相同,但是也可以是一个回调函数,需要两个参数:目标图像和要清除的区域。 |
clear(Surface_dest, background) -> None |
从组中移除所有的精灵。 |
碰撞检测函数
sprite
模块中还定义了一些碰撞检测函数。以下内容将介绍常用的函数(详见官方文档)。
spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
:返回一个组中与一个精灵相交的所有的精灵的列表。布尔参数dokill
指定是否将所有将组中所有碰撞的精灵删除。可选的参数collided
是一个回调函数,用于计算两个精灵是否碰撞,它应该把两个精灵作为参数,并返回一个布尔值,表明是否相撞。如果没有传递collided
参数,则所有精灵都要求有rect
属性,用于计算碰撞。collided
可以传入的 Pygame 内置函数有:collide_rect
,collide_rect_ratio
,collide_circle
,collide_circle_ratio
,collide_mask
。
collide_rect(left, right) -> bool
:使用pygame.Rect.collide_rect
方法检测两个精灵之间的碰撞,要求两个精灵都有rect
属性。
collide_rect_ratio(ratio) -> collided_callable
:一个可调用的类,collide_rect
函数的可缩放版本,初始化时传入一个比率。
collide_circle(left, right) -> bool
:通过检测以精灵为中心的两个圆是否重叠来检测碰撞。如果精灵有radius
属性,将被用来创建圆,否则,将创建一个足够大的圆完全包围精灵的rect
属性。两个精灵必须有rect
属性和可选的radius
属性。
collide_circle_ratio(ratio) -> collided_callable
:一个可调用的类,collide_circle
函数的可缩放版本,初始化时传入一个比率。
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
:参数与spritecollide
函数类似,找到所有在两组之间发生碰撞的精灵。group1
中的所有精灵将添加为返回字典的键,而每个键对应的值就是group2
中与该精灵发生碰撞的精灵列表。
spritecollideany(sprite, group, collided = None) -> Sprite | None
:简单测试精灵是否与组中任何一个精灵相撞,如果有碰撞,将返回组中的一个精灵,否则,返回None
。
实例:弹球
本实例将利用Sprite
创建一个弹球引用程序。
请创建一个新的文件,命名为ball.py
,并添加以下代码:
import sys
import pygame
class BallGame:
def __init__(self) -> None:
self.screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption('Ball')
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.flip()
if __name__ == '__main__':
game = BallGame()
game.run()
创建精灵
我们需要创建一个继承于Sprite
类的精灵类Ball
,在BallGame
之前添加如下代码:
class Ball(pygame.sprite.Sprite):
def __init__(self, screen_rect) -> None:
super().__init__()
self.image = pygame.Surface((20, 20))
pygame.draw.circle(self.image, (255, 255, 255), (10, 10), 10)
self.screen_rect = screen_rect
self.rect = self.image.get_rect()
self.rect.center = self.screen_rect.center
self.vel = (2, 1)
def update(self):
self.rect.x += self.vel[0]
self.rect.y += self.vel[1]
if self.rect.left < 0 or self.rect.right > self.screen_rect.width:
self.vel = (-self.vel[0], self.vel[1])
if self.rect.top < 0 or self.rect.bottom > self.screen_rect.height:
self.vel = (self.vel[0], -self.vel[1])
上述代码中,Ball
类继承于Sprite
类,以定义一个精灵,并且使用pygame.draw.circle
函数在image
上绘制了一个白色的圆,同时将rect
定位到屏幕矩形的中心。
update
方法中,更新了rect
的位置,并防止球超出屏幕范围。
使用精灵
更改BallGame
类的方法,代码如下:
class BallGame:
def __init__(self) -> None:
self.screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption('Ball')
self.ball = Ball(self.screen.get_rect())
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self.screen.fill((0, 0, 0))
self.ball.update()
self.screen.blit(self.ball.image, self.ball.rect)
pygame.display.flip()
这里并没有使用Group
来组织精灵,是因为我们只使用了一个精灵,无需使用它。
完整代码
import sys
import pygame
class Ball(pygame.sprite.Sprite):
def __init__(self, screen_rect) -> None:
super().__init__()
self.image = pygame.Surface((20, 20))
pygame.draw.circle(self.image, (255, 255, 255), (10, 10), 10)
self.screen_rect = screen_rect
self.rect = self.image.get_rect()
self.rect.center = self.screen_rect.center
self.vel = (2, 1)
def update(self):
self.rect.x += self.vel[0]
self.rect.y += self.vel[1]
if self.rect.left < 0 or self.rect.right > self.screen_rect.width:
self.vel = (-self.vel[0], self.vel[1])
if self.rect.top < 0 or self.rect.bottom > self.screen_rect.height:
self.vel = (self.vel[0], -self.vel[1])
class BallGame:
def __init__(self) -> None:
self.screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption('Ball')
self.ball = Ball(self.screen.get_rect())
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self.screen.fill((0, 0, 0))
self.ball.update()
self.screen.blit(self.ball.image, self.ball.rect)
pygame.display.flip()
if __name__ == '__main__':
game = BallGame()
game.run()
代码运行截图:
文章来源:https://www.toymoban.com/news/detail-768948.html
结语(很重要!!)
至此,Pygame 教程已经结束啦🎉🎉!!!通过此教程,你已经学会了 Pygame 的基础知识。你已经可以尝试自己编写简单的应用了。笔者也会努力更新,争取写出更多好的作品。文章来源地址https://www.toymoban.com/news/detail-768948.html
到了这里,关于Pygame 教程(6):使用精灵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!