From ee0194831ea309bdffba6259e265921e9a514f87 Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 12 Mar 2026 14:46:20 -0400 Subject: [PATCH] reorganized collider code --- collider/__pycache__/system.cpython-311.pyc | Bin 0 -> 8428 bytes collider/__pycache__/types.cpython-311.pyc | Bin 0 -> 8725 bytes collider.py => collider/system.py | 104 +------------------- collider/types.py | 104 ++++++++++++++++++++ main.py | 2 +- rigidbody.py | 3 +- 6 files changed, 108 insertions(+), 105 deletions(-) create mode 100644 collider/__pycache__/system.cpython-311.pyc create mode 100644 collider/__pycache__/types.cpython-311.pyc rename collider.py => collider/system.py (59%) create mode 100644 collider/types.py diff --git a/collider/__pycache__/system.cpython-311.pyc b/collider/__pycache__/system.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca5662772257e56668bdb02ecfcad0422b57b7dc GIT binary patch literal 8428 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 literal 0 HcmV?d00001 diff --git a/collider/__pycache__/types.cpython-311.pyc b/collider/__pycache__/types.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93bf534b29fe9c6d69495b11eed816f9a436d1e9 GIT binary patch literal 8725 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 literal 0 HcmV?d00001 diff --git a/collider.py b/collider/system.py similarity index 59% rename from collider.py rename to collider/system.py index 8c902d9..e688045 100644 --- a/collider.py +++ b/collider/system.py @@ -1,110 +1,8 @@ -from dataclasses import dataclass -from abc import ABC, abstractmethod -from typing import Generator - import pygame as pg -from math import pi +from collider.types import * from transform import Transform -@dataclass -class Face: - begin: pg.Vector2 - end: pg.Vector2 - - @property - def normal(self) -> pg.Vector2: - return (self.end-self.begin).rotate(-90).normalize() - -@dataclass -class ColliderContact: - __slots__ = ["points", "normal", "penetration"] - points: list[pg.Vector2] - normal: pg.Vector2 - penetration: float - -@dataclass(frozen=True) -class PolygonalHull: - _vertices: list[pg.Vector2] - - def get_vertex_at_index(self, key: int) -> pg.Vector2: - return self._vertices[key] - - def get_face_at_index(self, key: int) -> Face: - return Face(self._vertices[key], self._vertices[(key + 1) % len(self._vertices)]) - - def vertices(self) -> Generator[pg.Vector2, None, None]: - for v in self._vertices: - yield v - - def faces(self) -> Generator[Face, None, None]: - for i in range(len(self._vertices)): - yield self.get_face_at_index(i) - - def project(self, axis: pg.Vector2) -> tuple[float, float]: - projections = [v.dot(axis) for v in self._vertices] - return (min(projections), max(projections)) - - -class BaseCollider(ABC): - - @abstractmethod - def moment_of_inertia(self, mass: float) -> float: - pass - -class ConvexCollider(BaseCollider): - - @abstractmethod - def hull(self, transform: Transform) -> PolygonalHull: - pass - -@dataclass -class CircleCollider(BaseCollider): - - radius: float - - def moment_of_inertia(self, mass: float) -> float: - return 0.5 * self.radius ** 2 * mass - -@dataclass -class LineCollider(ConvexCollider): - - length: float - - def hull(self, transform: Transform) -> PolygonalHull: - return PolygonalHull([ - transform.global_position - pg.Vector2(self.length / 2.0, 0).rotate(transform.global_degrees) * transform.global_scale, - transform.global_position + pg.Vector2(self.length / 2.0, 0).rotate(transform.global_degrees) * transform.global_scale - ]) - - def moment_of_inertia(self, mass): - return 1.0 / 12.0 * mass * self.length**2 - - -@dataclass -class RectCollider(ConvexCollider): - - dimensions: tuple[float, float] - - @property - def width(self): - return self.dimensions[0] - - @property - def height(self): - return self.dimensions[1] - - def hull(self, transform: Transform) -> PolygonalHull: - return PolygonalHull([ - transform.global_position - pg.Vector2(self.width / 2.0, self.height / 2.0).rotate(transform.global_degrees) * transform.global_scale, - transform.global_position - pg.Vector2(-self.width / 2.0, self.height / 2.0).rotate(transform.global_degrees) * transform.global_scale, - transform.global_position - pg.Vector2(-self.width / 2.0, -self.height / 2.0).rotate(transform.global_degrees) * transform.global_scale, - transform.global_position - pg.Vector2(self.width / 2.0, -self.height / 2.0).rotate(transform.global_degrees) * transform.global_scale - ]) - - def moment_of_inertia(self, mass: float) -> float: - return (1.0 / 12.0) * mass * (self.width ** 2 + self.height ** 2) - def _interval_overlap(a: tuple[float, float], b: tuple[float, float]) -> float | None: if a[0] <= b[1] and b[0] <= a[1]: return min(a[1], b[1]) - max(a[0], b[0]) diff --git a/collider/types.py b/collider/types.py new file mode 100644 index 0000000..a57d5bd --- /dev/null +++ b/collider/types.py @@ -0,0 +1,104 @@ +from dataclasses import dataclass +from typing import Generator +from abc import ABC, abstractmethod + +import pygame as pg +from transform import Transform + +@dataclass +class Face: + begin: pg.Vector2 + end: pg.Vector2 + + @property + def normal(self) -> pg.Vector2: + return (self.end-self.begin).rotate(-90).normalize() + +@dataclass +class ColliderContact: + __slots__ = ["points", "normal", "penetration"] + points: list[pg.Vector2] + normal: pg.Vector2 + penetration: float + +@dataclass(frozen=True) +class PolygonalHull: + _vertices: list[pg.Vector2] + + def get_vertex_at_index(self, key: int) -> pg.Vector2: + return self._vertices[key] + + def get_face_at_index(self, key: int) -> Face: + return Face(self._vertices[key], self._vertices[(key + 1) % len(self._vertices)]) + + def vertices(self) -> Generator[pg.Vector2, None, None]: + for v in self._vertices: + yield v + + def faces(self) -> Generator[Face, None, None]: + for i in range(len(self._vertices)): + yield self.get_face_at_index(i) + + def project(self, axis: pg.Vector2) -> tuple[float, float]: + projections = [v.dot(axis) for v in self._vertices] + return (min(projections), max(projections)) + + +class BaseCollider(ABC): + + @abstractmethod + def moment_of_inertia(self, mass: float) -> float: + pass + +class ConvexCollider(BaseCollider): + + @abstractmethod + def hull(self, transform: Transform) -> PolygonalHull: + pass + +@dataclass +class CircleCollider(BaseCollider): + + radius: float + + def moment_of_inertia(self, mass: float) -> float: + return 0.5 * self.radius ** 2 * mass + +@dataclass +class LineCollider(ConvexCollider): + + length: float + + def hull(self, transform: Transform) -> PolygonalHull: + return PolygonalHull([ + transform.global_position - pg.Vector2(self.length / 2.0, 0).rotate(transform.global_degrees) * transform.global_scale, + transform.global_position + pg.Vector2(self.length / 2.0, 0).rotate(transform.global_degrees) * transform.global_scale + ]) + + def moment_of_inertia(self, mass): + return 1.0 / 12.0 * mass * self.length**2 + + +@dataclass +class RectCollider(ConvexCollider): + + dimensions: tuple[float, float] + + @property + def width(self): + return self.dimensions[0] + + @property + def height(self): + return self.dimensions[1] + + def hull(self, transform: Transform) -> PolygonalHull: + return PolygonalHull([ + transform.global_position - pg.Vector2(self.width / 2.0, self.height / 2.0).rotate(transform.global_degrees) * transform.global_scale, + transform.global_position - pg.Vector2(-self.width / 2.0, self.height / 2.0).rotate(transform.global_degrees) * transform.global_scale, + transform.global_position - pg.Vector2(-self.width / 2.0, -self.height / 2.0).rotate(transform.global_degrees) * transform.global_scale, + transform.global_position - pg.Vector2(self.width / 2.0, -self.height / 2.0).rotate(transform.global_degrees) * transform.global_scale + ]) + + def moment_of_inertia(self, mass: float) -> float: + return (1.0 / 12.0) * mass * (self.width ** 2 + self.height ** 2) \ No newline at end of file diff --git a/main.py b/main.py index 5bc52a0..ab03300 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,7 @@ import pygame as pg from math import pi from rigidbody import * -from collider import RectCollider +from collider.types import RectCollider from tools import debug diff --git a/rigidbody.py b/rigidbody.py index 06d5427..d70c988 100644 --- a/rigidbody.py +++ b/rigidbody.py @@ -4,7 +4,8 @@ from itertools import combinations import pygame as pg from tools import debug -from collider import * +from collider.system import intersect +from collider.types import * from transform import Transform @dataclass