PyGame圆形碰撞问题 - 圆形内部

时间:2011-05-04 07:16:56

标签: python collision-detection physics pygame game-physics

我正在制作一款益智游戏,要求用户在背景上“画圆”以将球送到出口。他们通过按住鼠标按钮创建圆圈,圆圈增大;当它足够大的时候,它们就会松开,然后它被“打孔”进入物理空间,然后球会对它作出反应。

然而,我有一个问题,当两个圆相交时(因此球应该通过),如果交点不大于球的直径,则球与内部碰撞这个圈子像往常一样。

这可能有点难以理解,所以这里有一个显示问题的截屏视频链接(你无法在Stack Overflow上嵌入视频):http://www.youtube.com/watch?v=3dKyPzqTDhs

希望这使我的问题清楚。以下是BallCircle类的Python / PyGame代码:

class Ball():
    def __init__(self, (x,y), size, colourID):
        """Setting up the new instance"""
        self.x = x
        self.y = y
        self.size = size
        self.exited = False
        self.colour = setColour(colourID)
        self.thickness = 0
        self.speed = 0.01
        self.angle = math.pi/2

    def display(self, surface):
        """Draw the ball"""
        # pygame.gfxdraw.aacircle(screen,cx,cy,new_dist,settings['MINIMAP_RINGS'])
        if self.exited != True:
            pygame.draw.circle(surface, self.colour, (int(self.x), int(self.y)), self.size, self.thickness)

    def move(self):
        """Move the ball according to angle and speed"""
        self.x += math.sin(self.angle) * self.speed
        self.y -= math.cos(self.angle) * self.speed
        (self.angle, self.speed) = module_physicsEngine.addVectors((self.angle, self.speed), gravity)
        self.speed *= drag

Circle类:

class Circle():
    def __init__(self, (x,y), size, colourID):
        """Set up the new instance of the Circle class"""
        self.x = x
        self.y = y
        self.size = size
        self.colour = setColour(colourID)
        self.thickness = 2
        self.angle = 0 # Needed for collision...
        self.speed = 0 # detection against balls

    def display(self, surface):
        """Draw the circle"""
        pygame.draw.circle(surface, self.colour, (int(self.x), int(self.y)), self.size, self.thickness)

在游戏的主循环(while running == True:等)中,此代码用于对每个球执行操作:

for b in balls:
    b.move()
    for i, ball in enumerate(balls):
        for ball2 in balls[i+1:]:
            collideBalls(ball, ball2)
        collideCircle(b) #      <---------------- This is the important line
        collideExit(b)
        b.display(screen)

最后,collideCircle(b)函数,每个球调用一次以检查与圆内部的碰撞,并检查圆是否相交。

def collideCircle(ball):
    """Check for collision between a ball and a circle"""

    hit = False
    closestDist = 0

    for c in circles:
        # Code cannot be replaced with physicsEngine.collideTest because it
        # is slightly differnt, testing if ball [ball] inside a circle [c]
        dx = c.x - ball.x
        dy = c.y - ball.y
        distance = math.hypot(dx, dy)

        if distance <= c.size - ball.size:
            # If BALL inside any CIRCLE
            hit = False
            break
        else:
            # If we're outside of a circle.
            if closestDist < c.size - (distance - ball.size):
                hit = c
                closestDist = (c.size - (distance - ball.size))

    if hit:

        module_physicsEngine.circleBounce(hit, ball)

好的,所以我知道这是一个冗长而有说服力的问题,但我认为你拥有所需的所有信息。解决方案是让球正确地与线if distance <= c.size - ball.size:进行交互吗?

无论如何,提前谢谢!

纳丹出去了。

TL; DR - 观看youtube视频,并告诉我它为什么无效。

2 个答案:

答案 0 :(得分:1)

问题在于无意识的点击而不是错过的点击。你真正想要检查的是球的所有部分是否被某个圆覆盖,而你正在做的检查是否有任何圆圈只是部分重叠 - 但如果任何圆圈完全覆盖球,则覆盖。

我认为任何潜在的生命点,即最近的圆形内壁,通过检查它与所有其他圆圈的距离,让该点沿着墙“行走”。如果它然后离开球,这是一个错误的打击。

首先,您会找到触及球的圆圈列表。和以前一样,如果有任何一个覆盖它,你可以跳过其余的检查。同时找到圆圈最接近球的壁点。对于每个最近的壁点,如果它与另一个圆重叠,则将其移动到最接近球但距离当前点更远的交叉点。如果它在球外,请丢弃它。对所有圆圈重复此过程,因为两个以上可能重叠。另请注意,移动该点可能会导致其进入新的圈子。

您可以预先计算交叉点并丢弃任何其他圆圈内的任何球半径。

这肯定可以改进,但我认为这是一个开始。当一对圆的两个交叉点与球重叠时,我怀疑涉及这种情况的错误,但是一条步行链将其中一个引导到球外。也许初始碰撞点应该仅由两个交叉点替换,而不是最接近的交叉点。

答案 1 :(得分:0)

我观看了视频,我喜欢游戏原理。 :)

问题是,当你遇到一个包围球的圆圈时,你break就会离开循环。我指的是片段

if distance <= c.size - ball.size:
    # If BALL inside any CIRCLE
    hit = False
    break

在这种情况下,为什么不检查所有其他圈子?可能还有另一个未选中的圈子导致hit

顺便说一下,我不会说if condition == True:,那是不可思议的。只需说if condition: