0%

利用pygame开发一款游戏:「跳跳兔」(四)

简介

「跳跳兔」小游戏中的玩家当然要有跳跃能力,本节就来实现玩家类的跳跃以及整个游戏框界面的更新,当玩家跳跃时,游戏背景要往后移动,要有新的平台产生,让玩家可以继续跳跃,本节就来实现这样的功能。

赋予玩家跳跃功能

为了让界面有多个元素,在一开始初始化游戏框时,就初始化多个平台元素,效果如下:

代码如下,为了方便理解,没有展示无关代码,将多个文件的代码一同显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# settings.py

# 平台列表
PLATFORM_LIST = [(0, HEIGHT - 40, WIDTH, 40),
(WIDTH / 2 - 50, HEIGHT * 3 / 4, 100, 20),
(125, HEIGHT - 350, 100, 20),
(350, 200, 100, 20),
(175, 100, 50, 20)]

# main.py/Game

def new(self):
# start a new game
self.all_sprites = pg.sprite.Group()
self.platforms = pg.sprite.Group()
self.player = Player(self)
self.all_sprites.add(self.player)
# 实例化一系列平台,并添加到所有元素组与平台元素组中
for plat in PLATFORM_LIST:
p = Platform(*plat)
self.all_sprites.add(p)
self.platforms.add(p)
self.run()

上述逻辑就是在开始新游戏时,for迭代创建PLATFORM_LIST列表中给定位位置与大小的平台。

接着就来实现跳跃逻辑。

为了代码直观,将监控跳跃相关的逻辑写到events()方法中(该方法负责事件处理),我们希望点击空格键,玩家元素跳跃,其具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
# main.py/Game

def events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
if self.playing:
self.playing = False
self.running = False
# 玩家跳跃
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
self.player.jump() # 调用玩家跳跃方法

简单而言,就是监控键盘敲击事件,然后判断敲击的按键为空格键(K_SPACE),最后调用玩家对象的jump()方法实现跳跃。

看一下jump()方法的具体逻辑。

1
2
3
4
5
6
7
8
9
10
#sprites.py/Player

# 跳跃
def jump(self):
# 对x轴进行加一减一操作,玩家只有站立在平台上,才能跳跃成功。
self.rect.x += 1
hits = pg.sprite.spritecollide(self, self.game.platforms, False)
self.rect.x -= 1
if hits: # 碰撞检测成功,站立在了平台上
self.vel.y = -20 # 跳跃

对player玩家对象的x走了加一减一并进行碰撞检测的操作,通过这种方式,就可以判断当前玩家对象是否站立与平台上,只有在平台上,才能让其跳跃,在空中是不允许玩家跳跃的(无法二段跳).

跳跃的本质是让玩家对象向上移动,这里就是-20,之所以是负数,是因为最上传y轴坐标为0,最下方y轴坐标为游戏框的高度,-20就是让玩家对象向上移动,如下图:

但这里跟新的只是self.vel速度属性,真正移动玩家对象的方法依旧是update()方法,其逻辑如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#sprites.py/Player

def update(self):
# 有初始的加速度 - 玩家没有在平台上就会掉落
self.acc = vec(0, PLAYER_GRAV)
keys = pg.key.get_pressed()
if keys[pg.K_LEFT]:
self.acc.x = -PLAYER_ACC
if keys[pg.K_RIGHT]:
self.acc.x = PLAYER_ACC

self.acc.x += self.vel.x * PLAYER_FRICTION
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
# 赋值给底部 - 碰撞检测相关
self.rect.midbottom = self.pos

update()方法逻辑与上节内容相同,不再赘述。

至此,就完成了玩家的跳跃。

背景移动效果

但玩家对象光跳跃是不够的,整个游戏界面不移动,玩家跳两下就没有平台可以跳跃了,所以接着来实现游戏界面整体移动的效果。

在开始写之前,需要理清一个概念,要实现移动效果,并不是游戏界面整体向下移动了,而是游戏框中的元素整体向后移动的,具体而言就是玩家类向下移动了一部分具体,对应的平台元素也向下移动了一段距离。

要实现这个效果,可以通过Game游戏类的update()方法来实现,该方法主要用于更新游戏的整体状态,其具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# main.py/Game

def update(self):
self.all_sprites.update()
# # 玩家在界面中时(y>0),进行碰撞检测,检测玩家是否碰撞到平台
if self.player.vel.y > 0:
hits = pg.sprite.spritecollide(self.player, self.platforms, False)
if hits:
self.player.pos.y = hits[0].rect.top
self.player.vel.y = 0
# 玩家到达游戏框 1/4 处时(注意,游戏框,头部为0,底部为游戏框长度,到到游戏框的1/4处,表示已经到达了顶部一部分了)
if self.player.rect.top <= HEIGHT / 4:
# 玩家位置移动(往下移动)
self.player.pos.y += abs(self.player.vel.y)
# 平台在游戏框外时,将其注销,避免资源浪费
for plat in self.platforms:
# 平台移动位置(往下移动,移动的距离与玩家相同,这样玩家才能依旧站立在原本的平台上)
plat.rect.y += abs(self.player.vel.y)
if plat.rect.top >= HEIGHT:
plat.kill()

# 判断平台数,产生新的平台
while len(self.platforms) < 6:
width = random.randrange(50, 100)
# 随机生成平台
p = Platform(random.randrange(0, WIDTH - width),
random.randrange(-75, -30),
width, 20)
self.platforms.add(p)
self.all_sprites.add(p)

Game类的update()方法中,主要新增了两段逻辑。

当玩家到达游戏框的1/4时,此时玩家对象已经在高位,此时要做的就是移动玩家对象以及通过for迭代移动所有的平台对象,让玩家对象与平台对象向下移动相同的距离实现整个游戏框界面向下移动的效果。此外还会判断平台对象的顶部是否大于游戏框高度,如果大于,说明当前的平台对象依旧完全在游戏框外了,调用kill()方法将其注销,避免占用额外的内存。

接着通过while循环当前平台对象的个数,通过此前的逻辑,我们消除了在游戏框外的平台对象,为了让平台对象个数总是为6,这里会随机创建相应个数的平台对象作为补充,通过random来实现平台位置的随机,让游戏不至于太过无聊。

结尾

因为考虑到篇幅,文中没有给出完整的代码,但为了方便大家理解,我将相应的代码上传到了github

https://github.com/ayuLiao/jumprabbit

如果文章对你有帮助或你觉得有点意思,点击「在看」支持作者一波。