From 5dfd84a2f6ee5d59e3bd3e78bd2df99db939e2ad Mon Sep 17 00:00:00 2001 From: Matt Low Date: Sun, 15 Nov 2020 00:24:44 +0400 Subject: [PATCH] Allow rotating shape in SAT Moved rendering of separating axes to function Calculate overlaps instead of binary collision, write min distance to resolve collision --- geom/__init__.py | 4 +++- geom/demos/sat.py | 59 ++++++++++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/geom/__init__.py b/geom/__init__.py index 1237be0..d95d9da 100644 --- a/geom/__init__.py +++ b/geom/__init__.py @@ -7,7 +7,6 @@ HEIGHT = 720 surface = None screen = None - def init(): pygame.display.set_caption("Geom Demo") pygame.mouse.set_visible(False) @@ -37,3 +36,6 @@ def loop(): def get_cursor_pos(): return sub(*pygame.mouse.get_pos(), WIDTH / 2, HEIGHT / 2) + +def get_inputs(): + return pygame.key.get_pressed() diff --git a/geom/demos/sat.py b/geom/demos/sat.py index 5f94946..b09b61f 100644 --- a/geom/demos/sat.py +++ b/geom/demos/sat.py @@ -1,9 +1,10 @@ from ..geom import Rect, Polygon -from .. import WIDTH, HEIGHT, get_cursor_pos +from .. import WIDTH, HEIGHT, get_cursor_pos, get_inputs from ..colors import * from ..math import * from ..draw import * + class SeparatingAxisTheorem: title = "Separating Axis Theorem" @@ -23,9 +24,35 @@ class SeparatingAxisTheorem: (-60, 60) ]) - def render(self, surface): + 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): @@ -46,32 +73,22 @@ class SeparatingAxisTheorem: _max = max(_max, proj) return _min, _max - collisions = [] + 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()) - colliding = max1 > min2 and max2 > min1 - collisions.append(colliding) + overlap = max(min2 - max1, min1 - max2) + overlaps.append(overlap) - 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) + 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 all(collisions) else WHITE, 4) + self.shape2.draw(surface, RED if colliding else WHITE, 4)