解决不规则图形碰撞
反例:
用矩形对象来检测两个圆的碰撞
# coding: utf-8
# 作者:爱编程的章老师
# 创建:2021/1/28 8:48 下午
# 邮箱:[email protected]
# 微信:slxxfl
# 微信公众号:A卫隆少儿编程
# 格言:给自己的生活增加一份向上的力,每都进步一点点
import pygame
from sys import exit
WIDTH = 800
HEIGHT = 800
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("没用遮罩")
clock = pygame.time.Clock()
# 红色圆
red_circle = pygame.Surface((200, 200), pygame.SRCALPHA)
pygame.draw.circle(red_circle, "red", (100, 100), 100)
# 红色圆的位置矩形
red_circle_rect = pygame.Rect(600, 0, 200, 200) # 初位置位于屏幕左上角
# 蓝色圆
blue_circle = pygame.Surface((200, 200), pygame.SRCALPHA)
pygame.draw.circle(blue_circle, "blue", (100, 100), 100)
# 蓝色圆的位置
blue_circle_rect = pygame.Rect(0, 600, 200, 200) # 初位置位于屏幕右下角
screen.blit(red_circle, red_circle_rect)
screen.blit(blue_circle, blue_circle_rect)
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if not red_circle_rect.colliderect(blue_circle_rect):
red_circle_rect.move_ip(-1, 1)
blue_circle_rect.move_ip(1, -1)
screen.fill("black")
screen.blit(red_circle, red_circle_rect)
screen.blit(blue_circle, blue_circle_rect)
pygame.display.update()
# 设置帧率
clock.tick(60)
效果图:
可以看到,当两个圆所在的矩形的角落发生碰撞的时候,就判定为碰撞成功.但这个显然不是我们想要的结果.
因此,对于圆(或其他不规则的形状)不能简单的用矩形来判定碰撞
遮罩的应用:
# coding: utf-8
# 作者:爱编程的章老师
# 创建:2021/1/28 8:48 下午
# 邮箱:[email protected]
# 微信:slxxfl
# 微信公众号:A卫隆少儿编程
# 格言:给自己的生活增加一份向上的力,每都进步一点点
import pygame
from sys import exit
WIDTH = 800
HEIGHT = 800
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("遮罩")
clock = pygame.time.Clock()
# 红色圆
red_circle = pygame.Surface((200, 200), pygame.SRCALPHA)
pygame.draw.circle(red_circle, "red", (100, 100), 100)
# 红色圆的位置矩形
red_circle_rect = pygame.Rect(600, 0, 200, 200) # 初位置位于屏幕左上角
m1 = pygame.mask.from_surface(red_circle) # 生成红球的遮罩
# 蓝色圆
blue_circle = pygame.Surface((200, 200), pygame.SRCALPHA)
pygame.draw.circle(blue_circle, "blue", (100, 100), 100)
# 蓝色圆的位置
blue_circle_rect = pygame.Rect(0, 600, 200, 200) # 初位置位于屏幕右下角
m2 = pygame.mask.from_surface(blue_circle) # 生成蓝球的遮罩
screen.blit(red_circle, red_circle_rect)
screen.blit(blue_circle, blue_circle_rect)
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
offset = blue_circle_rect.x - red_circle_rect.x, blue_circle_rect.y - red_circle_rect.y
p = m1.overlap(m2, offset)
if not p:
red_circle_rect.move_ip(-1, 1)
blue_circle_rect.move_ip(1, -1)
screen.fill("black")
screen.blit(red_circle, red_circle_rect)
screen.blit(blue_circle, blue_circle_rect)
pygame.display.update()
# 设置帧率
clock.tick(60)
效果图:
可以看到,当我们用了遮罩的时候,两个是真实的碰到了一起才停止移动
使用遮罩的基本流程:
mask1 = pygame.mask.from_surface(surface,threshold = 127)
当surface对象是基于set_colorkey 透明时,第二个参数会忽略
当surface对象是基于每象素透明时,第二个参数是是一个阈值.如果该象的alpha的值>127则不透明,<127则透明
透明处的值为1,不透明的值为0
mask1.overlap(mask2, offset)
offset = rect2.x - rect1.x , rect2.y - rect1.y
offset:第二个遮罩对应的矩形的左上角与第一个遮罩对应的矩形的左上角的相对位置.
因此,按上面的公式进行计算即可
上式代码会返回一个值.这个值为第二个遮罩与第一个遮罩的碰撞点的相对于第一个遮罩的左上角的坐标:
如rect1.x = 10, rect1.y = 20
p = (20, 20)
即这个点在 第一个矩形左上的右侧20 象素,下方20象素的位置
即实际位置为(30,40)
如果没有碰撞,则返回一个None的值