微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在pygame中使用碰撞点函数时,线被检测为矩形的对角线

如何解决在pygame中使用碰撞点函数时,线被检测为矩形的对角线

我正在研究一个基于图形的项目。我正在画线来表示边缘。我的目标是当我点击特定的线条时改变线条的颜色。问题是 pygame 将线视为虚拟矩形的对角线。因此,即使我不单击线条但鼠标位置在虚拟矩形的投影区域中,使用collidepoint() 时也会将事件检测为碰撞。我只想在仅在实际行上单击鼠标时检测到这一点。

我是 pygame 的新手,所以如果有其他我可以使用的函数或库,请告诉我。这是我的项目的示例代码

import pygame

pygame.init()

screen = pygame.display.set_mode((1200,700))

running = True
red = 0
green = 255
blue = 210

while running:
   screen.fill((red,green,blue))
    line = pygame.draw.line(screen,(50,50),(400,400),10)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            if line.collidepoint(event.pos):
                red = 255
                green = 0
                blue = 0
        if event.type == pygame.MOUSEBUTTONUP:
            red = 0
            green = 255
            blue = 210

    pygame.display.update()

解决方法

pygame.draw.line 返回一个 pygame.Rect 对象,该对象定义围绕线的轴对齐的边界矩形。 collidepoint 测试点是否在矩形中。


您必须使用不同的方法。编写一个函数来计算点到线的最短距离:

dist = abs(dot(normalized(NV),P - LP)),其中 NV 是线的法向量,LP 是线上的一个点,P 是需要计算距离的点。

import math
def distance_point_line(pt,l1,l2):
    nx,ny = l1[1] - l2[1],l2[0] - l1[0]
    nlen = math.hypot(nx,ny)
    nx /= nlen
    ny /= nlen
    vx,vy = pt[0] - l1[0],pt[1] - l1[1]
    dist = abs(nx*vx + ny*vy)
    return dist

与使用pygame.math.Vector2相同的功能:

def distance_point_line(pt,l2):
    NV = pygame.math.Vector2(l1[1] - l2[1],l2[0] - l1[0])
    LP = pygame.math.Vector2(l1)
    P = pygame.math.Vector2(pt)
    return abs(NV.normalize().dot(P -LP))

测试鼠标指针是否在直线定义的矩形内,距离是否小于线宽的一半:

if (line_rect.collidepoint(event.pos) and 
    distance_point_line(event.pos,(50,50),(400,400)) < 5):
    # [...]

说明:

我使用了从点到线的 Dot product 距离。一般来说,2 个向量的点积等于 2 个向量之间夹角的 余弦乘以两个向量的大小(长度)。

dot( A,B ) == | A | * | B | * cos( angle_A_B ) 

由此可知,2 Unit vectors 的点积等于 2 个向量之间夹角的 余弦,因为单位向量的长度为 1。

uA = normalize( A )
uB = normalize( B )
cos( angle_A_B ) == dot( uA,uB )

因此归一化法向量到直线 (NV) 和直线上的点 (LP) 到距离必须的点的点积计算(P)是点到线的最短距离。


最小示例:

import pygame
import math

pygame.init()
screen = pygame.display.set_mode((1200,700))

def distance_point_line(pt,l2[0] - l1[0])
    LP = pygame.math.Vector2(l1)
    P = pygame.math.Vector2(pt)
    return abs(NV.normalize().dot(P -LP))

color = (255,255,255)
running = True
while running:

    screen.fill((0,0))
    line_rect = pygame.draw.line(screen,color,400),10)
    pygame.display.update()
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        
        if event.type == pygame.MOUSEBUTTONDOWN: 
            if (line_rect.collidepoint(event.pos) and 
                distance_point_line(event.pos,400)) < 5):
                color = (255,0)
        if event.type == pygame.MOUSEBUTTONUP:
            color = (255,255)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。