第6章    马里奥优化

整个世界都使用了图片,变得漂漂亮亮的,而我们的马里奥却还是个小方块,是时候请马里奥现身,展现其真正的模样了。

6.1    瓦片图集

马里奥的瓦片图集比较复杂,如6‑1所示。第一组是普通马里奥,包括大个和小个两种状态,第二组是吃了火力花之后的状态,第三组是马里奥的弟弟路易吉,后面几组是吃了无敌星星变颜色的状态。

61马里奥的瓦片图集

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

62马里奥的图片对应的状态

让我们编写一个缓存类,将需要使用的图片拆分并进行缓存。由于图片数量不多而且会重复使用,建议使用有意义的变量名来存储图片,而不是使用数字编号。这样可以让代码更加清晰易懂,并且提高代码的可维护性。缓存类的代码如下所示:

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_xflip_y分别控制是否进行水平翻转和垂直翻转,取值为TrueFalse