Collisions
在Pygame中,我们使用矩形来移动物体,并且用矩形检测碰撞。
colliderect
检测两个矩形是否碰撞,但是没法确定碰撞的方向。
Rect1.colliderect(Rect2)
# collision -> return Ture
# else -> return False
collidepoint
可以确定一个矩形是否和另一个矩形的某个点碰撞(并确定碰撞方向),但是会很麻烦,并且很容易遗漏某些碰撞。
Rect1.collidepoint(x, y)
# x,y is the point on a Rect
综合考虑之后,
我们通常使用colliderect
来检测碰撞,然后根据两个矩形的相对位置确定碰撞方向。
案例
一个矩形(和边框的碰撞)
# rect1
rect1 = pygame.Rect(100, 100, 50, 50)
color1 = (255, 255, 255)
speed_1_x = 5
speed_1_y = 5
def update_rect():
global speed_1_x, speed_1_y
rect1.x += speed_1_x
rect1.y += speed_1_y
# rect 和边界的碰撞:
if rect1.left <= 0 and speed_1_x <0:
speed_1_x *= -1
elif rect1.right >= witdth and speed_1_x > 0:
speed_1_x *= -1
if rect1.top <= 0 and speed_1_y < 0 :
speed_1_y *= -1
elif rect1.bottom >= height and speed_1_y > 0:
speed_1_y *= -1
pygame.draw.rect(screen, color1, rect1)
# 在主循环中调用 update_rect()
while True:
...
screen.fill((30, 30, 30))
update_rect()
...
添加第二个矩形
注意:除了判断碰撞方向之外,还要判断矩形的速度方向,以防止矩形在碰撞后反复移动。
# rect2
rect2 = pygame.Rect(200, 200, 200, 50)
color2 = (0, 255, 0)
speed_2_x = 0
speed_2_y = 4 # 为了简化,rect2只在竖直方向上移动
def update_rect():
global speed_1_x, speed_1_y, speed_2_y
...
rect2.y += speed_2_y
# rect 和边界的碰撞:
...
if rect2.top <= 0 and speed_2_y < 0 :
speed_2_y *= -1
elif rect2.bottom >= height and speed_2_y > 0:
speed_2_y *= -1
# rect1 和 rect2的碰撞
collide_threshold = 20
if rect1.colliderect(rect2):
if abs(rect1.top - rect2.bottom) < collide_threshold and speed_1_y < 0:
speed_1_y *= -1
elif abs(rect1.bottom - rect2.top) < collide_threshold and speed_1_y > 0:
speed_1_y *= -1
elif abs(rect1.left - rect2.right) < collide_threshold and speed_1_x < 0:
speed_1_x *= -1
elif abs(rect1.right - rect2.left) < collide_threshold and speed_1_x > 0:
speed_1_x *= -1
pygame.draw.rect(screen, color1, rect1)
pygame.draw.rect(screen, color2, rect2)
完整案例
两个方块的碰撞。为了简化,rect2只在竖直方向上移动。
import sys
import time
import pygame
# Initialize Pygame
pygame.init()
# Set up the display
witdth = 800
height = 600
screen = pygame.display.set_mode((witdth, height))
# Set up the clock
clock = pygame.time.Clock()
# rect1
rect1 = pygame.Rect(100, 100, 50, 50)
color1 = (255, 255, 255)
speed_1_x = 5
speed_1_y = 5
# rect2
rect2 = pygame.Rect(200, 200, 300, 50)
color2 = (0, 255, 0)
speed_2_x = 0
speed_2_y = 4 # 为了简化,rect2只在竖直方向上移动
def update_rect():
global speed_1_x, speed_1_y, speed_2_x, speed_2_y
rect1.x += speed_1_x
rect1.y += speed_1_y
#rect2.x += speed_2_x
rect2.y += speed_2_y
# rect 和边界的碰撞:
if rect1.left <= 0 and speed_1_x <0:
speed_1_x *= -1
elif rect1.right >= witdth and speed_1_x > 0:
speed_1_x *= -1
if rect1.top <= 0 and speed_1_y < 0 :
speed_1_y *= -1
elif rect1.bottom >= height and speed_1_y > 0:
speed_1_y *= -1
if rect2.top <= 0 and speed_2_y < 0 :
speed_2_y *= -1
elif rect2.bottom >= height and speed_2_y > 0:
speed_2_y *= -1
#以 HH:MM:SS 的格式 输出当前时间
form_time1 = time.strftime("%H:%M:%S", time.localtime())
print('rect2 to bottom', 'time= ', form_time1)
# rect1 和 rect 2的碰撞
collide_threshold = 20
if rect1.colliderect(rect2):
if abs(rect1.top - rect2.bottom) < collide_threshold and speed_1_y < 0:
speed_1_y *= -1
if abs(rect1.bottom - rect2.top) < collide_threshold and speed_1_y > 0:
speed_1_y *= -1
if abs(rect1.left - rect2.right) < collide_threshold and speed_1_x < 0:
speed_1_x *= -1
if abs(rect1.right - rect2.left) < collide_threshold and speed_1_x > 0:
speed_1_x *= -1
# Draw the rect
pygame.draw.rect(screen, color1, rect1)
pygame.draw.rect(screen, color2, rect2)
while True:
# Handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill((30, 30, 30))
update_rect()
# Update the display
pygame.display.flip()
# Cap the frame rate
clock.tick(60)