这节研究下跳跃如何做得更自然,先看看之前的跳跃有什么问题,我们把settings.py里的初始化参数调整下:
1 # starting platform 2 # PLATFORM_LIST = [(5, HEIGHT - 35), 3 # (WIDTH / 2 - 50, HEIGHT * 0.75), 4 # (WIDTH * 0.12, HEIGHT * 0.5), 5 # (WIDTH * 0.65, 200), 6 # (WIDTH * 0.5, 100)] 7 8 PLATFORM_LIST = [(15, HEIGHT - 35), 9 (55, HEIGHT - 140), 10 (5, HEIGHT - 215), 11 (WIDTH * 0.70, 180), 12 (WIDTH * 0.5, 100)]View Code
同时,把Platform类微调一下,只加载长的跳板:
1 class Platform(pg.sprite.Sprite): 2 def __init__(self, game, x, y): 3 pg.sprite.Sprite.__init__(self) 4 self.game = game 5 images = [self.game.spritesheet.get_image("ground_grass_broken.png"), 6 self.game.spritesheet.get_image("ground_grass_small_broken.png")] 7 # self.image = random.choice(images) 8 # 临时改成只使用长的跳板 9 self.image = images[0] 10 self.rect = self.image.get_rect() 11 self.rect.x = x 12 self.rect.y = yView Code
仔细观察一下,有二个问题:
1. (当跳板上下间隔较小时)player越过第2块跳板(从下向上数,初始时,站着的那块为1),直接蹦到第3块上去了,有点不太自然,如果头顶有板的话,最好是落在最低的那块上
2.从第3块,向下落到第2块时,继续向左走,理论上应该落到第1块板上,但是无论如何,总是会被第3块板自动吸上去。
原因:连续碰到多个跳板时,碰撞检测返回的是一个被碰到的跳板数组,hits[0]返回的是最高的那块,所以总是被吸上去。
改进思路:找出最低那块,后面的就好处理了。
def update(self): self.all_sprites.update() if self.player.vel.y > 0: hits = pg.sprite.spritecollide(self.player, self.platforms, False) if hits: # 当player向上同时碰撞到多个跳板(注:跳板之间挨得很近时,容易出现这种情况) # 找出最低的那块,让player落上最低的跳板上 lowest = hits[0] for hit in hits: if hit.rect.bottom > lowest.rect.bottom: lowest = hit if self.player.pos.y < lowest.rect.centery: self.player.pos.y = lowest.rect.top self.player.vel.y = 0 ...
改进后的效果:
搞定这个,还有一个小问题:
当player走到跳板边缘时,实际上确实发生了碰撞(从垂直方向上看,player的身体与跳板有重叠,即碰撞),但从视觉上看,双脚已经离开跳板了,应该向下掉,看上去不太真实。
改进办法:
发生碰撞时,对比player.centerx(角色的x轴中心点)与跳板的left/right值,只有x轴中心点未离开跳板时,才认为真正发生了碰撞。
仍然是修改刚才的碰撞检测代码:(注:具体实现时,下面的代码在两侧保留了5px的余量,大家可以调整下这个值,以控制检测的灵敏度)
def update(self): self.all_sprites.update() if self.player.vel.y > 0: hits = pg.sprite.spritecollide(self.player, self.platforms, False) if hits: # 当player向上同时碰撞到多个跳板(注:跳板之间挨得很近时,容易出现这种情况) # 找出最低的那块,让player落上最低的跳板上 lowest = hits[0] for hit in hits: if hit.rect.bottom > lowest.rect.bottom: lowest = hit if self.player.pos.y < lowest.rect.centery: # fix 走到跳板最边缘时,仍挂在半空中,不掉下去 if lowest.rect.right + 5 >= self.player.rect.centerx >= lowest.rect.left - 5: self.player.pos.y = lowest.rect.top self.player.vel.y = 0 ...
效果:
源码:https://github.com/yjmyzz/kids-can-code/tree/master/part_13