def collision_aabb(A, B): '''Retorna uma colisão com o objeto other considerando apenas a caixas de contorno alinhadas ao eixo.''' # Detecta colisão pelas sombras das caixas de contorno rx, ry = B._pos - A._pos shadowx = A._delta_x + B._delta_x - abs(rx) shadowy = A._delta_y + B._delta_y - abs(ry) if shadowx <= 0 or shadowy <= 0: return None # Calcula ponto de colisão x_col = max(A.xmin, B.xmin) + shadowx / 2. y_col = max(A.ymin, B.ymin) + shadowy / 2. pos_col = Vec2(x_col, y_col) # Define sinal dos vetores normais: colisões tipo PONG if shadowx > shadowy: n = Vec2(0, (1 if A.ymin < B.ymin else -1)) delta = shadowy else: n = Vec2((1 if A.xmin < B.xmin else -1), 0) delta = shadowx return Collision(A, B, pos=pos_col, normal=n, delta=delta)
def circle_aabb(A, B): # TODO: implementar direito, está utilizando AABBs r = A.cbb_radius x, y = A._pos Axmin, Axmax = x - r, x + r Aymin, Aymax = y - r, y + r x, y = B._pos dx, dy = B._delta_x, B._delta_y Bxmin, Bxmax = x - dx, x + dx Bymin, Bymax = y - dy, y + dy shadowx = min(Axmax, Bxmax) - max(Axmin, Bxmin) shadowy = min(Aymax, Bymax) - max(Aymin, Bymin) if shadowx < 0 or shadowy < 0: return None # Calcula ponto de colisão x_col = max(A.xmin, B.xmin) + shadowx / 2. y_col = max(A.ymin, B.ymin) + shadowy / 2. pos_col = Vec2(x_col, y_col) # Define sinal dos vetores normais: colisões tipo PONG if shadowx > shadowy: n = Vec2(0, (1 if A.ymin < B.ymin else -1)) else: n = Vec2((1 if A.xmin < B.xmin else -1), 0) return Collision(A, B, pos=pos_col, normal=n)
def circle_collision(A, B): '''Testa a colisão pela distância dos centros''' delta = B.pos - A.pos if delta.norm() < A.radius + B.radius: n = delta.normalized() D = A.radius + B.radius - delta.norm() pos = A.pos + (A.radius - D / 2) * n return Collision(A, B, pos=pos, n=n) else: return None
def collision_circle(A, B): '''Testa a colisão pela distância dos centros''' rA = A.cbb_radius rB = B.cbb_radius delta = B._pos - A._pos if delta.norm() < rA + rB: n = delta.normalize() D = rA + rB - delta.norm() pos = A._pos + (rA - D / 2) * n return Collision(A, B, pos=pos, normal=n, delta=D) else: return None
def get_collision_generic(A, B): '''Retorna uma colisão genérica definido pela CBB dos objetos A e B''' rA = A.cbb_radius rB = B.cbb_radius delta = B._pos - A._pos if delta.norm() < rA + rB: n = delta.normalize() D = rA + rB - delta.norm() pos = A._pos + (rA - D / 2) * n return Collision(A, B, pos=pos, normal=n, delta=D) else: return None
def get_collision_poly(A, B, directions=None): '''Implementa a colisão entre dois polígonos arbitrários''' # Cria a lista de direções a partir das normais do polígono if directions is None: if A.num_normals + B.num_normals < 9: directions = A.get_normals() + B.get_normals() else: directions = DEFAULT_DIRECTIONS # Testa se há superposição de sombras em todas as direções consideradas # e calcula o menor valor para sombra e a direção normal min_shadow = float('inf') norm = None for u in directions: A_coords = [round(dot(pt, u), 6) for pt in A.vertices] B_coords = [round(dot(pt, u), 6) for pt in B.vertices] Amax, Amin = max(A_coords), min(A_coords) Bmax, Bmin = max(B_coords), min(B_coords) minmax, maxmin = min(Amax, Bmax), max(Amin, Bmin) shadow = minmax - maxmin if shadow < 0: return None elif shadow < min_shadow: min_shadow = shadow norm = u # Determina o sentido da normal if dot(A.pos, norm) > dot(B.pos, norm): norm = -norm # Computa o polígono de intersecção e usa o seu centro de massa como ponto # de colisão try: clipped = clip(A.vertices, B.vertices) # não houve superposição (talvez por usar normais aproximadas) except ValueError: return None if area(clipped) == 0: return None col_pt = center_of_mass(clipped) return Collision(A, B, col_pt, norm, min_shadow)
def collision_aabb(A, B): # Detects collision using bounding box shadows. x0, x1 = max(A.xmin, B.xmin), min(A.xmax, B.xmax) y0, y1 = max(A.ymin, B.ymin), min(A.ymax, B.ymax) dx = x1 - x0 dy = y1 - y0 if x1 < x0 or y1 < y0: return None # Chose collision center as the center point in the intersection pos = Vec2((x1 + x0) / 2, (y1 + y0) / 2) # Normal is the direction with smallest penetration if dy < dx: delta = dy normal = Vec2(0, (1 if A.pos.y < B.pos.y else -1)) else: delta = dx normal = Vec2((1 if A.pos.x < B.pos.x else -1), 0) return Collision(A, B, pos=pos, normal=normal, delta=delta)