7.3    金币滚动

当马里奥移动时,会发现金币也跟随着移动,一直位于马里奥的头顶,如7‑5所示。

75马里奥行走后的金币

         这是因为金币的显示位置在代码中是固定的,所以金币始终显示在屏幕的特定位置,它的坐标实际是屏幕坐标。我们希望金币能随着屏幕滚动而移动,并最终移出屏幕不再可见。滚屏动作现在是更新马里奥后触发的,代码如下所示:

07\02\mario\Mario.py

        # 显示马里奥

        self.screen.blit(self.image, self.rect)

 

        # 滚动地图

        if self.currentState.getScrollMap():

            Globals.game.scrollMap(self.walkStep)

         scrollMap()方法中,会改变屏幕的显示范围,随后在下一帧会根据新范围重新绘制地图,从而实现地图滚动的效果。然而,由于金币是单独创建的,不在地图文件中,它是一个游离于地图之外的物体,因此地图的重绘不会影响到金币。

         我们需要将金币管理起来,使用一个数组来存储多个金币对象,代码如下所示:

07\02\Game.py

        # 多个金币

        from item.FlashingCoinAnimation import FlashingCoinAnimation

        self.itemArray = [FlashingCoinAnimation(100, 100),

                          FlashingCoinAnimation(260, 110),

                          FlashingCoinAnimation(400, 60)]

在重绘地图后,只需更新数组中所有物体的坐标,即可实现物体随屏幕滚动。不过,在修改代码进行坐标转换的过程中,我们发现金币与地图中的砖块、水管类似,都需要两个坐标:一个地图坐标和一个屏幕坐标。实际上,金币类中的坐标可以被视为地图坐标,表示金币在整个地图中的位置,绘制时转换为屏幕坐标即可。由于scrollMap()方法会更新mapViewFrom值,因此下一帧金币的屏幕坐标自然就变化了,金币类本身不需要进行额外操作。

修改后的金币代码如下所示:

07\02\item\FlashingCoinAnimation.py

from pygame import Rect

from game_globals.Globals import Globals

from game_globals.constants import MAP_BLOCK_SIZE, SCREEN_WIDTH

from utils.utils import mapToScreen

 

 

# 闪烁金币动画

class FlashingCoinAnimation(object):

    # 帧动画

    frames = [Globals.itemImageCache.flashingCoinImg1,

              Globals.itemImageCache.flashingCoinImg1,

              Globals.itemImageCache.flashingCoinImg2,

              Globals.itemImageCache.flashingCoinImg3,

              Globals.itemImageCache.flashingCoinImg4]

 

    # 构造方法,记录初始坐标

    def __init__(self, x, y):

        self.rect = Rect(x, y, MAP_BLOCK_SIZE, MAP_BLOCK_SIZE)  # 地图坐标

        self.frameDuration = 100  # 每帧显示时间,单位为毫秒

        self.frameIndex = 0  # 当前帧的下标

        self.elapsedTime = 0  # 时间差累计

 

    # 更新动画

    def update(self, keys, deltaTime):

        # 转换为屏幕坐标,并判断是否在显示范围内

        screenRect = mapToScreen(self.rect)

        if screenRect[0] + MAP_BLOCK_SIZE > 0 and screenRect[0] < SCREEN_WIDTH:

 

            # 时间差累计

            self.elapsedTime += deltaTime

 

            # 切换动画图片

            if self.elapsedTime > self.frameDuration:

                self.elapsedTime -= self.frameDuration  # 减去差值

                self.frameIndex += 1

                if self.frameIndex >= len(self.frames):

                    self.frameIndex = 0

 

            # 显示图片

            Globals.screen.blit(self.frames[self.frameIndex], screenRect)

         运行程序,画面如7‑6所示。

76多个金币

滚动屏幕后,可以看到金币也随着移动了,如7‑7所示。

77随着屏幕滚动的金币