/
Vibek
/
First_Game
Обзор
Документация
Войти
/
Vibek
/
First_Game
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
utils/collision.py
98 строк
4 KB
Vibek
Оптимизация, иснхронизация хитбоксов
21 июн 2026, 17:09
21 июн 2026, 17:09
bbdda9b
Код
Авторство
О чём код?
import pygame from pygame.math import Vector2 import math def get_obb_corners(center: Vector2, size: tuple[int, int], angle_deg: float) -> list[Vector2]: """Возвращает 4 вершины повёрнутого прямоугольника (мировые координаты).""" half_w, half_h = size[0] / 2, size[1] / 2 rad = math.radians(angle_deg) cos_a, sin_a = math.cos(rad), math.sin(rad) local = [ Vector2(-half_w, -half_h), Vector2(half_w, -half_h), Vector2(half_w, half_h), Vector2(-half_w, half_h) ] return [ center + Vector2(l.x * cos_a - l.y * sin_a, l.x * sin_a + l.y * cos_a) for l in local ] def sat_collision(poly1: list[Vector2], poly2: list[Vector2]) -> bool: """ Универсальная проверка пересечения двух выпуклых полигонов. Работает для: прямоугольник-прямоугольник, треугольник-прямоугольник, и т.д. """ def get_axes(shape): axes = [] for i in range(len(shape)): edge = shape[(i + 1) % len(shape)] - shape[i] axes.append(Vector2(-edge.y, edge.x).normalize()) return axes def project(shape, axis): dots = [v.dot(axis) for v in shape] return min(dots), max(dots) for axis in get_axes(poly1) + get_axes(poly2): min1, max1 = project(poly1, axis) min2, max2 = project(poly2, axis) if max1 < min2 or max2 < min1: return False return True def check_polygon_overlap(poly1: list[Vector2], poly2: list[Vector2]) -> bool: """ Чистая проверка пересечения двух полигонов. Не зависит от игровых моделей, работает только с векторами. """ if len(poly1) < 3 or len(poly2) < 3: return False return sat_collision(poly1, poly2) def point_in_convex_polygon(point: Vector2, corners: list[Vector2]) -> bool: """True, если точка внутри выпуклого полигона (вершины по порядку).""" if len(corners) < 3: return False positive: bool | None = None for i in range(len(corners)): a = corners[i] b = corners[(i + 1) % len(corners)] cross = (b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x) if cross == 0: continue sign = cross > 0 if positive is None: positive = sign elif sign != positive: return False return True def distance_point_to_segment(point: Vector2, a: Vector2, b: Vector2) -> float: """Кратчайшее расстояние от точки до отрезка ab.""" ab = b - a length_sq = ab.length_squared() if length_sq == 0: return point.distance_to(a) t = max(0.0, min(1.0, (point - a).dot(ab) / length_sq)) return point.distance_to(a + ab * t) def circle_overlaps_obb( circle_center: Vector2, radius: float, obb_center: Vector2, size: tuple[int, int], angle_deg: float, ) -> bool: """Проверка пересечения круга (снаряд) с повёрнутым прямоугольником.""" corners = get_obb_corners(obb_center, size, angle_deg) if point_in_convex_polygon(circle_center, corners): return True for i in range(len(corners)): a = corners[i] b = corners[(i + 1) % len(corners)] if distance_point_to_segment(circle_center, a, b) <= radius: return True return False