From 9e0068e926bb6d7b42d2d215c3b23c6fa3719ec0 Mon Sep 17 00:00:00 2001 From: binaerverkehr <65082683+binaerverkehr@users.noreply.github.com> Date: Mon, 11 May 2026 10:11:09 +0200 Subject: [PATCH 1/5] - Lade map.json innerhalb von try-except - test-Funktion entfernt --- game.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/game.py b/game.py index d368f47..4e89c98 100644 --- a/game.py +++ b/game.py @@ -44,15 +44,13 @@ class Game: self.player = Player(self, (50, 50), (8, 15)) self.tilemap = Tilemap(self, 16) - self.tilemap.load("map.json") + try: + self.tilemap.load("map.json") + except FileNotFoundError: + pass self.clouds = Clouds(self.assets["clouds"], count=16) self.isJumping = False self.scroll = [0, 0] - self.test: dict = {"dsa"} - - def testolino(self): - print(self.test) - print(type(self.test)) def run(self): while self.running: -- 2.45.2 From dc5239aa4c65773ce1d7994a141cc7b9f4a09e3f Mon Sep 17 00:00:00 2001 From: binaerverkehr <65082683+binaerverkehr@users.noreply.github.com> Date: Mon, 11 May 2026 10:11:52 +0200 Subject: [PATCH 2/5] fix: Falsch geschriebene Variable korrigiert --- scripts/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/models.py b/scripts/models.py index 101b919..4ce034e 100644 --- a/scripts/models.py +++ b/scripts/models.py @@ -9,14 +9,14 @@ class Tile: def grid_key(self) -> str: """Erzeugt den String-Key für die Tilemap.""" - return f"{self.pos[0]};{self.post[1]}" - + return f"{self.pos[0]};{self.pos[1]}" + def to_dict(self) -> dict: """Konvertiert zurück in ein Dict (für JSON-Speicherung).""" return { 'type': self.type, 'variant': self.variant, - 'pos': list(self.post) + 'pos': list(self.pos) } @staticmethod -- 2.45.2 From da973dd968a2ba3a3d2f54dc9a58cbd1fcf915fb Mon Sep 17 00:00:00 2001 From: binaerverkehr <65082683+binaerverkehr@users.noreply.github.com> Date: Mon, 11 May 2026 10:19:31 +0200 Subject: [PATCH 3/5] fix: Save/Load Funktionen korrigiert. --- scripts/tilemap.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/scripts/tilemap.py b/scripts/tilemap.py index ad7d0a0..aca209a 100644 --- a/scripts/tilemap.py +++ b/scripts/tilemap.py @@ -1,6 +1,5 @@ import pygame as pg import json -from scripts.models import Tile NEIGHBOR_OFFSETS = [ (0, 0), @@ -37,8 +36,16 @@ class Tilemap: self.tilemap = {} self.offgrid_tiles = [] for i in range(10): - self.tilemap[str(3 + i) + ";10"] = Tile("grass", 1, (3 + i, 10)) - self.tilemap["10;" + str(5 + i)] = Tile("stone", 1, (10, i + 5)) + self.tilemap[str(3 + i) + ";10"] = { + "type": "grass", + "variant": 1, + "pos": (3 + i, 10), + } + self.tilemap["10;" + str(5 + i)] = { + "type": "stone", + "variant": 1, + "pos": (10, i + 5), + } def render(self, surface: pg.Surface, offset: tuple = (0, 0)): for tile in self.offgrid_tiles: @@ -127,27 +134,21 @@ class Tilemap: tile["variant"] = AUTOTILE_MAP[neighbors] def save(self, path: str) -> None: - data = { - "tilemap": {k: tile.to_dict() for k, tile in self.tilemap.items()}, + "tilemap": self.tilemap, "tile_size": self.tile_size, - "offgrid": [tile.to_dict() for tile in self.offgrid_tiles], + "offgrid": self.offgrid_tiles, } with open(path, "w") as f: json.dump(data, f) - def load(self, path: str): + def load(self, path: str) -> None: """Lädt die gespeicherte Tilemap.""" with open(path, "r") as f: map_data: dict = json.load(f) - self.tilemap: dict[str:Tile] = {} - self.offgrid_tiles: list[Tile] = [] - - for key, data in map_data.items(): - self.tilemap[key] = Tile.from_dict(data) - - for tile in map_data["offgrid"]: - self.offgrid_tiles.append(Tile.from_dict(tile)) + self.tilemap: dict[str, dict] = map_data["tilemap"] + self.tile_size: int = map_data["tile_size"] + self.offgrid_tiles: list[dict] = map_data["offgrid"] -- 2.45.2 From d796b47c464fe4851698faba35db1e119311d7bb Mon Sep 17 00:00:00 2001 From: binaerverkehr <65082683+binaerverkehr@users.noreply.github.com> Date: Mon, 11 May 2026 10:37:28 +0200 Subject: [PATCH 4/5] feat: Collisions Dataclass eingefuehrt und in PhysicsEntity verwendet - Neue @dataclass Collisions mit Feldern top/right/bottom/left - collisions-Dict in PhysicsEntity durch Collisions-Instanz ersetzt - Attribut-Zugriff (collisions.top) statt Dict-Indexierung - Typisierung von Feldern und Methoden in PhysicsEntity und Player --- scripts/entities.py | 61 ++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/scripts/entities.py b/scripts/entities.py index 42be0eb..5f71cb9 100644 --- a/scripts/entities.py +++ b/scripts/entities.py @@ -1,26 +1,37 @@ 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, pos: tuple, size): + def __init__(self, game, e_type: str, pos: tuple[float, float], size: tuple[int, int]): self.game = game - self.e_type = e_type - self.pos = list(pos) - self.size = size - self.velocity = [0, 0] - self.collisions = {"top": False, "bottom": False, "left": False, "right": False} - self.speed = 3 + 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 = "" - self.flip = False - self.animation_offset = (-3, -3) + 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 = (0, 0)): - self.collisions = {"top": False, "bottom": False, "left": False, "right": False} - frame_movement = ( + 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], ) @@ -31,12 +42,12 @@ class PhysicsEntity: if entity_rect.colliderect(recto): if frame_movement[0] > 0: entity_rect.right = recto.left - self.collisions["right"] = True + self.collisions.right = True self.game.isJumping = False if frame_movement[0] < 0: entity_rect.left = recto.right - self.collisions["left"] = True + self.collisions.left = True self.game.isJumping = False self.pos[0] = entity_rect.x @@ -48,12 +59,12 @@ class PhysicsEntity: if entity_rect.colliderect(rectolino): if frame_movement[1] > 0: entity_rect.bottom = rectolino.top - self.collisions["bottom"] = True + self.collisions.bottom = True self.game.isJumping = False if frame_movement[1] < 0: entity_rect.top = rectolino.bottom - self.collisions["top"] = True + self.collisions.top = True self.pos[1] = entity_rect.y @@ -62,14 +73,14 @@ class PhysicsEntity: if movement[0] < 0: self.flip = True - if self.collisions["bottom"] or self.collisions["top"]: + 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 = (0, 0)): + def render(self, surface: pygame.Surface, offset: tuple[int, int] = (0, 0)) -> None: surface.blit( pygame.transform.flip(self.animation.img(), self.flip, False), ( @@ -78,10 +89,10 @@ class PhysicsEntity: ), ) - def rect(self): + 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): + def set_action(self, action: str) -> None: if action != self.action: self.action = action image = self.e_type + "/" + self.action @@ -89,16 +100,16 @@ class PhysicsEntity: class Player(PhysicsEntity): - def __init__(self, game, pos, size): + def __init__(self, game, pos: tuple[float, float], size: tuple[int, int]): super().__init__(game, "player", pos, size) - self.air_time = 0 # Neu! Zählt, wie lange wir fallen/springe + self.air_time: int = 0 # Neu! Zählt, wie lange wir fallen/springe - def update(self, tilemap, movement=(0, 0)): + def update(self, tilemap: Tilemap, movement: tuple[float, float] = (0, 0)) -> None: super().update(tilemap, movement) self.air_time += 1 - if self.collisions["bottom"]: + 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: -- 2.45.2 From 4449656a696fa6c59ae4d1036a4cf19baad2f1b2 Mon Sep 17 00:00:00 2001 From: binaerverkehr <65082683+binaerverkehr@users.noreply.github.com> Date: Mon, 11 May 2026 10:37:37 +0200 Subject: [PATCH 5/5] refactor: Typisierung in Hauptdateien und Skripten ergaenzt - Felder und Methoden in Game und Editor typisiert - Tilemap: Felder, render, tiles_around, physics_rects_around, autotile - Animation: Konstruktor-Parameter, Felder, copy und update - Clouds: Cloud und Clouds vollstaendig typisiert - utils: load_image und load_images mit Rueckgabe-Typ --- editor.py | 42 ++++++++++++++++++------------------- game.py | 26 +++++++++++------------ scripts/animation.py | 18 ++++++++-------- scripts/clouds.py | 49 ++++++++++++++++++++------------------------ scripts/tilemap.py | 18 ++++++++-------- scripts/utils.py | 12 +++++++---- 6 files changed, 83 insertions(+), 82 deletions(-) diff --git a/editor.py b/editor.py index 85dbf7b..3adf043 100644 --- a/editor.py +++ b/editor.py @@ -3,7 +3,7 @@ import sys from scripts.tilemap import Tilemap from scripts.utils import load_images -RENDER_SCALE = 2.0 +RENDER_SCALE: float = 2.0 class better_list(list): @@ -16,45 +16,45 @@ class Editor: pygame.init() pygame.display.set_caption("Editor") - self.screen = pygame.display.set_mode((640, 480)) - self.display = pygame.Surface((320, 240)) + self.screen: pygame.Surface = pygame.display.set_mode((640, 480)) + self.display: pygame.Surface = pygame.Surface((320, 240)) - self.clock = pygame.time.Clock() - self.running = True + self.clock: pygame.time.Clock = pygame.time.Clock() + self.running: bool = True - self.collision_area = pygame.Rect(50, 50, 300, 50) - self.movement = [False, False, False, False] + self.collision_area: pygame.Rect = pygame.Rect(50, 50, 300, 50) + self.movement: list[bool] = [False, False, False, False] - self.assets = { + self.assets: dict[str, list[pygame.Surface]] = { "decor": load_images("tiles/decor"), "grass": load_images("tiles/grass"), "large_decor": load_images("tiles/large_decor"), "stone": load_images("tiles/stone"), } - self.tilemap = Tilemap(self, 16) + self.tilemap: Tilemap = Tilemap(self, 16) try: self.tilemap.load("map.json") except FileNotFoundError: pass - self.isJumping = False - self.scroll = [0, 0] - self.tile_list = better_list(self.assets) - self.tile_group = 0 - self.tile_variant = 0 + self.isJumping: bool = False + self.scroll: list[float] = [0, 0] + self.tile_list: better_list = better_list(self.assets) + self.tile_group: int = 0 + self.tile_variant: int = 0 - self.clicking = False - self.right_clicking = False - self.shifting = False + self.clicking: bool = False + self.right_clicking: bool = False + self.shifting: bool = False - self.sekunde = 60 - self.zaehler = 0 + self.sekunde: int = 60 + self.zaehler: int = 0 - self.on_grid = True + self.on_grid: bool = True - def run(self): + def run(self) -> None: while self.running: self.display.fill((0, 0, 0)) diff --git a/game.py b/game.py index 4e89c98..56eb25a 100644 --- a/game.py +++ b/game.py @@ -13,16 +13,16 @@ class Game: pygame.init() pygame.display.set_caption("Jump and run spiel") - self.screen = pygame.display.set_mode((640, 480)) - self.display = pygame.Surface((320, 240)) + self.screen: pygame.Surface = pygame.display.set_mode((640, 480)) + self.display: pygame.Surface = pygame.Surface((320, 240)) - self.clock = pygame.time.Clock() - self.running = True + self.clock: pygame.time.Clock = pygame.time.Clock() + self.running: bool = True - self.collision_area = pygame.Rect(50, 50, 300, 50) - self.movement = [False, False] + self.collision_area: pygame.Rect = pygame.Rect(50, 50, 300, 50) + self.movement: list[bool] = [False, False] - self.assets = { + self.assets: dict = { # Andere Dinge "background": load_image("background.png"), "decor": load_images("tiles/decor"), @@ -41,18 +41,18 @@ class Game: "player/slide": Animation(load_images("entities/player/slide")), "player/wall_slide": Animation(load_images("entities/player/wall_slide")), } - self.player = Player(self, (50, 50), (8, 15)) + self.player: Player = Player(self, (50, 50), (8, 15)) - self.tilemap = Tilemap(self, 16) + self.tilemap: Tilemap = Tilemap(self, 16) try: self.tilemap.load("map.json") except FileNotFoundError: pass - self.clouds = Clouds(self.assets["clouds"], count=16) - self.isJumping = False - self.scroll = [0, 0] + self.clouds: Clouds = Clouds(self.assets["clouds"], count=16) + self.isJumping: bool = False + self.scroll: list[float] = [0, 0] - def run(self): + def run(self) -> None: while self.running: self.display.blit(self.assets["background"], (0, 0)) diff --git a/scripts/animation.py b/scripts/animation.py index 5768c43..5686ac8 100644 --- a/scripts/animation.py +++ b/scripts/animation.py @@ -1,5 +1,5 @@ class Animation: - def __init__(self, images, image_duration=5, loop=True): + def __init__(self, images: list, image_duration: int = 5, loop: bool = True): """ Initialisiert eine Animation mit einer Liste von Bildern. @@ -11,13 +11,13 @@ class Animation: - done startet bei False """ # TODO: Implementieren - self.images = images - self.image_duration = image_duration - self.loop = loop - self.frame = 0 - self.done = False + self.images: list = images + self.image_duration: int = image_duration + self.loop: bool = loop + self.frame: int = 0 + self.done: bool = False - def copy(self): + def copy(self) -> "Animation": """ Erstellt eine Kopie der Animation. @@ -29,7 +29,8 @@ class Animation: # TODO: Implementieren copy_animation = Animation(self.images, self.image_duration, self.loop) return copy_animation - def update(self): + + def update(self) -> None: """ Aktualisiert die Animation um einen Frame weiter. @@ -50,6 +51,7 @@ class Animation: self.frame = min(self.frame + 1, len(self.images) * self.image_duration -1) if self.frame >= self.image_duration * (len(self.images) - 1): self.done = True + def img(self): """ Gibt das aktuelle Bild der Animation zurück. diff --git a/scripts/clouds.py b/scripts/clouds.py index eb16596..a130fd5 100644 --- a/scripts/clouds.py +++ b/scripts/clouds.py @@ -1,45 +1,40 @@ import pygame import random -class Cloud: - def __init__(self, pos:tuple, img, speed:float, depth): - self.pos = list(pos) - self.image = img - self.speed = speed - self.depth = depth - - def update(self): + +class Cloud: + def __init__(self, pos: tuple[float, float], img: pygame.Surface, speed: float, depth: float): + self.pos: list[float] = list(pos) + self.image: pygame.Surface = img + self.speed: float = speed + self.depth: float = depth + + def update(self) -> None: self.pos[0] += self.speed - def render(self, surface:pygame.Surface,offset:tuple=(0,0)): + + def render(self, surface: pygame.Surface, offset: tuple[int, int] = (0, 0)) -> None: render_pos = (self.pos[0] - offset[0] * self.depth, self.pos[1] - offset[1] * self.depth) - - surface.blit(self.image, - (render_pos[0] % (surface.get_width() + self.image.get_width()) - self.image.get_width(), + + surface.blit(self.image, + (render_pos[0] % (surface.get_width() + self.image.get_width()) - self.image.get_width(), render_pos[1] % (surface.get_height() + self.image.get_height()) - self.image.get_height()) ) + + class Clouds: - def __init__(self, cloud_images, count=16): - self.clouds = [] + def __init__(self, cloud_images: list[pygame.Surface], count: int = 16): + self.clouds: list[Cloud] = [] for _ in range(count): self.clouds.append(Cloud((random.random() * 99999, random.random() * 99999), random.choice(cloud_images), - (random.random() * 0.05 + 0.05) * 1, + (random.random() * 0.05 + 0.05) * 1, random.random() * 0.6 + 0.2)) self.clouds.sort(key=lambda x: x.depth) - """ - self.clouds = [] - # Erstelle die Wolken mit zufälligen Eigenschaften - for i in range(count): - self.clouds.append(Cloud((random.random() * 99999, random.random() * 99999), - random.choice(cloud_images), - random.random() * 0.05 + 0.05, - random.random() * 0.6 + 0.2) - ) - self.clouds.sort(key=lambda x: x.depth)""" - def update(self): + def update(self) -> None: for cloud in self.clouds: cloud.update() - def render(self, surface:pygame.Surface, offset:tuple=(0,0)): + + def render(self, surface: pygame.Surface, offset: tuple[int, int] = (0, 0)) -> None: for cloud in self.clouds: cloud.render(surface, offset) \ No newline at end of file diff --git a/scripts/tilemap.py b/scripts/tilemap.py index aca209a..9b35f9d 100644 --- a/scripts/tilemap.py +++ b/scripts/tilemap.py @@ -32,9 +32,9 @@ class Tilemap: def __init__(self, game, tile_size: int = 16): self.game = game - self.tile_size = tile_size - self.tilemap = {} - self.offgrid_tiles = [] + self.tile_size: int = tile_size + self.tilemap: dict[str, dict] = {} + self.offgrid_tiles: list[dict] = [] for i in range(10): self.tilemap[str(3 + i) + ";10"] = { "type": "grass", @@ -47,7 +47,7 @@ class Tilemap: "pos": (10, i + 5), } - def render(self, surface: pg.Surface, offset: tuple = (0, 0)): + def render(self, surface: pg.Surface, offset: tuple[int, int] = (0, 0)) -> None: for tile in self.offgrid_tiles: surface.blit( self.game.assets[tile["type"]][tile["variant"]], @@ -72,8 +72,8 @@ class Tilemap: ), ) - def tiles_around(self, pos: list): - tiles = [] + def tiles_around(self, pos: list[float]) -> list[dict]: + tiles: list[dict] = [] tile_location = (int(pos[0] // self.tile_size), int(pos[1] // self.tile_size)) for offset in NEIGHBOR_OFFSETS: check_location = ( @@ -86,9 +86,9 @@ class Tilemap: return tiles - def physics_rects_around(self, pos: list) -> list: + def physics_rects_around(self, pos: list[float]) -> list[pg.Rect]: # Erzeuge eine leere Liste für die Rechtecke - rects = [] + rects: list[pg.Rect] = [] # Durchlaufe alle Tiles aus der Umgebung (tiles_around) for tile in self.tiles_around(pos): # Prüfe, ob der Tile-Typ in PHYSICS_TILES enthalten ist @@ -110,7 +110,7 @@ class Tilemap: # Gib die Liste der Rechtecke zurück return rects - def autotile(self): + def autotile(self) -> None: for loc in self.tilemap: tile = self.tilemap[loc] diff --git a/scripts/utils.py b/scripts/utils.py index 6d1f994..5f49120 100644 --- a/scripts/utils.py +++ b/scripts/utils.py @@ -1,13 +1,17 @@ import pygame import os -BASE_IMG_PATH = 'data/images/' -def load_image(path): + +BASE_IMG_PATH: str = 'data/images/' + + +def load_image(path: str) -> pygame.Surface: img = pygame.image.load(BASE_IMG_PATH + path).convert() img.set_colorkey((0, 0, 0)) return img -def load_images(path): - images = [] + +def load_images(path: str) -> list[pygame.Surface]: + images: list[pygame.Surface] = [] for img_name in sorted(os.listdir(BASE_IMG_PATH + path)): images.append(load_image(path + '/' + img_name)) return images -- 2.45.2