碰撞检测(collision detection)负责计算屏幕上地两个物体合适发生彼此接触(也就是发生碰撞)。碰撞检测在游戏中应用还是比较多的,不如玩家接触敌人损失生命值,得到金币增加游戏金钱等等。
在这个程序中,碰撞检测将判断两个矩形是否彼此重叠。
目录
(一)循环准备
1)导入模块
2)使用一个时钟来同步程序
3)创建窗口和数据结构
4)设置变量以记录移动
(二)游戏循环
1)处理事件
处理KEYDOWN事件
处理KEYUP事件
处理MOUSEBUTTONUP事件
2)添加新的食物块
3)在屏幕上移动玩家
将玩家绘制到屏幕上
检查碰撞
绘制方块、收尾
主要内容:
import pygame, sys, random
from pygame.locals import *
# Set up pygame.
pygame.init()
mainClock = pygame.time.Clock()
# Set up the window.
WINDOWWIDTH = 400
WINDOWHEIGHT = 400
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT),
0, 32)
pygame.display.set_caption('Collision Detection')
# Set up the colors.
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
# Set up the player and food data structures.
foodCounter = 0
NEWFOOD = 40
FOODSIZE = 20
player = pygame.Rect(300, 100, 50, 50)
foods = []
for i in range(20):
foods.append(pygame.Rect(random.randint(0, WINDOWWIDTH - FOODSIZE),
random.randint(0, WINDOWHEIGHT - FOODSIZE), FOODSIZE, FOODSIZE))
# Set up movement variables.
moveLeft = False
moveRight = False
moveUp = False
moveDown = False
MOVESPEED = 6
import pygame, sys, random
from pygame.locals import *
# Set up pygame.
pygame.init()
mainClock = pygame.time.Clock()
一个程序运行的快慢取决于计算机的快慢。如果你想要程序在任何的计算机上都以相同的速度运行,我们需要一个函数能够对于较快的计算机暂停的时间长一点,而对于较慢的计算机暂停的时间短一些。
pygame.time.Clock对象可以对任何计算机都暂停适当的时间。
# Set up the player and food data structures.
foodCounter = 0
NEWFOOD = 40
FOODSIZE = 20
player = pygame.Rect(300, 100, 50, 50)
foods = []
for i in range(20):
foods.append(pygame.Rect(random.randint(0, WINDOWWIDTH - FOODSIZE),
random.randint(0, WINDOWHEIGHT - FOODSIZE), FOODSIZE, FOODSIZE))
首先是为食物方块创建了一些变量。
player = pygame.Rect为玩家的位置设置了一个pygame.Rect对象,它表示方块的大小和位置。
通过for循环,调用pygame.Rect()构造函数来返回一个新的pygame.Rect对象,用来表示食物方块的位置和大小。并将其添加到foods中去。其中要注意我们想要一个随机的坐标,它在0和窗口大小减去食物方块大小所得结果之间。如果使用了0到窗口大小之间的一个随机坐标,那么可能会把食物方块推到了窗口之外。
# Set up movement variables.
moveLeft = False
moveRight = False
moveUp = False
moveDown = False
MOVESPEED = 6
以上代码创建了记录玩家方块在每一个方向上的移动的一些变量。
这4个布尔值变量用来记录按下了哪个方向键。例如,当用户按下键盘上向左的方向键时,把moveLeft设置为True。当松开这个键时,把moveLeft设置回False。
MOVESPEED = 5用于设置移动速度。
# Run the game loop.
while True:
# Check for events.
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
# Change the keyboard variables.
if event.key == K_LEFT or event.key == K_a:
moveRight = False
moveLeft = True
if event.key == K_RIGHT or event.key == K_d:
moveLeft = False
moveRight = True
if event.key == K_UP or event.key == K_w:
moveDown = False
moveUp = True
if event.key == K_DOWN or event.key == K_s:
moveUp = False
moveDown = True
if event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_LEFT or event.key == K_a:
moveLeft = False
if event.key == K_RIGHT or event.key == K_d:
moveRight = False
if event.key == K_UP or event.key == K_w:
moveUp = False
if event.key == K_DOWN or event.key == K_s:
moveDown = False
if event.key == K_x:
player.top = random.randint(0, WINDOWHEIGHT -
player.height)
player.left = random.randint(0, WINDOWWIDTH -
player.width)
if event.type == MOUSEBUTTONUP:
foods.append(pygame.Rect(event.pos[0], event.pos[1],
FOODSIZE, FOODSIZE))
foodCounter += 1
if foodCounter >= NEWFOOD:
# Add new food.
foodCounter = 0
foods.append(pygame.Rect(random.randint(0, WINDOWWIDTH -
FOODSIZE), random.randint(0, WINDOWHEIGHT - FOODSIZE),
FOODSIZE, FOODSIZE))
# Draw the white background onto the surface.
windowSurface.fill(WHITE)
# Move the player.
if moveDown and player.bottom < WINDOWHEIGHT:
player.top += MOVESPEED
if moveUp and player.top > 0:
player.top -= MOVESPEED
if moveLeft and player.left > 0:
player.left -= MOVESPEED
if moveRight and player.right < WINDOWWIDTH:
player.right += MOVESPEED
# Draw the player onto the surface.
pygame.draw.rect(windowSurface, BLACK, player)
# Check whether the player has intersected with any food squares.
for food in foods[:]:
if player.colliderect(food):
foods.remove(food)
# Draw the food.
for i in range(len(foods)):
pygame.draw.rect(windowSurface, GREEN, foods[i])
# Draw the window onto the screen.
pygame.display.update()
mainClock.tick(40)
pygame模块可以产生事件以响应来自鼠标或者键盘的用户输入。如下是常见的事件。
事件 | 产生途径 | 参数 |
QUIT | 用户按下关闭按钮 | none |
ATIVEEVENT | Pygame被激活或者隐藏 | gain, state |
KEYDOWN | 键盘被按下 | unicode, key, mod |
KEYUP | 键盘被放开 | key, mod |
MOUSEMOTION | 鼠标移动 | pos, rel, buttons |
MOUSEBUTTONDOWN | 鼠标按下 | pos, button |
MOUSEBUTTONUP | 鼠标放开 | pos, button |
JOYAXISMOTION | 游戏手柄(Joystick or pad) 移动 | joy, axis, value |
JOYBALLMOTION | 游戏球(Joy ball) 移动 | joy, axis, value |
JOYHATMOTION | 游戏手柄(Joystick) 移动 | joy, axis, value |
JOYBUTTONDOWN | 游戏手柄按下 | joy, button |
JOYBUTTONUP | 游戏手柄放开 | joy, button |
VIDEORESIZE | Pygame窗口缩放 | size, w, h |
VIDEOEXPOSE | Pygame窗口部分公开(expose) | none |
USEREVENT | 触发了一个用户事件 | code |
MOUSEMOTION事件会在鼠标动作的时候发生,它有三个参数:
buttons | 一个含有三个数字的元组,三个值分别代表左键、中键和右键,1就是按下了。 |
pos | 位置 |
rel | 代表了现在距离上次产生鼠标事件时的距离 |
和MOUSEMOTION类似的,我们还有MOUSEBUTTONDOWN和MOUSEBUTTONUP两个事件。它们的参数为:
button | 这个值代表了哪个按键被操作 |
pos | 位置 |
键盘的事件为KEYDOWN和KEYUP :
key | 按下或者放开的键值,是一个数字,Pygame中可以使用K_xxx来表示,比如字母a就是K_a,还有K_SPACE和K_RETURN等。 |
mo | 包含了组合键信息,如果mod & KMOD_CTRL是真的话,表示用户同时按下了Ctrl键。类似的还有KMOD_SHIFT,KMOD_ALT。 |
unicode | 代表了按下键的Unicode值 |
Key中键盘按键的常量变量可查看Pygame.locals常量。
常用事件函数:
if event.type == KEYDOWN:
# Change the keyboard variables.
if event.key == K_LEFT or event.key == K_a:
moveRight = False
moveLeft = True
if event.key == K_RIGHT or event.key == K_d:
moveLeft = False
moveRight = True
if event.key == K_UP or event.key == K_w:
moveDown = False
moveUp = True
if event.key == K_DOWN or event.key == K_s:
moveUp = False
moveDown = True
以上代码实现:当按下A键时,就会改变记录移动变量的布尔值。按下DWS按键时同理。
if event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_LEFT or event.key == K_a:
moveLeft = False
if event.key == K_RIGHT or event.key == K_d:
moveRight = False
if event.key == K_UP or event.key == K_w:
moveUp = False
if event.key == K_DOWN or event.key == K_s:
moveDown = False
if event.key == K_x:
player.top = random.randint(0, WINDOWHEIGHT -
player.height)
player.left = random.randint(0, WINDOWWIDTH -
player.width)
当释放按下的键时,会触发KEYUP事件。
如果用户释放的是ESC键,那么程序终止。记住,在pygame中在调用sys.exit()之前,必须先调用pygame.quit()函数。
如果是该方向的按键是释放状态的话,就会改变变量为False。
如果玩家释放的是X键,则将用户的方块随机的放在一个位置。
通过点击鼠标添加新的食物块。当鼠标释放时,会触发MOUSEBUTTONUP事件。
if event.type == MOUSEBUTTONUP:
foods.append(pygame.Rect(event.pos[0], event.pos[1],
FOODSIZE, FOODSIZE))
如果鼠标进行了点击,就在该位置添加一个食物块。
可以使用鼠标添加,也可以设置自动添加。
if event.type == MOUSEBUTTONUP:
foods.append(pygame.Rect(event.pos[0], event.pos[1],
FOODSIZE, FOODSIZE))
foodCounter += 1
if foodCounter >= NEWFOOD:
# Add new food.
foodCounter = 0
foods.append(pygame.Rect(random.randint(0, WINDOWWIDTH -
FOODSIZE), random.randint(0, WINDOWHEIGHT - FOODSIZE),
FOODSIZE, FOODSIZE))
NEWFOOD为食物块添加的速度。
每次循环之后需要用白色windowSurface.fill(WHITE)填充屏幕。
我们已经根据用户的按键,设置了移动变量(moveDown、moveUp、moveLeft、和moveRight)。现在,通过调整玩家的X坐标和Y坐标,来移动玩家的方块(用存储在player中的pygame.Rect对象来表示)。
# Draw the white background onto the surface.
windowSurface.fill(WHITE)
# Move the player.
if moveDown and player.bottom < WINDOWHEIGHT:
player.top += MOVESPEED
if moveUp and player.top > 0:
player.top -= MOVESPEED
if moveLeft and player.left > 0:
player.left -= MOVESPEED
if moveRight and player.right < WINDOWWIDTH:
player.right += MOVESPEED
# Draw the player onto the surface.
pygame.draw.rect(windowSurface, BLACK, player)
使用Rect对象都拥有的碰撞检测方法colliderect():
# Check whether the player has intersected with any food squares.
for food in foods[:]:
if player.colliderect(food):
foods.remove(food)
其中foods[ : ]是foods列表的一个副本。
# Draw the food.
for i in range(len(foods)):
pygame.draw.rect(windowSurface, GREEN, foods[i])
# Draw the window onto the screen.
pygame.display.update()
mainClock.tick(40)
其中mainClock.tick(40):调用我们前面前面创建的Clock对象的方法,调整程序运时间。
参考: