I am working on a Pygame project and there is water on the map. I want to slow down the player if player goes into water. Area where water is has an elliptic shape. I can slow down player if the shape was a rectangle but i don't want the non-water area to slow down the player. So how can i get the area where player is supposed to be slowed down? How to control if character's coordinates are in the ellipse?
Edit: I checked the link in the comments and it worked for me.
The collision of an ellipse and a point can be reduced to the collision of a circle and a point by scaling the ellipse to appear as a circle and scaling the distance vector of the point to the center of the ellipse in the same way. Since the ellipses are axis-aligned in PyGame, this can easily be achieved by scaling one of the coordinates by the ratio of the ellipse axis length.
Define the bounding rectangle (pygame.Rect
) of the ellipse (ellipse_rect
) and get the semi-axis (a
, b
):
a = ellipse_rect.width // 2
b = ellipse_rect.height // 2
Compute the ratio of the semi-axis
scale_y = a / b
Define an point (test_x
, test_y
) and calculate the vector of the point to the center of the ellipse (cpt_x
, cpt_y
). Scale the y-coordinate of the vector with the ratio of semi-x-axis and semi-y-axis:
cpt_x, cpt_y = ellipse_rect.center
dx = test_x - cpt_x
dy = (test_y - cpt_y) * scale_y
The point lies in the ellipse if the square of the Euclidean distance (dx*dx + dy*dy
) is smaller than the square of the semi-x axis (a*a
):
collide = dx*dx + dy*dy <= a*a
See also Collision and Intersection - Point and Ellipse
Minimal example:
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()