看过之前的范例代码后,大家有什么感受呢?想必已经对位置计算和碰撞检测的细微之处感到头疼了吧。接下来,让我们尝试使用Pygame提供的Rect对象来简化这一过程。
Rect对象中存储了矩形的位置和大小信息,格式如下:
Rect(left, top, width, height)
使用Rect对象后,马里奥的变量原本需要四个,现在只需要一个就足够了,代码对比如下:
|
#旧写法,马里奥位置和大小 marioX=10 marioY=20 marioWidth = blockSize marioHeight = blockSize
#Rect的写法 marioRect = pygame.Rect(10, 20, blockSize, blockSize) |
看起来简洁多了,而且还可以使用marioRect.x、marioRect.y、marioRect.width和marioRect.height来轻松获取位置和宽高信息。最重要的是,Rect对象提供了一个方法用来检测两个矩形是否碰撞,返回True表示碰撞,格式如下:
RectA.colliderect(RectB)
让我们尝试使用Rect对象重新编写程序,代码如下所示:
02\10.py
|
import pygame
# 初始化pygame pygame.init()
# 设置窗口大小 WIDTH = 600 HEIGHT = 400 screen = pygame.display.set_mode((WIDTH, HEIGHT))
# 设置窗口标题 pygame.display.set_caption('super mario bros')
# 避免输入法影响按键 pygame.key.stop_text_input()
# 时钟 clock = pygame.time.Clock()
# 方块大小 blockSize = 30
# 马里奥位置和大小 marioRect = pygame.Rect(10, 20, blockSize, blockSize)
# 水管的位置和大小 pipeRect = pygame.Rect(400, 300 - blockSize * 2, blockSize, blockSize * 2)
# 主循环 isRunning = True while isRunning: for event in pygame.event.get(): if event.type == pygame.QUIT: isRunning = False
# 马里奥的步伐 marioWalkStep = 18
# 获取按键状态 keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: print("按了左方向键")
# 窗口边界判断 if marioRect.x - marioWalkStep <= 0: marioWalkStep = marioRect.x
# 下一步预判断 nextStepRect = marioRect.move(-1 * marioWalkStep, 0) if nextStepRect.colliderect(pipeRect): marioWalkStep = marioRect.x - pipeRect.right marioRect = marioRect.move(-1 * marioWalkStep, 0) if keys[pygame.K_RIGHT]: print("按了右方向键")
# 窗口边界判断 if marioRect.right + marioWalkStep >= WIDTH: marioWalkStep = WIDTH - marioRect.right
# 下一步预判断 nextStepRect = marioRect.move(marioWalkStep, 0) if nextStepRect.colliderect(pipeRect): marioWalkStep = pipeRect.x - marioRect.right marioRect = marioRect.move(marioWalkStep, 0) if keys[pygame.K_g]: print("按了跳跃键") if marioRect.y > 0: marioRect = marioRect.move(0, -10)
# 全屏擦除 screen.fill((0, 0, 0))
# 地平线 pygame.draw.line(screen, (255, 255, 255), (0, 300), (WIDTH, 300), 1) # 画直线
# 障碍物 pygame.draw.rect(screen, (255, 255, 255), pipeRect, 0)
# 马里奥Y轴步伐 marioWalkStepY = 4
# 下一步预判断 nextStepRect = marioRect.move(0, marioWalkStepY) if nextStepRect.colliderect(pipeRect): marioWalkStepY = pipeRect.y - marioRect.bottom marioRect = marioRect.move(0, marioWalkStepY) if marioRect.y >= 300 - marioRect.height: marioRect.y = 300 - marioRect.height
# 显示马里奥 pygame.draw.rect(screen, (0, 0, 0), marioRect, 1) # 边框 pygame.draw.rect(screen, (255, 255, 255), marioRect.inflate(-2, -2), 0) # 边框内部白色填充 pygame.draw.rect(screen, (0, 0, 0), marioRect.inflate(-10, -10), 0) # 中心黑色填充
# 刷新显示 pygame.display.flip()
# 每秒60帧 clock.tick(60) # 退出 Pygame pygame.quit() |
在代码中,我们使用了Rect对象的move(x, y)方法来实现位置移动。其中,参数x和y可以为负数,x为正值表示向右移动,负值表示向左移动,y为正值表示向下移动,负值表示向上移动。需要注意的是,move方法返回一个新的Rect对象,如果需要修改原来的Rect对象,需要将新的Rect对象重新赋值给自己。
此外,Rect对象提供了一些便捷的属性供我们使用,如marioRect.left等同于marioRect.x,marioRect.right等同于marioRect.x + marioRect.width,marioRect.bottom等同于marioRect.y + marioRect.height。想要了解更多属性,请阅读官方文档。修改属性可能会导致位置的变化,比如修改right值实际上会改变X坐标的值。
还有一个有用的方法是inflate(x, y),它可以在保持矩形中心不变的情况下放大或缩小矩形。如果参数是正数,则放大矩形,如果是负数,则缩小矩形。这比手动计算位置和大小要方便得多。
当我们运行程序后,会发现效果与之前一样,但代码变得更加简洁了。