import pygame from dataclasses import dataclass from scripts.animation import Animation from scripts.tilemap import Tilemap @dataclass class Collisions: top: bool = False right: bool = False bottom: bool = False left: bool = False class PhysicsEntity: def __init__(self, game, e_type: str, pos: tuple[float, float], size: tuple[int, int]): self.game = game self.e_type: str = e_type self.pos: list[float] = list(pos) self.size: tuple[int, int] = size self.velocity: list[float] = [0, 0] self.collisions: Collisions = Collisions() self.speed: int = 3 # Animationen self.action: str = "" self.flip: bool = False self.animation_offset: tuple[int, int] = (-3, -3) self.animation: Animation self.set_action("idle") def update(self, tilemap: Tilemap, movement: tuple[float, float] = (0, 0)) -> None: self.collisions = Collisions() frame_movement: tuple[float, float] = ( (movement[0] + self.velocity[0]) * self.speed, movement[1] + self.velocity[1], ) self.pos[0] += frame_movement[0] entity_rect = self.rect() for recto in tilemap.physics_rects_around(self.pos): if entity_rect.colliderect(recto): if frame_movement[0] > 0: entity_rect.right = recto.left self.collisions.right = True self.game.isJumping = False if frame_movement[0] < 0: entity_rect.left = recto.right self.collisions.left = True self.game.isJumping = False self.pos[0] = entity_rect.x self.pos[1] += frame_movement[1] entity_rect = self.rect() for rectolino in tilemap.physics_rects_around(self.pos): if entity_rect.colliderect(rectolino): if frame_movement[1] > 0: entity_rect.bottom = rectolino.top self.collisions.bottom = True self.game.isJumping = False if frame_movement[1] < 0: entity_rect.top = rectolino.bottom self.collisions.top = True self.pos[1] = entity_rect.y if movement[0] > 0: self.flip = False if movement[0] < 0: self.flip = True if self.collisions.bottom or self.collisions.top: self.velocity[1] = 0 self.velocity[1] = min(5, self.velocity[1] + 0.1) self.animation.update() def render(self, surface: pygame.Surface, offset: tuple[int, int] = (0, 0)) -> None: surface.blit( pygame.transform.flip(self.animation.img(), self.flip, False), ( self.pos[0] - offset[0] + self.animation_offset[0], self.pos[1] - offset[1] + self.animation_offset[1], ), ) def rect(self) -> pygame.Rect: return pygame.Rect(self.pos[0], self.pos[1], self.size[0], self.size[1]) def set_action(self, action: str) -> None: if action != self.action: self.action = action image = self.e_type + "/" + self.action self.animation = self.game.assets[image].copy() class Player(PhysicsEntity): def __init__(self, game, pos: tuple[float, float], size: tuple[int, int]): super().__init__(game, "player", pos, size) self.air_time: int = 0 # Neu! Zählt, wie lange wir fallen/springe def update(self, tilemap: Tilemap, movement: tuple[float, float] = (0, 0)) -> None: super().update(tilemap, movement) self.air_time += 1 if self.collisions.bottom: self.air_time = 0 # Wenn wir länger als 4 Frames in der Luft sind -> Springen! if self.air_time > 4: self.set_action("jump") # Wenn wir nicht in der Luft sind, aber uns bewegen -> Rennen! elif movement[0] != 0: self.set_action("run") # Sonst -> Rumstehen! else: self.set_action("idle")