diff --git a/collider/__pycache__/system.cpython-311.pyc b/collider/__pycache__/system.cpython-311.pyc new file mode 100644 index 0000000..ca56627 Binary files /dev/null and b/collider/__pycache__/system.cpython-311.pyc differ diff --git a/collider/__pycache__/types.cpython-311.pyc b/collider/__pycache__/types.cpython-311.pyc new file mode 100644 index 0000000..93bf534 Binary files /dev/null and b/collider/__pycache__/types.cpython-311.pyc differ 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