Matt Low
5dfd84a2f6
Moved rendering of separating axes to function Calculate overlaps instead of binary collision, write min distance to resolve collision
95 lines
2.8 KiB
Python
95 lines
2.8 KiB
Python
from ..geom import Rect, Polygon
|
|
from .. import WIDTH, HEIGHT, get_cursor_pos, get_inputs
|
|
from ..colors import *
|
|
from ..math import *
|
|
from ..draw import *
|
|
|
|
|
|
class SeparatingAxisTheorem:
|
|
|
|
title = "Separating Axis Theorem"
|
|
|
|
def __init__(self):
|
|
self.shape1 = Polygon(0, 0, [
|
|
(0, 60),
|
|
(60, 0),
|
|
(0, -60),
|
|
(-60, 0)
|
|
])
|
|
|
|
self.shape2 = Polygon(*get_cursor_pos(), [
|
|
(60, 60),
|
|
(60, -60),
|
|
(-60, -60),
|
|
(-60, 60)
|
|
])
|
|
|
|
def handle_input(self):
|
|
self.shape2.set_position(*get_cursor_pos())
|
|
|
|
inputs = get_inputs()
|
|
if inputs[pygame.K_q]:
|
|
self.shape2.rotate((1/60) * -90)
|
|
if inputs[pygame.K_e]:
|
|
self.shape2.rotate((1/60) * 90)
|
|
|
|
def draw_axis(self, surface, normal, colliding, min1, max1, min2, max2):
|
|
offset = scale(*rnormal(*normal), 300)
|
|
|
|
# axis
|
|
line(surface, WHITE,
|
|
add(*scale(*reverse(*normal), 1000), *offset),
|
|
add(*scale(*normal, 1000), *offset))
|
|
|
|
# shape 1
|
|
line(surface, YELLOW if not colliding else RED,
|
|
add(*scale(*normal, min1), *offset),
|
|
add(*scale(*normal, max1), *offset), 5)
|
|
# shape 2
|
|
line(surface, YELLOW if not colliding else RED,
|
|
add(*scale(*normal, min2), *offset),
|
|
add(*scale(*normal, max2), *offset), 5)
|
|
|
|
def render(self, surface):
|
|
self.handle_input()
|
|
|
|
normals = []
|
|
|
|
def add_if_not_exists(normal):
|
|
for existing in normals:
|
|
if is_equal(*existing, *normal):
|
|
return
|
|
normals.append(normal)
|
|
|
|
for normal in self.shape1.get_normals() + self.shape2.get_normals():
|
|
add_if_not_exists(normal)
|
|
|
|
def get_min_max(normal, vertices):
|
|
_min = float('inf')
|
|
_max = float('-inf')
|
|
for vertex in vertices:
|
|
proj = dot(*normal, *vertex)
|
|
_min = min(_min, proj)
|
|
_max = max(_max, proj)
|
|
return _min, _max
|
|
|
|
overlaps = []
|
|
for normal in normals:
|
|
min1, max1 = get_min_max(normal,
|
|
self.shape1.get_translated_vertices())
|
|
min2, max2 = get_min_max(normal,
|
|
self.shape2.get_translated_vertices())
|
|
|
|
overlap = max(min2 - max1, min1 - max2)
|
|
overlaps.append(overlap)
|
|
|
|
self.draw_axis(surface, normal, overlap < 0, min1, max1, min2, max2)
|
|
|
|
colliding = all(overlap < 0 for overlap in overlaps)
|
|
if colliding:
|
|
text_screen(surface, WHITE, (10, HEIGHT - 20),
|
|
f"Min Distance to Resolve: {max(overlaps)}")
|
|
|
|
self.shape1.draw(surface, YELLOW, 4)
|
|
self.shape2.draw(surface, RED if colliding else WHITE, 4)
|