现在还遗留了一个问题,当滚动地图时,如果马里奥移动到水管的左侧时,如图3‑7所示。

图3‑7马里奥位于水管左侧
此时,继续滚动地图,马里奥会嗖的一下自己跳上水管,如图3‑8所示,但实际上我们并没有按跳跃键。

图3‑8 马里奥自己跳上了水管
让我们仔细研究一下为什么会发生这种情况。
在第一帧中,地图滚动,马里奥移动到水管左侧,如图3‑7的位置。
第二帧包含以下步骤:
l 根据当前mapViewFrom变量的值,绘制地图。
l 马里奥处理按键,向右移动。因为马里奥超过屏幕的一半位置,直接修改了mapViewFrom变量的值来移动屏幕范围。
l 马里奥处理重力,需要将马里奥的坐标转换为地图坐标,然后进行碰撞检测。由于上一步修改了mapViewFrom的值,所以转换后的地图坐标,实际是马里奥向右移动了一步的坐标。马里奥的右侧是水管,所以检测到碰撞,但是,这个碰撞检测是不区分方向的,无论是横着撞到水管还是竖着撞到水管,结果都是一样的。这时认为马里奥在掉落时碰到了水管,所以将马里奥放到水管顶部。
通过分析可见,第一个问题是在处理当前帧时提前修改了mapViewFrom的值,影响了后续的坐标转换。解决办法是暂时不修改变量值,只做一个标记,直到本帧结束再修改变量值。第二个问题是滚动地图时直接滚动,而没有判断右侧是否有障碍物。为了解决这两个问题,需要做一些修改,代码如下所示:
03\06\Mario.py
|
# 更新 def update(self, keys):
# 步伐,先恢复默认值 self.walkStep = self.walkStepDefault self.jumpStep = self.jumpStepDefault self.dropStep = self.dropStepDefault
# 是否滚动地图 isScrollMap = False
# 按键状态 if keys[pygame.K_LEFT]: print("按了左方向键")
# 窗口边界判断 if self.rect.x - self.walkStep <= 0: self.walkStep = self.rect.x
# 下一步预判断 nextStepRect = self.rect.move(-1 * self.walkStep, 0) pipeIndex = screenToMap(nextStepRect).collidelist(Globals.game.objectArray) # 是否碰撞 if pipeIndex != -1: self.walkStep = self.rect.x - mapToScreen(Globals.game.objectArray[pipeIndex]).right self.rect = self.rect.move(-1 * self.walkStep, 0) if keys[pygame.K_RIGHT]: print("按了右方向键")
# 超过屏幕中线才滚动地图,地图末尾右半屏也不滚动 if self.rect.x >= SCREEN_WIDTH / 2 and screenToMap( self.rect).x < Globals.game.mapViewFromMax + SCREEN_WIDTH / 2:
# 如果地图滚动后,有碰撞发生,则不能滚动 # 地图向左滚动,相当于马里奥向右移动。 # 这里不能修改mapViewFrom的值 nextStepRect = self.rect.move(self.walkStep, 0) pipeIndex = screenToMap(nextStepRect).collidelist(Globals.game.objectArray) if pipeIndex == -1: isScrollMap = True else: # 窗口边界判断 if self.rect.right + self.walkStep >= SCREEN_WIDTH: self.walkStep = SCREEN_WIDTH - self.rect.right
# 下一步预判断 nextStepRect = self.rect.move(self.walkStep, 0) pipeIndex = screenToMap(nextStepRect).collidelist(Globals.game.objectArray) if pipeIndex != -1: self.walkStep = mapToScreen(Globals.game.objectArray[pipeIndex]).x - self.rect.right self.rect = self.rect.move(self.walkStep, 0) if keys[pygame.K_g]: print("按了跳跃键")
# 窗口边界判断 if self.rect.y - self.jumpStep <= 0: self.jumpStep = self.rect.y
# 下一步预判断 nextStepRect = self.rect.move(0, -1 * self.jumpStep) pipeIndex = screenToMap(nextStepRect).collidelist(Globals.game.objectArray) if pipeIndex != -1: self.jumpStep = (mapToScreen(Globals.game.objectArray[pipeIndex]).bottom - self.rect.y) * -1 self.rect = self.rect.move(0, -1 * self.jumpStep)
# ----重力影响---- # 下一步预判断 nextStepRect = self.rect.move(0, self.dropStep) pipeIndex = screenToMap(nextStepRect).collidelist(Globals.game.objectArray) if pipeIndex != -1: self.dropStep = mapToScreen(Globals.game.objectArray[pipeIndex]).y - self.rect.bottom self.rect = self.rect.move(0, self.dropStep)
# 显示马里奥 pygame.draw.rect(self.screen, COLOR_BLACK, self.rect, 1) # 边框 pygame.draw.rect(self.screen, COLOR_WHITE, self.rect.inflate(-2, -2), 0) # 边框内部白色填充 pygame.draw.rect(self.screen, COLOR_BLACK, self.rect.inflate(-10, -10), 0) # 中心黑色填充
# 滚动地图 if isScrollMap: Globals.game.scrollMap(self.walkStep) |
由于不能修改mapViewFrom的值,所以让马里奥移动后进行碰撞检测,效果与滚动地图来检测是一样的。注意nextStepRect变量是一个临时变量,只是用来做碰撞检测,实际并没有修改马里奥的Rect对象。运行程序,会发现马里奥跳上水管的问题解决了。