如何测试一个点是否在椭圆内?

con*_*mer 1 python pygame collision-detection python-3.x

我正在开发一个 Pygame 项目,地图上有水。如果玩家进入水中,我想减慢玩家的速度。有水的区域呈椭圆形。如果形状是矩形,我可以减慢玩家的速度,但我不希望非水域区域减慢玩家的速度。那么我怎样才能得到玩家应该放慢速度的区域呢?如何控制角色坐标是否在椭圆内?

编辑:我检查了评论中的链接,它对我有用。

Rab*_*d76 5

通过缩放椭圆以显示为圆并以相同的方式缩放点到椭圆中心的距离向量,可以将椭圆和点的碰撞简化为圆和点的碰撞。由于椭圆在 PyGame 中是轴对齐的,因此可以通过按椭圆轴长度的比例缩放其中一个坐标来轻松实现这一点。

pygame.Rect定义椭圆( ) 的外接矩形( ellipse_rect) 并获取半轴 ( a, b):

a = ellipse_rect.width // 2
b = ellipse_rect.height // 2
Run Code Online (Sandbox Code Playgroud)

计算半轴之比

scale_y = a / b
Run Code Online (Sandbox Code Playgroud)

定义一个点 ( test_x, test_y) 并计算该点到椭圆中心 ( cpt_x, cpt_y) 的向量。使用半 x 轴和半 y 轴的比率缩放向量的 y 坐标:

cpt_x, cpt_y = ellipse_rect.center
dx = test_x - cpt_x
dy = (test_y - cpt_y) * scale_y
Run Code Online (Sandbox Code Playgroud)

如果欧氏距离( dx*dx + dy*dy) 的平方小于 x 半轴 ( a*a)的平方,则该点位于椭圆内:

collide = dx*dx + dy*dy <= a*a  
Run Code Online (Sandbox Code Playgroud)

另请参见碰撞和相交 - 点和椭圆


最小的例子:

import pygame

pygame.init()

width, height = 400, 400
window = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()

ellipse_rect = pygame.Rect(0, 0, 200, 100)
ellipse_rect.center = window.get_rect().center

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    a = ellipse_rect.width // 2
    b = ellipse_rect.height // 2
    scale_y = a / b
    cpt_x, cpt_y = ellipse_rect.center
    test_x, test_y = pygame.mouse.get_pos()
    dx = test_x - cpt_x
    dy = (test_y - cpt_y) * scale_y
    collide = dx*dx + dy*dy <= a*a  
            
    window.fill(0)
    
    color = (127, 0, 0) if collide else (0, 127, 0)
    pygame.draw.ellipse(window, color, ellipse_rect)
    if collide:
        pygame.draw.ellipse(window, (255, 255, 255), ellipse_rect, 3)

    pygame.display.flip()

pygame.quit()
exit()
Run Code Online (Sandbox Code Playgroud)