整个世界都使用了图片,变得漂漂亮亮的,而我们的马里奥却还是个小方块,是时候请马里奥现身,展现其真正的模样了。
马里奥的瓦片图集比较复杂,如图6‑1所示。第一组是普通马里奥,包括大个和小个两种状态,第二组是吃了火力花之后的状态,第三组是马里奥的弟弟路易吉,后面几组是吃了无敌星星变颜色的状态。

图6‑1马里奥的瓦片图集
普通马里奥的瓦片图如图6‑2所示,其中每个图片对应的状态已经标识出来。

图6‑2马里奥的图片对应的状态
让我们编写一个缓存类,将需要使用的图片拆分并进行缓存。由于图片数量不多而且会重复使用,建议使用有意义的变量名来存储图片,而不是使用数字编号。这样可以让代码更加清晰易懂,并且提高代码的可维护性。缓存类的代码如下所示:
06\01\MarioImageCache.py
|
import pygame from ImageUtil import *
# 马里奥图集 class MarioImageCache: def __init__(self): # 加载图集 marioSet = pygame.image.load("mario_bros_level1.png.png").convert_alpha()
# 小mario脸朝右的图片(按一行16像素,则小mario在第三行) self.marioWalk1 = ImageUtil.getSubImage(marioSet, 3, 0) # 走路1 self.marioWalk2 = ImageUtil.getSubImage(marioSet, 3, 1) # 走路2 self.marioWalk3 = ImageUtil.getSubImage(marioSet, 3, 2) # 走路3 self.marioStop = ImageUtil.getSubImage(marioSet, 3, 3) # 滑行 self.marioJump = ImageUtil.getSubImage(marioSet, 3, 4) # 跳跃 self.marioDead = ImageUtil.getSubImage(marioSet, 3, 5) # 死亡 self.marioStand = ImageUtil.getSubImage(marioSet, 3, 6) # 站立 self.marioPole = ImageUtil.getSubImage(marioSet, 3, 7) # 抱旗杆1 self.marioPole2 = ImageUtil.getSubImage(marioSet, 3, 8) # 抱旗杆2 self.marioSwim1 = ImageUtil.getSubImage(marioSet, 3, 9) # 游泳 self.marioSwim2 = ImageUtil.getSubImage(marioSet, 3, 10) # 游泳 self.marioSwim3 = ImageUtil.getSubImage(marioSet, 3, 11) # 游泳 self.marioSwim4 = ImageUtil.getSubImage(marioSet, 3, 12) # 游泳 self.marioSwim5 = ImageUtil.getSubImage(marioSet, 3, 13) # 游泳
# 小mario脸朝左的图片 self.marioLeftWalk1 = ImageUtil.flipImageX(self.marioWalk1) self.marioLeftWalk2 = ImageUtil.flipImageX(self.marioWalk2) self.marioLeftWalk3 = ImageUtil.flipImageX(self.marioWalk3) self.marioLeftStop = ImageUtil.flipImageX(self.marioStop) self.marioLeftJump = ImageUtil.flipImageX(self.marioJump) self.marioLeftStand = ImageUtil.flipImageX(self.marioStand) self.marioLeftPole = ImageUtil.flipImageX(self.marioPole) self.marioLeftPole2 = ImageUtil.flipImageX(self.marioPole2) self.marioLeftSwim1 = ImageUtil.flipImageX(self.marioSwim1) self.marioLeftSwim2 = ImageUtil.flipImageX(self.marioSwim2) self.marioLeftSwim3 = ImageUtil.flipImageX(self.marioSwim3) self.marioLeftSwim4 = ImageUtil.flipImageX(self.marioSwim4) self.marioLeftSwim5 = ImageUtil.flipImageX(self.marioSwim5)
# 大Mario脸朝右的图片 self.marioBigWalk1 = ImageUtil.getSubImage1632(marioSet, 1, 0) # 走路1 self.marioBigWalk2 = ImageUtil.getSubImage1632(marioSet, 1, 1) # 走路2 self.marioBigWalk3 = ImageUtil.getSubImage1632(marioSet, 1, 2) # 走路3 self.marioBigStop = ImageUtil.getSubImage1632(marioSet, 1, 3) # 滑行 self.marioBigJump = ImageUtil.getSubImage1632(marioSet, 1, 4) # 跳跃 self.marioBigSquat = ImageUtil.getSubImage1632(marioSet, 1, 5) # 下蹲 self.marioBigStand = ImageUtil.getSubImage1632(marioSet, 1, 6) # 站立 self.marioBigPole = ImageUtil.getSubImage1632(marioSet, 1, 7) # 抱旗杆1 self.marioBigPole2 = ImageUtil.getSubImage1632(marioSet, 1, 8) # 抱旗杆2 self.marioBigSwim1 = ImageUtil.getSubImage1632(marioSet, 1, 9) # 游泳 self.marioBigSwim2 = ImageUtil.getSubImage1632(marioSet, 1, 10) # 游泳 self.marioBigSwim3 = ImageUtil.getSubImage1632(marioSet, 1, 11) # 游泳 self.marioBigSwim4 = ImageUtil.getSubImage1632(marioSet, 1, 12) # 游泳 self.marioBigSwim5 = ImageUtil.getSubImage1632(marioSet, 1, 13) # 游泳 self.marioBigSwim6 = ImageUtil.getSubImage1632(marioSet, 1, 14) # 游泳 self.marioMiddleStand = ImageUtil.getSubImage1632(marioSet, 1, 15) # 半高 self.marioBigFire1 = ImageUtil.getSubImage1632(marioSet, 1, 16) # 开火1 self.marioBigFire2 = ImageUtil.getSubImage1632(marioSet, 1, 17) # 开火2 self.marioBigFire3 = ImageUtil.getSubImage1632(marioSet, 1, 18) # 开火3
# 大mario脸朝左的图片 self.marioBigLeftWalk1 = ImageUtil.flipImageX(self.marioBigWalk1) self.marioBigLeftWalk2 = ImageUtil.flipImageX(self.marioBigWalk2) self.marioBigLeftWalk3 = ImageUtil.flipImageX(self.marioBigWalk3) self.marioBigLeftStop = ImageUtil.flipImageX(self.marioBigStop) self.marioBigLeftJump = ImageUtil.flipImageX(self.marioBigJump) self.marioBigLeftSquat = ImageUtil.flipImageX(self.marioBigSquat) self.marioBigLeftStand = ImageUtil.flipImageX(self.marioBigStand) self.marioBigLeftPole = ImageUtil.flipImageX(self.marioBigPole) self.marioBigLeftPole2 = ImageUtil.flipImageX(self.marioBigPole2) self.marioBigLeftSwim1 = ImageUtil.flipImageX(self.marioBigSwim1) self.marioBigLeftSwim2 = ImageUtil.flipImageX(self.marioBigSwim2) self.marioBigLeftSwim3 = ImageUtil.flipImageX(self.marioBigSwim3) self.marioBigLeftSwim4 = ImageUtil.flipImageX(self.marioBigSwim4) self.marioBigLeftSwim5 = ImageUtil.flipImageX(self.marioBigSwim5) self.marioBigLeftSwim6 = ImageUtil.flipImageX(self.marioBigSwim6) self.marioMiddleLeftStand = ImageUtil.flipImageX(self.marioMiddleStand) self.marioBigLeftFire1 = ImageUtil.flipImageX(self.marioBigFire1) self.marioBigLeftFire2 = ImageUtil.flipImageX(self.marioBigFire2) self.marioBigLeftFire3 = ImageUtil.flipImageX(self.marioBigFire3) |
脸朝右边的图片可以直接从图集里截取,截取方法已经被封装在工具类ImageUtil中。而脸朝左边的图片则需要通过水平翻转脸朝右边的图片来获得,翻转操作也被封装在工具类中。以下是工具类的代码:
06\01\ImageUtil.py
|
import pygame
class ImageUtil:
# 根据行列号(从1开始)获取图片(16*16) # x坐标根据列号计算,y坐标根据行号计算 @staticmethod def getSubImage(imgSet, rowIndex, cellIndex): # x,y,width,height return imgSet.subsurface([(cellIndex - 1) * 16, (rowIndex - 1) * 16, 16, 16])
# 根据行列号(从1开始)获取图片(16*32) # x坐标根据列号计算,y坐标根据行号计算 @staticmethod def getSubImage1632(imgSet, rowIndex, cellIndex): # x,y,width,height return imgSet.subsurface([(cellIndex - 1) * 16, (rowIndex - 1) * 32, 16, 32])
# 水平翻转图片 @staticmethod def flipImageX(img): return pygame.transform.flip(img, True, False) |
在工具类中,我们使用了@staticmethod注解来定义方法,将其转换为静态方法。这样一来,可以直接使用ImageUtil.<方法名>的形式来调用方法。
其中,transform模块的flip方法用于翻转图片,格式如下:
flip(surface, flip_x, flip_y)
其中,flip_x和flip_y分别控制是否进行水平翻转和垂直翻转,取值为True或False。