72 lines
2.1 KiB
Python
72 lines
2.1 KiB
Python
"""Der Koffer: Geometrie und Einlaufbewegung.
|
||
|
||
Bewusst ohne ``pygame``-Abhängigkeit, damit die Regeln testbar bleiben.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
|
||
from . import config
|
||
|
||
|
||
@dataclass
|
||
class Case:
|
||
"""Ein Koffer im Auflieger.
|
||
|
||
``units_w`` / ``units_h`` beschreiben die **aktuelle** Grundfläche in
|
||
Kasten-Einheiten. Eine Drehung tauscht die beiden Werte – es gibt also
|
||
keinen zusätzlichen ``rotated``-Schalter, der mit den Massen kollidieren
|
||
könnte (das war im Altstand eine Fehlerquelle).
|
||
"""
|
||
|
||
units_w: int
|
||
units_h: int
|
||
x: float
|
||
y: float
|
||
color: tuple[int, int, int] = config.CASE_COLORS[0]
|
||
placed: bool = False
|
||
snapped: bool = False
|
||
allow_snap: bool = False
|
||
can_rotate: bool = True
|
||
|
||
# -- Geometrie ------------------------------------------------------
|
||
@property
|
||
def width(self) -> float:
|
||
return self.units_w * config.UNIT_LENGTH
|
||
|
||
@property
|
||
def height(self) -> float:
|
||
return self.units_h * config.UNIT_HEIGHT
|
||
|
||
@property
|
||
def right(self) -> float:
|
||
return self.x + self.width
|
||
|
||
@property
|
||
def bottom(self) -> float:
|
||
return self.y + self.height
|
||
|
||
# -- Bewegung -------------------------------------------------------
|
||
def move(self, dt: float, wall_x: float) -> None:
|
||
"""Bewegt den Koffer nach links, mit Abbremsen kurz vor der Barriere."""
|
||
if self.placed:
|
||
return
|
||
distance = self.x - wall_x
|
||
speed = (
|
||
config.CASE_SPEED_FAST
|
||
if distance > config.FAST_TO_SLOW_DISTANCE
|
||
else config.CASE_SPEED_SLOW
|
||
)
|
||
self.x -= speed * dt
|
||
if self.x <= wall_x + config.SNAP_THRESHOLD:
|
||
self.allow_snap = True
|
||
|
||
def rotate_footprint(self) -> None:
|
||
"""Tauscht Breite und Höhe (nach einer 90°-Drehung)."""
|
||
self.units_w, self.units_h = self.units_h, self.units_w
|
||
|
||
def fits_trailer_height(self) -> bool:
|
||
"""Passt der Koffer nach einer Drehung noch in die Höhe des Aufliegers?"""
|
||
return self.width <= config.TRAILER_HEIGHT
|