Allow rotating shape in SAT

Moved rendering of separating axes to function
Calculate overlaps instead of binary collision, write min distance to
resolve collision
This commit is contained in:
Matt Low 2020-11-15 00:24:44 +04:00
parent 3296d3a582
commit 5dfd84a2f6
2 changed files with 41 additions and 22 deletions

View File

@ -7,7 +7,6 @@ HEIGHT = 720
surface = None surface = None
screen = None screen = None
def init(): def init():
pygame.display.set_caption("Geom Demo") pygame.display.set_caption("Geom Demo")
pygame.mouse.set_visible(False) pygame.mouse.set_visible(False)
@ -37,3 +36,6 @@ def loop():
def get_cursor_pos(): def get_cursor_pos():
return sub(*pygame.mouse.get_pos(), WIDTH / 2, HEIGHT / 2) return sub(*pygame.mouse.get_pos(), WIDTH / 2, HEIGHT / 2)
def get_inputs():
return pygame.key.get_pressed()

View File

@ -1,9 +1,10 @@
from ..geom import Rect, Polygon 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 ..colors import *
from ..math import * from ..math import *
from ..draw import * from ..draw import *
class SeparatingAxisTheorem: class SeparatingAxisTheorem:
title = "Separating Axis Theorem" title = "Separating Axis Theorem"
@ -23,9 +24,35 @@ class SeparatingAxisTheorem:
(-60, 60) (-60, 60)
]) ])
def render(self, surface): def handle_input(self):
self.shape2.set_position(*get_cursor_pos()) 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 = [] normals = []
def add_if_not_exists(normal): def add_if_not_exists(normal):
@ -46,32 +73,22 @@ class SeparatingAxisTheorem:
_max = max(_max, proj) _max = max(_max, proj)
return _min, _max return _min, _max
collisions = [] overlaps = []
for normal in normals: for normal in normals:
min1, max1 = get_min_max(normal, min1, max1 = get_min_max(normal,
self.shape1.get_translated_vertices()) self.shape1.get_translated_vertices())
min2, max2 = get_min_max(normal, min2, max2 = get_min_max(normal,
self.shape2.get_translated_vertices()) self.shape2.get_translated_vertices())
colliding = max1 > min2 and max2 > min1 overlap = max(min2 - max1, min1 - max2)
collisions.append(colliding) overlaps.append(overlap)
offset = scale(*rnormal(*normal), 300) self.draw_axis(surface, normal, overlap < 0, min1, max1, min2, max2)
# 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)
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.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)