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

How can I test if a point is in an ellipse?

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

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

椭圆与点的碰撞可以简化为圆与点的碰撞,方法是将椭圆缩放为圆,缩放点到椭圆中心的距离向量同样的方式。由于椭圆在 PyGame 中是轴对齐的,这可以很容易地通过按 ellipse 轴长度的比例缩放其中一个坐标来实现。

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

a = ellipse_rect.width // 2
b = ellipse_rect.height // 2

计算半轴的比例

scale_y = a / b

定义一个点(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

如果Euclidean distancedx*dx + dy*dy)的平方小于半x轴(a*a)的平方,则点在椭圆内:

collide = dx*dx + dy*dy <= a*a  

另见 Collision and Intersection - Point and Ellipse


最小示例:

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()