Python 椭圆与圆的碰撞检测

Python 椭圆与圆的碰撞检测,python,math,pygame,collision-detection,ellipse,Python,Math,Pygame,Collision Detection,Ellipse,我想在椭圆和圆之间进行碰撞检测。我这样做的方式是: 计算从椭圆中心到圆的角度 计算该点在该角度的椭圆中的位置 检查是否与该点发生碰撞 然而,我有一个小问题。当我计算角度时,它好像偏离了90度。我做了一个肮脏的修正,简单地增加了1.5弧度来解释90度,这有点工作,但存在不一致性,在某些角度下不能正常工作,特别是在0.7和-2.6弧度左右。这是代码(所有的冲突内容都在collision类中的eliple方法中) 导入pygame 从数学输入sin,cos,atan2,弧度 pygame.init()

我想在椭圆和圆之间进行碰撞检测。我这样做的方式是:

  • 计算从椭圆中心到圆的角度
  • 计算该点在该角度的椭圆中的位置
  • 检查是否与该点发生碰撞
  • 然而,我有一个小问题。当我计算角度时,它好像偏离了90度。我做了一个肮脏的修正,简单地增加了1.5弧度来解释90度,这有点工作,但存在不一致性,在某些角度下不能正常工作,特别是在0.7和-2.6弧度左右。这是代码(所有的冲突内容都在
    collision
    类中的
    eliple
    方法中)

    导入pygame
    从数学输入sin,cos,atan2,弧度
    pygame.init()
    SW=1200
    SH=600
    WIN=pygame.display
    D=赢。设置_模式((SW,SH))
    班级圈子:
    定义初始(自身,半径):
    self.x=0
    self.y=0
    自半径=半径
    def更新(自我,pos):
    self.x=pos[0]
    self.y=pos[1]
    def绘图(自显示):
    pygame.draw.circle(显示,(255,0,0),(int(self.x),int(self.y)),self.radius,2)
    圆圈=圆圈(30)
    类椭圆:
    定义初始值(自身、中心、接收、ry):
    自我中心
    self.collide=False
    self.rx=rx
    self.ry=ry
    def绘图(自显示):
    角度=0
    当角度<6.28时:
    角度+=0.001
    x=自中心[0]+sin(角度)*自接收
    y=自中心[1]+cos(角度)*自中心
    如果自碰撞:
    显示。将_设置为((int(x),int(y)),(255,0,0))
    其他:
    显示。将_设置为((int(x),int(y)),(0,0,255))
    pygame.draw.circle(D,(0,255,0),(int(自中心[0]),int(自中心[1])),5)
    def碰撞(自身、圆):
    #与圆成角度
    dx=圆x-自中心[0]
    dy=圆y-自中心[1]
    角度=atan2(-dy,dx)
    打印(角度)
    #点位于椭圆中该角度处的位置
    x=sin(角度+1.5)*self.rx+self.center[0]
    y=cos(角度+1.5)*self.ry+self.center[1]
    #打印(x,y)
    #绘制点只是为了确保其工作正常
    #(调试)
    pygame.draw.circle(D,(0,255,0),(int(x),int(y)),5)
    #我们刚才看到的点之间的距离
    #计算出圆的中心
    距离=((x-circle.x)**2+(y-circle.y)**2)**0.5
    #打印(距离)
    #碰撞条件
    如果距离<圆半径:
    self.collide=True
    其他:
    self.collide=False
    椭圆=椭圆([600300],300200)
    尽管如此:
    events=pygame.event.get()
    mousePos=pygame.mouse.get_pos()
    对于事件中的事件:
    如果event.type==pygame.QUIT:
    pygame.quit()
    D.填充((255、255、255))
    循环更新(鼠标点)
    画圆(D)
    椭圆图(D)
    椭圆.碰撞(圆)
    pygame.display.flip()
    
    第一个错误是,1.5不等于pi/2:

    从数学导入pi
    
    x=sin(角度+1.5)*self.rx+self.center[0]

    y=cos(角度+1.5)*self.ry+self.center[1]

    x=sin(角度+pi/2)*self.rx+self.center[0]
    y=cos(角度+pi/2)*自转角+自中心[1]
    

    第二,通过角度计算椭圆上的点稍微复杂一些。请参见问题的答案和:

    从数学导入pi、sin、cos、atan2、弧度、copysign、sqrt
    
    类椭圆:
    # [...]
    def pointFromAngle(自身,a):
    c=cos(a)
    s=sin(a)
    ta=s/c##tan(a)
    tt=ta*self.rx/self.ry#tan(t)
    d=1sqrt(1.+tt*tt)
    x=自中心[0]+复制符号(自接收*d,c)
    y=自中心[1]-复制符号(自中心*tt*d,s)
    返回x,y
    def碰撞(自身、圆):
    # [...]
    #点位于椭圆中该角度处的位置
    x、 y=自身点fromAngle(角度)
    # [...]
    

    最简单的例子:

    导入数学
    导入pygame
    班级圈子:
    定义初始(自、中心x、中心y、半径):
    self.center=中心x,中心y
    自半径=半径
    def更新(自我、中心x、中心y):
    self.center=中心x,中心y
    def绘图(自、表面):
    pygame.draw.circle(曲面,(255,0,0),(圆(自中心[0])、圆(自中心[1])、自半径,3)
    类椭圆:
    定义初始(自、中心、顶点):
    self.center=中心
    self.collide=False
    self.vertex=顶点
    def绘图(自、表面):
    bounding_rect=pygame.rect(0,0,self.vertex[0]*2,self.vertex[1]*2)
    边界中心=圆形(自中心[0]),圆形(自中心[1])
    pygame.draw.ellipse(曲面,(0,255,0),边界矩形,3)
    def pointFromAngle(自身,a):
    c=数学cos(a)
    s=数学。sin(a)
    ta=s/c##tan(a)
    tt=ta*self.vertex[0]/self.vertex[1]##tan(t)
    d=1数学sqrt(1.+tt*tt)
    x=self.center[0]+数学复制符号(self.vertex[0]*d,c)
    y=self.center[1]-数学复制符号(self.vertex[1]*tt*d,s)
    返回x,y
    定义相交圆椭圆(圆,椭圆):
    dx=圆.中心[0]-椭圆.中心[0]
    dy=圆.中心[1]-椭圆.中心[1]
    角度=数学常数2(-dy,dx)
    x、 y=椭圆。点从角度(角度)
    距离=数学形(x-圆.中心[0],y-圆.中心[1])
    
    返回距离谢谢你的回答。我明白为什么你发布的解决方案会起作用,但我不明白为什么我的解决方案不起作用,因为画的点清楚地一直在椭圆上。我很困惑。@hippozipos你用不同的方法缩放了
    sin(角度)
    cos(角度)
    import pygame
    from math import sin, cos, atan2, radians
    pygame.init()
    
    SW = 1200
    SH = 600
    WIN = pygame.display
    D = WIN.set_mode((SW, SH))
    
    class Circle:
        def __init__(self, radius):
            self.x = 0
            self.y = 0
            self.radius = radius
    
        def update(self, pos):
            self.x = pos[0]
            self.y = pos[1]
    
        def draw(self, display):
            pygame.draw.circle(display, (255, 0, 0), (int(self.x), int(self.y)), self.radius, 2)
    
    circle = Circle(30)
    
    class Ellipse:
        def __init__(self, centre, rx, ry):
            self.centre = centre
            self.collided = False
            self.rx = rx
            self.ry = ry
            
        def draw(self, display):
            angle = 0
            while angle < 6.28:
                angle += 0.001
                x = self.centre[0] + sin(angle)* self.rx
                y = self.centre[1] + cos(angle)* self.ry
                if self.collided:
                    display.set_at((int(x), int(y)), (255, 0, 0))
                else:
                    display.set_at((int(x), int(y)), (0, 0, 255))
            pygame.draw.circle(D, (0, 255, 0), (int(self.centre[0]), int(self.centre[1])), 5)
    
        def collision(self, circle):
            #angle to the circle
            dx = circle.x - self.centre[0]
            dy = circle.y - self.centre[1]
            angle = atan2(-dy, dx)
            print(angle)
    
            #where the point lies in the ellipse at that angle
            x = sin(angle + 1.5)* self.rx + self.centre[0] 
            y = cos(angle + 1.5)* self.ry + self.centre[1]
            #print(x, y)
    
            #drawing the point just to make sure its working
            # (debugging)
            pygame.draw.circle(D, (0, 255, 0), (int(x), int(y)), 5)
    
            # distance between the point we just
            # calculated and the circle's centre
            distance = ((x-circle.x)**2 + (y-circle.y)**2)**0.5
            #print(distance)
    
            #collision condition
            if distance < circle.radius:
                self.collided = True
            else:
                self.collided = False
            
    ellipse = Ellipse([600, 300], 300, 200)
    
    while True:
        events = pygame.event.get()
        mousePos = pygame.mouse.get_pos()
        for event in events:
            if event.type == pygame.QUIT:
                pygame.quit()
        D.fill((255, 255, 255))
    
        circle.update(mousePos)
        circle.draw(D)
        ellipse.draw(D)
        ellipse.collision(circle)
        
        pygame.display.flip()