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)