import pygame as pg import json from scripts.models import Tile NEIGHBOR_OFFSETS = [ (0, 0), (-1, 0), (-1, -1), (-1, 1), (0, 1), (0, -1), (1, 1), (1, 0), (1, -1), ] PHYSICS_TILES = {"grass", "stone"} AUTOTILE_TYPES = {"grass", "stone"} AUTOTILE_MAP = { tuple(sorted([(1, 0), (0, 1)])): 0, tuple(sorted([(1, 0), (0, 1), (-1, 0)])): 1, tuple(sorted([(-1, 0), (0, 1)])): 2, tuple(sorted([(-1, 0), (0, -1), (0, 1)])): 3, tuple(sorted([(-1, 0), (0, -1)])): 4, tuple(sorted([(-1, 0), (0, -1), (1, 0)])): 5, tuple(sorted([(1, 0), (0, -1)])): 6, tuple(sorted([(1, 0), (0, -1), (0, 1)])): 7, tuple(sorted([(1, 0), (-1, 0), (0, 1), (0, -1)])): 8, } class Tilemap: """Eine Map aus Tiles.""" def __init__(self, game, tile_size: int = 16): self.game = game self.tile_size = tile_size 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)) def render(self, surface: pg.Surface, offset: tuple = (0, 0)): for tile in self.offgrid_tiles: surface.blit( self.game.assets[tile["type"]][tile["variant"]], (tile["pos"][0] - offset[0], tile["pos"][1] - offset[1]), ) for x in range( offset[0] // self.tile_size, (offset[0] + surface.get_width()) // self.tile_size + 1, ): for y in range( offset[1] // self.tile_size, (offset[1] + surface.get_height()) // self.tile_size + 1, ): location_key = f"{x};{y}" if location_key in self.tilemap: tile = self.tilemap[location_key] surface.blit( self.game.assets[tile["type"]][tile["variant"]], ( tile["pos"][0] * self.tile_size - offset[0], tile["pos"][1] * self.tile_size - offset[1], ), ) def tiles_around(self, pos: list): tiles = [] tile_location = (int(pos[0] // self.tile_size), int(pos[1] // self.tile_size)) for offset in NEIGHBOR_OFFSETS: check_location = ( str(tile_location[0] + offset[0]) + ";" + str(tile_location[1] + offset[1]) ) if check_location in self.tilemap: tiles.append(self.tilemap[check_location]) return tiles def physics_rects_around(self, pos: list) -> list: # Erzeuge eine leere Liste für die Rechtecke rects = [] # 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 # (nur diese Tiles sollen kollidieren) if tile["type"] in PHYSICS_TILES: # Rechne die Tile-Position in Pixel-Koordinaten um x_pixel = tile["pos"][0] * self.tile_size y_pixel = tile["pos"][1] * self.tile_size # Erzeuge ein pygame.Rect mit: # - x_pixel # - y_pixel # - Breite = self.tile_size # - Höhe = self.tile_size rect = pg.Rect(x_pixel, y_pixel, self.tile_size, self.tile_size) # Füge das Rechteck der Liste rects hinzu rects.append(rect) # Gib die Liste der Rechtecke zurück return rects def autotile(self): for loc in self.tilemap: tile = self.tilemap[loc] neighbors = set() for shift in [(1, 0), (-1, 0), (0, -1), (0, 1)]: check_loc = ( str(tile["pos"][0] + shift[0]) + ";" + str(tile["pos"][1] + shift[1]) ) if check_loc in self.tilemap: if self.tilemap[check_loc]["type"] == tile["type"]: neighbors.add(shift) neighbors = tuple(sorted(neighbors)) if (tile["type"] in AUTOTILE_TYPES) and (neighbors in AUTOTILE_MAP): tile["variant"] = AUTOTILE_MAP[neighbors] def save(self, path: str) -> None: data = { "tilemap": {k: tile.to_dict() for k, tile in self.tilemap.items()}, "tile_size": self.tile_size, "offgrid": [tile.to_dict() for tile in self.offgrid_tiles], } with open(path, "w") as f: json.dump(data, f) def load(self, path: str): """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))