pygame无法加载图片_利用 pygame 开发一款游戏:「跳跳兔」(七)

前言

在第 6 节内容中,实现了游戏结束逻辑与玩家图片化,但跳跳兔只是一张简单的图片,显得比较呆板,本节会为跳跳兔添加上相应的动画效果,并将平台替换成相应的图片。

添加动画

跳跳兔在站立时,希望有上下蹲的动画,在走动时,希望有左右走动的动画,在跳跃时,希望有跳跃动画。

动画的本质就是不同图片间的切换,在 pygame 中要实现动画,只需要在不同帧使用不同的图片则可。

在 Player 的__init__() 方法中定义多个变量用于记录不同的状态,代码如下

  1. # sprites.py
  2. class Player(pg.sprite.Sprite):
  3. def __init__(self, game):
  4. pg.sprite.Sprite.__init__(self)
  5. self.game = game
  6. # 不同的状态
  7. self.walking = False
  8. self.jumping = False
  9. # 当前帧(用于判断当前要执行哪个动画)
  10. self.current_frame = 0
  11. self.last_update = 0
  12. self.load_images() # 加载图片
  13. self.image = self.standing_frames[0]
  14. self.rect = self.image.get_rect()
  15. self.rect.center = (WIDTH / 2, HEIGHT / 2)
  16. self.pos = vec(WIDTH / 2, HEIGHT / 2)
  17. self.vel = vec(0, 0) # 速度
  18. self.acc = vec(0, 0) # 加速度

在__init__() 方法中,定义了 self.walking 与 self.jumping 状态,用于表示玩家对象是在行走状态还是跳跃状态,接着定义了 self.currentframe 用于表示当前帧,定义了 self.lastupdate 用于记录上一次的时间点,随后,编调用了 load_images () 方法来载入图片,该方法代码如下

  1. # sprites.py/Player
  2. def load_images(self):
  3. # 站立状态
  4. self.standing_frames = [self.game.spritesheet.get_image(614, 1063, 120, 191),
  5. self.game.spritesheet.get_image(690, 406, 120, 201)]
  6. for frame in self.standing_frames:
  7. frame.set_colorkey(BLACK) # 将图像矩阵中除图像外周围的元素都设置为透明的
  8. # 走动状态
  9. self.walk_frames_r = [self.game.spritesheet.get_image(678, 860, 120, 201),
  10. self.game.spritesheet.get_image(692, 1458, 120, 207)]
  11. self.walk_frames_l = []
  12. for frame in self.walk_frames_r:
  13. frame.set_colorkey(BLACK)
  14. # 水平翻转
  15. self.walk_frames_l.append(pg.transform.flip(frame, True, False))
  16. # 跳跃状态
  17. self.jump_frame = self.game.spritesheet.get_image(382, 763, 150, 181)
  18. self.jump_frame.set_colorkey(BLACK)

在 load_images () 方法中,为不同的状态载入了不同的图片,其中,走动状态的图片还做了水平翻转处理,这是因为原始的大图中,走动的图片只有一个方向的,而走动可以往左走也可以往右走,所以需要将图片水平翻转一下。

调用 pygame.transform.flip (Surface, xbool, ybool) 用于翻转,xbool => True 为水平翻转,ybool => True 为垂直翻转。

图片准备好后,动画效果的基本素材就准备好了,在 Player 类的 update () 方法中调用动画方法。

  1. # sprites.py/Player
  2. def update(self):
  3. # 动画
  4. self.animate()
  5. ...
  6. def animate(self):
  7. # 获得当前过了多少毫秒
  8. now = pg.time.get_ticks()
  9. if self.vel.x != 0: # 判断速度在x轴方向是否为0,从而判断玩家对象是否移动
  10. self.walking = True
  11. else:
  12. self.walking = False
  13. # 走动状态下的动画
  14. if self.walking:
  15. # 当前时间 - 上次时间 大于 180,即间隔时间大于180时
  16. if now - self.last_update > 180:
  17. self.last_update = now
  18. # 当前帧 加一 与 walk_frames_l 长度取余,从而得到当前要做哪个东西
  19. self.current_frame = (self.current_frame + 1) % len(self.walk_frames_l)
  20. bottom = self.rect.bottom
  21. # 向左走还是向右走
  22. if self.vel.x > 0:
  23. # 当前帧要做的动作
  24. self.image = self.walk_frames_r[self.current_frame]
  25. else:
  26. self.image = self.walk_frames_l[self.current_frame]
  27. self.rect = self.image.get_rect()
  28. self.rect.bottom = bottom
  29. # 站立状态下的动画
  30. if not self.jumping and not self.walking:
  31. if now - self.last_update > 350:
  32. self.last_update = now
  33. self.current_frame = (self.current_frame + 1) % len(self.standing_frames)
  34. bottom = self.rect.bottom
  35. self.image = self.standing_frames[self.current_frame]
  36. self.rect = self.image.get_rect()
  37. self.rect.bottom = bottom

在 pygame 中的时间是以毫秒(千分之一秒)表示的,通过 pygame.time.get_ticks 函数可以获得 pygame.init 后经过的时间的毫秒数。

随后的逻辑通过注释可以比较简单的理解。判断当前时间与上一层记录时间的间隔,如果满足条件,则只需图片的切换逻辑,注意,时间都是毫秒级的。

切换图片的核心逻辑就是当前帧与图片列表长度取余,获得下标,通过下标去取列表中的图片。

走动时效果如下:

b5c8ca84ea71c3944b287512ac79f3dc.png

有个细节需要注意,在判断玩家对象是否是走动状态时,利用了速度变量的 x 轴是否为 0 来判断

  1. if self.vel.x != 0: # 判断速度在x轴方向是否为0,从而判断玩家对象是否移动
  2. self.walking = True
  3. else:
  4. self.walking = False

但 self.vel.x 通常不会为 0,所以需要处理一下,修改一下 update () 方法中的逻辑,代码如下

  1. def update(self):
  2. # 动画
  3. self.animate()
  4. self.acc = vec(0, PLAYER_GRAV)
  5. keys = pg.key.get_pressed()
  6. if keys[pg.K_LEFT]:
  7. self.acc.x = -PLAYER_ACC
  8. if keys[pg.K_RIGHT]:
  9. self.acc.x = PLAYER_ACC
  10. # 获得加速度
  11. self.acc.x += self.vel.x * PLAYER_FRICTION
  12. # 速度与加速度
  13. self.vel += self.acc
  14. # 如果速度小于0.1,则速度为0(比如这样设置,不然速度永远无法0)
  15. if abs(self.vel.x) < 0.1:
  16. self.vel.x = 0
  17. self.pos += self.vel + 0.5 * self.acc
  18. # wrap around the sides of the screen
  19. if self.pos.x > WIDTH:
  20. self.pos.x = 0
  21. if self.pos.x < 0:
  22. self.pos.x = WIDTH
  23. self.rect.midbottom = self.pos

如果 self.vel.x 的绝对值小于 0.1,则让 self.vel.x 为 0。

平台图片化

跳跳兔要跳跃到相应的平台上,现在平依旧是方块,这里以相同的方式将平台替换成相应的图片。

在 Platform 的__init__() 中,实现载入图片的逻辑,代码如下

  1. class Platform(pg.sprite.Sprite):
  2. def __init__(self, game, x, y):
  3. pg.sprite.Sprite.__init__(self)
  4. self.game = game
  5. # 载入图片
  6. images = [self.game.spritesheet.get_image(0, 288, 380, 94),
  7. self.game.spritesheet.get_image(213, 1662, 201, 100)]
  8. # 随机选择一种
  9. self.image = random.choice(images)
  10. self.image.set_colorkey(BLACK)
  11. self.rect = self.image.get_rect()
  12. self.rect.x = x
  13. self.rect.y = y

载入完图片,随机选择一个图片作为样式,需要注意,我们修改了__init__() 的参数,此时该方法只需要获得 (x,y) 坐标以及 game 实例则可。

因为__init__() 被修改了,所以实例化逻辑也要修改一下。

  1. #setting.py
  2. # 起始平台
  3. PLATFORM_LIST = [(0, HEIGHT - 60),
  4. (WIDTH / 2 - 50, HEIGHT * 3 / 4 - 50),
  5. (125, HEIGHT - 350),
  6. (350, 200),
  7. (175, 100)]
  8. # main.py/Game
  9. def new(self):
  10. self.score = 0
  11. self.all_sprites = pg.sprite.Group()
  12. self.platforms = pg.sprite.Group()
  13. self.player = Player(self)
  14. self.all_sprites.add(self.player)
  15. for plat in PLATFORM_LIST:
  16. p = Platform(self, *plat)
  17. self.all_sprites.add(p)
  18. self.platforms.add(p)
  19. self.run()
  20. def update(self):
  21. # ...
  22. # 判断平台数,产生新的平台
  23. while len(self.platforms) < 6:
  24. width = random.randrange(50, 100)
  25. # 平台虽然是随机生成的,但会生成在某一个范围内
  26. p = Platform(self, random.randrange(0, WIDTH - width),
  27. random.randrange(-75, -30))
  28. self.platforms.add(p)
  29. self.all_sprites.add(p)

最终效果如下

067005c7cb3cd6d05454e337174216a2.png

在本节中,我们实现了玩家对象的动画效果以及平台的图片化。

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

https://github.com/ayuLiao/jumprabbit

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值