def aabb_poly(A, B, collision_class=Collision): if shadow_x(A, B) < 0 or shadow_y(A, B) < 0: return None A_poly = Rectangle(A.rect_coords) col = collision_poly(A_poly, B) if col is not None: return collision_class(A, B, pos=col.pos, normal=col.normal, delta=col.delta) else: return None
def circle_aabb(A, B): '''Reutiliza a lógica de Circle/Poly para realizar a colisão com AABBs''' if shadow_x(A, B) < 0 or shadow_y(A, B) < 0: return None B_poly = Rectangle(bbox=B.bbox) col = circle_poly(A, B_poly) if col is not None: return Collision(A, B, pos=col.pos, normal=col.normal, delta=col.delta) else: return None
def aabb_poly(A, B): '''Implementa a colisão entre um polígono arbitrário e uma caixa AABB''' if shadow_x(A, B) < 0 or shadow_y(A, B) < 0: return None A_poly = Rectangle(bbox=A.bbox) col = collision_poly(A_poly, B) if col is not None: return Collision(A, B, pos=col.pos, normal=col.normal, delta=col.delta) else: return None
def circle_poly(A, B): '''Implementa a colisão entre um círculo arbitrário um polígono. A normal resultante sempre sai do círculo na direção do polígono. ''' # Verifica as AABB if shadow_x(A, B) < 0 or shadow_y(A, B) < 0: return None # Procura o ponto mais próximo de B vertices = B.vertices N = len(vertices) center = A.pos normals = [(i, v - center, v) for i, v in enumerate(vertices)] idx, _, pos = min(normals, key=lambda x: x[1].norm()) # A menor distância para o centro pode ser do tipo vértice-ponto ou # aresta-ponto. Assumimos o vértice inicialmente. distance = (pos - center).norm() # Agora verificamos cada face P0 = pos P = vertices[(idx - 1) % N] v = center - P u = P0 - P L = u.norm() delta = v.cross(u) / L # Verifica se o ponto mais próximo se encontra no segmento if delta < distance and u.dot(v) < L**2: pos = P + (u.dot(v) / L**2) * u distance = delta # Mesmo teste para a face do ponto posterior P = vertices[(idx + 1) % N] v = center - P u = P0 - P L = u.norm() delta = -v.cross(u) / L if delta < distance and u.dot(v) < L ** 2: pos = P + (u.dot(v) / L ** 2) * u distance = delta # Verificamos se houve colisão ou não na direção esperada delta = A.radius - distance normal = (pos - center).normalized() if delta > 0: return Collision(A, B, pos=pos, normal=normal, delta=delta) else: return None
def circle_poly(A, B, collision_class=Collision): if shadow_x(A, B) < 0 or shadow_y(A, B) < 0: return None # Searches for the nearest point to B vertices = B.vertices center = A.pos normals = [(i, v - center, v) for i, v in enumerate(vertices)] idx, _, pos = min(normals, key=lambda x: x[1].norm()) # The smaller distance to the center can be vertex-center or side-center. # We need to detect this. separation = (pos - center).norm() # Verify each face P0 = pos N = len(vertices) for idx in [(idx - 1) % N, (idx + 1) % N]: P = vertices[idx] v = center - P u = P0 - P L = u.norm() distance = abs(v.cross(u) / L) # Verify if closest point is inside segment if distance < separation and u.dot(v) < L ** 2: pos = P + (u.dot(v) / L ** 2) * u separation = distance # Verify if there is collision in the direction of smaller separation delta = A.radius - separation normal = (pos - center).normalize() if delta > 0: return collision_class(A, B, pos=pos, normal=normal, delta=delta) else: return None
def circle_poly(A, B, collision_class=Collision): if shadow_x(A, B) < 0 or shadow_y(A, B) < 0: return None # Searches for the nearest point to B vertices = B.vertices center = A.pos normals = [(i, v - center, v) for i, v in enumerate(vertices)] idx, _, pos = min(normals, key=lambda x: x[1].norm()) # The smaller distance to the center can be vertex-center or side-center. # We need to detect this. separation = (pos - center).norm() # Verify each face P0 = pos N = len(vertices) for idx in [(idx - 1) % N, (idx + 1) % N]: P = vertices[idx] v = center - P u = P0 - P L = u.norm() distance = abs(v.cross(u) / L) # Verify if closest point is inside segment if distance < separation and u.dot(v) < L**2: pos = P + (u.dot(v) / L**2) * u separation = distance # Verify if there is collision in the direction of smaller separation delta = A.radius - separation normal = (pos - center).normalize() if delta > 0: return collision_class(A, B, pos=pos, normal=normal, delta=delta) else: return None