Issue Finding Side Of Collision For Circle-rectangle Collision
Solution 1:
You can find the side of the circle, by finding the on the rectangle, which is on the straight line, which is given by the center of the circle and the center of the rectangle.
The point on the rectangle and the circle can be computed by the minimum relation of the offset between the center points and the size of the rectangle.
In the following algorithm, the rectangle is defined by the center point (r_cpt
) and the size (r_size
) and the circle is defined by the center point (c_cpt
) and the radius (c_rad
):
defintersectRectangleCircle(r_cpt, r_size, c_cpt, c_rad):
v2_c_cpt = pygame.math.Vector2(c_cpt)
v2_r_cpt = pygame.math.Vector2(r_cpt)
offset = v2_c_cpt - v2_r_cpt
if offset.x == 0and offset.y == 0:
return [v2_c_cpt, v2_r_cpt]
if offset.x == 0:
ratio = r_size[1] / abs(offset.y)
elif offset.y == 0:
ratio = r_size[0] / abs(offset.x)
else:
ratio = min(r_size[0] / abs(offset.x), r_size[1] / abs(offset.y))
ratio *= 0.5
p1 = v2_r_cpt + (offset * ratio)
offset.scale_to_length(c_rad)
p2 = v2_c_cpt - offset
return [p1, p2]
The direction to the circle is the given by the vector from the center point of the rectangle to the point on the rectangle contour:
isect_pts = intersectRectangleCircle(rect_center, rect_size, circle_center, circle_diameter/2)
dx, dy = isect_pts[0].x - rect_center[0], isect_pts[1].y - rect_center[1]
See the example, (dx
, dy
) is represented by the magenta colored line:
repl.it/@Rabbid76/PyGame-NearestPointOnRectangle
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((500, 500))
defintersectRectangleCircle(r_cpt, r_size, c_cpt, c_rad):
v2_c_cpt = pygame.math.Vector2(c_cpt)
v2_r_cpt = pygame.math.Vector2(r_cpt)
offset = v2_c_cpt - v2_r_cpt
if offset.x == 0and offset.y == 0:
return [v2_c_cpt, v2_r_cpt]
if offset.x == 0:
ratio = r_size[1] / abs(offset.y)
elif offset.y == 0:
ratio = r_size[0] / abs(offset.x)
else:
ratio = min(r_size[0] / abs(offset.x), r_size[1] / abs(offset.y))
ratio *= 0.5
p1 = v2_r_cpt + (offset * ratio)
offset.scale_to_length(c_rad)
p2 = v2_c_cpt - offset
return [p1, p2]
definBetween(p1, p2, px):
v = pygame.math.Vector2(p2) - pygame.math.Vector2(p1)
d = v.length()
if d == 0:
returnFalse
v.normalize_ip()
vx = pygame.math.Vector2(px) - pygame.math.Vector2(p1)
dx = v.dot(vx)
return dx >= 0and dx <= d
done = Falsewhilenot done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
rect_center = screen.get_rect().center
rect_size = screen.get_width() // 5, screen.get_height() // 10
rect = pygame.Rect(rect_center[0] - rect_size[0] // 2, rect_center[1] - rect_size[1] // 2, *rect_size)
circle_center = pygame.mouse.get_pos()
circle_diameter = min(*screen.get_size()) // 5
isect_pts = intersectRectangleCircle(rect_center, rect_size, circle_center, circle_diameter/2)
dx, dy = isect_pts[0].x - rect_center[0], isect_pts[1].y - rect_center[1]
screen.fill((255,255,255))
pygame.draw.rect(screen, (0, 0, 0), rect, 3)
pygame.draw.circle(screen, (0, 0, 0), circle_center, circle_diameter // 2, 3)
pygame.draw.line(screen, (0, 0, 255), rect_center, circle_center, 1)
pygame.draw.line(screen, (255, 0, 255), rect_center, (round(isect_pts[0].x), round(isect_pts[0].y)), 3)
for i inrange(2):
px, py = round(isect_pts[i].x), round(isect_pts[i].y)
col = (255, 0, 0) if inBetween(rect_center, circle_center, (px, py)) else (0, 255, 0)
pygame.draw.line(screen, col, (px-5, py), (px+5, py), 3)
pygame.draw.line(screen, col, (px, py-5), (px, py+5), 3)
pygame.display.flip()
pygame.quit()
quit()
Post a Comment for "Issue Finding Side Of Collision For Circle-rectangle Collision"