【问题标题】:Detect collision between textbox and circle in pygame检测pygame中文本框和圆圈之间的碰撞
【发布时间】:2019-10-09 13:49:44
【问题描述】:

我正在尝试在 python 中创建一个游戏,其中可以在屏幕上拖动一个文本框,但是每当它触及围绕它的圆圈的边界时,我希望循环重新开始,但使用不同的文本(通过将所有文本字符串存储在列表中,但我还没有那么远)。这是我已经走了多远:

import pygame

import ptext

pygame.init()

gameDisplay = pygame.display.set_mode((500, 500))

gameDisplay.fill((255,255,255))

x = 190
y = 230
a = 250
b = 250

text = "ExampleText 1."

def textbox(x,y):
    ptext.draw(text, (x,y), color = (0,0,0))


def circle(a,b): 
    pygame.draw.circle(gameDisplay, (0,0,0), (250, 250), 210, 5)


done = False

while not done:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.MOUSEMOTION:
            if event.buttons[0]:
                x += event.rel[0]
                y += event.rel[1]

    textbox(x,y)
    circle(a,b)
    pygame.display.flip()

pygame.quit()
quit()

现在我知道我需要检测对象边界的碰撞,但在这里我很迷茫。我试图将我的对象的变量存储在矩形中,然后生成另一个 if 语句来识别我的对象是否发生碰撞(我使用了打印命令,因为我还没有得到我想要的实际命令),但这赢了'不要打印任何东西,我确定我走错了路,但这是我的最大努力......

为此我已经定义:

text_rect = pygame.Rect(x, y, 10, 30)

circle_rect = pygame.Rect(a,b, 300, 300)

然后在我的循环中:

if circle_rect.colliderect(text_rect): 
     print("COLLIDE")

有人对定义对象和创建我想要的功能的更好方法有任何建议吗?

(编辑:顺便说一句:我不太担心当我拖动我的文本框时,它会留下文本的打印,因为这在我的原始脚本中不会发生,但如果有人会感激不尽知道为什么在我当前的示例中会这样做。)

【问题讨论】:

    标签: python pygame collision-detection


    【解决方案1】:

    一个矩形有 4 个角点。如果矩形比圆“小”(圆的直径大于矩形的对角线),则矩形与圆的轮廓相撞,如果至少有一个点在圆外且至少圆中有一点。

    定义矩形并设置角点列表。进一步你必须知道圆的半径:

    w, h = 10, 30
    rect = pygame.Rect(x, y, 10, 30)
    
    corners = [rect.bottomleft, rect.bottomright, rect.topleft, rect.topright]
    radius = 210
    

    计算每个角点到圆心(a, b)Euclidean distance

    import math
    
    dist = [math.sqrt((p[0]-a)**2 + (p[1]-b)**2) for p in corners]
    

    创建列表,一个带有圆内的点 (p_in),一个带有圆外的点 (p_out):

    p_out = [i for i, d in enumerate(dist) if d > radius]
    p_in  = [i for i, d in enumerate(dist) if d < radius]
    

    如果两个列表都包含any元素,则矩形与圆形轮廓相交:

    if any(p_in) and any(p_out):
        print("COLLIDE")
    

    如果len(p_in) 为4,则矩形完全在圆中。如果len(p_out) 为 4,则矩形完全在圆外。

    if any(p_in) and any(p_out):
        print("COLLIDE")
    elif len(p_in) == 4:
        print("IN")
    elif len(p_out) == 4:
        print("OUT")
    

    查看简单示例,该示例基于您的代码 sn-p 并演示了碰撞测试。矩形附加到鼠标上:

    import pygame
    import math
    
    pygame.init()
    gameDisplay = pygame.display.set_mode((500, 500))
    done = False
    while not done:
        for event in pygame.event.get(): 
            if event.type == pygame.QUIT:
                done = True
    
        x, y = pygame.mouse.get_pos()
        w, h = 10, 30
        rect = pygame.Rect(x, y, 10, 30)
        a, b = 250, 250
        radius = 210
    
        corners = [rect.bottomleft, rect.bottomright, rect.topleft, rect.topright]
        dist    = [math.sqrt((p[0]-a)**2 + (p[1]-b)**2) for p in corners] 
        p_out   = [i for i, d in enumerate(dist) if d > radius]
        p_in    = [i for i, d in enumerate(dist) if d < radius]
    
        if any(p_in) and any(p_out):
            print("COLLIDE")
        elif len(p_in) == 4:
            print("IN")
        elif len(p_out) == 4:
            print("OUT")
    
        gameDisplay.fill((255,255,255))
        pygame.draw.rect(gameDisplay, (255, 0, 0), rect)
        pygame.draw.circle(gameDisplay, (0,0,0), (a, b), radius, 5)
        pygame.display.flip()
    
    pygame.quit()
    quit()
    

    【讨论】:

    • 首先,感谢您提供的出色方法。我现在尝试整合您的定义和循环部分,但现在每次移动对象时它打印的都是“IN”,我不明白为什么......另外,你能解释一下 p[0] 和 p [1] 在欧几里得距离函数中?谢谢。
    • @psyph 1. “现在打印的都是“IN” 我无法调试你的代码,但我已经添加了我用来测试的示例方法,答案。2.corners的内容是角点[rect.bottomleft, ...],每个角点是一个x和y坐标的元组(这就是pygame.Rect为一个点返回的)。所以p[0]p[1](在for p in corners中)是该点的x和y坐标。
    • 哦,我明白了。而且,在矩形固定到鼠标的示例的帮助下,我的代码可以按照我想要的方式工作。非常感谢您的帮助。
    猜你喜欢
    • 2012-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 2023-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多