zoukankan      html  css  js  c++  java
  • pygame-KidsCanCode系列jumpy-part13-改进跳跃

    这节研究下跳跃如何做得更自然,先看看之前的跳跃有什么问题,我们把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 = y
    View 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.bottom:
                          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.bottom:
                        # 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
                    ...
    

    效果:

    最后一个可以改进的地方,玩过超级玛丽的大概还记得这么一个细节:跳跃时,如果空格键按得比较重,会跳得较高,反之如果轻轻按一下,马上松开,跳跃的高度相对就很少。

    分析一下其中的原理,其实按键较重时,『按下的时间』相对轻轻一按马上抬起,会略长一点。所以,关键在于KEYUP事件,只要在该事件中,想办法快速终止跳跃,自然向上跳的高度就小。

    在event事件中,先添加对KEYUP的响应:

     1     def events(self):
     2         for event in pg.event.get():
     3             if event.type == pg.QUIT:
     4                 if self.playing:
     5                     self.playing = False
     6                 self.running = False
     7             if event.type == pg.KEYDOWN:
     8                 if event.key == pg.K_SPACE:
     9                     self.player.jump()
    10             # 按键松开时,强行中断跳跃
    11             if event.type == pg.KEYUP:
    12                 if event.key == pg.K_SPACE:
    13                     self.player.jump_cut()
    View Code

    然后在Player类中,新增jump_cut函数:

    1     def jump_cut(self):
    2         if self.jumping:
    3             # 给1个很小的正向速度,让其下降
    4             self.vel.y = 1
    View Code

    如果觉得vel.y=1这样有点粗暴(相当于把上升直接骤变为下降),也可以改进成下面这样:

    1     def jump_cut(self):
    2         if self.jumping:
    3             if self.vel.y < -3:
    4                 self.vel.y = -3
    View Code

    即:如果上升过快(即向上跳的速度过大),则让它变成一个较小的速度-3px,这样从视觉上看运动过程要连贯一些。

    此外,jump函数中,也要结合self.jumping标志位一起判断,同时要设置jumping标志位的值:

    1     def jump(self):
    2         hits = pg.sprite.spritecollide(self, self.game.platforms, False)
    3         # 加入状态位判断
    4         if hits and not self.jumping:
    5             self.vel.y = -PLAYER_JUMP
    6             if abs(self.vel.x) < 0.5:
    7                 self.jumping = True
    View Code

    另外,在下落停在档板上时,需要把jumping状态设置为False(main.py中的update函数里微调):

     1     def update(self):
     2         self.all_sprites.update()
     3         if self.player.vel.y > 0:
     4             hits = pg.sprite.spritecollide(self.player, self.platforms, False)
     5             if hits:
     6                 lowest = hits[0]
     7                 for hit in hits:
     8                     if hit.rect.bottom > lowest.rect.bottom:
     9                         lowest = hit
    10                 if self.player.pos.y < lowest.rect.bottom:
    11                     if lowest.rect.right + 5 >= self.player.rect.centerx >= lowest.rect.left - 5:
    12                         self.player.pos.y = lowest.rect.top
    13                         self.player.vel.y = 0
    14                         # 停下后,修改状态位
    15                         self.player.jumping = False
    View Code

    效果如下:

     

    源码:https://github.com/yjmyzz/kids-can-code/tree/master/part_13

  • 相关阅读:
    C#深入浅出 修饰符(二)
    HDU 5785 Interesting
    HDU 5783 Divide the Sequence
    HDU 5781 ATM Mechine
    UVA 714 Copying Books
    uva 1471 Defense Lines
    UVA 11134 Fabled Rooks
    UVA 11572 Unique Snowflakes
    UVA 11093 Just Finish it up
    UVA 10954 Add All
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/pygame-kidscancode-part13-improve-jump.html
Copyright © 2011-2022 走看看