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

  • 相关阅读:
    [转]String.getBytes()和new String()
    [转]文件加密和数字签名技术概述
    [转]Java获取当前路径
    Jaxb笔记
    [转]Hibernate重要规则总结
    [转]Hibernate3如何解决n+1 selects
    将win7电脑无线网变身WiFi热点,让手机、笔记本共享上网 (转)
    项目打包安装到未越狱的机器
    回调函数、消息和事件例程
    iPhone与iPad开发实战读书笔记
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/pygame-kidscancode-part13-improve-jump.html
Copyright © 2011-2022 走看看