Files
silent-fh/src/map.py
T
2026-05-08 18:49:47 +02:00

199 lines
8.0 KiB
Python

import pygame
from src.desk import Desk
from src.settings import DESK_WIDTH, DESK_HEIGHT, tile_size, screen_w, screen_h, color_wall, color_room, color_hall, color_door, color_void, color_text, color_border, color_start
class Map:
def __init__(self):
# Map wird mit "Tiles" (30x30 Feldern aufgebaut
# W=Wall, R=Room, S=Start, H=Hall, D=Door
self.map = [
"WWWWWWWWWWWWWWWWWWWHHSSHHWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"WWWWWWWWWWWWWWWWWWWHHHHHHWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWRRRRRRRRRRRRRRRWWHHHHHHWWRRRRRRRRRRRRRRRWWRRRRRRRRRRRRRRRWW",
"WWWWWWWWWWWWWWWDDWWHHHHHHWWWWWWWWWWWWWWDDWWWWDDWWWWWWWWWWWWWW",
"WWWWWWWWWWWWWWWDDWWHHHHHHWWWWWWWWWWWWWWDDWWWWDDWWWWWWWWWWWWWW",
"WWHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHWW",
"WWHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHWW",
"WWHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDD",
"WWHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDD",
"WWHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHWW",
"WWHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHWW",
"WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
"WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW",
]
# Raumbeschreibung in (Spalte, Zeile, Beschreibung)
# gibt an wo der Raumname auf dem Bildschirm angezeigt wird
self.room_decription = [
(7, 13, "Room 102"),
(32, 13, "Room 103"),
(49, 13, "Room 105")
]
# die Räume als Pixel-Rechtecke, Spalte und Zeile aus der Map * tile_size
# die Reihenfolge ist: x - y - breite - höhe | in Pixel
self.rooms: dict[str, pygame.Rect] = {
"Room 102": pygame.Rect(2 * tile_size, 2 * tile_size, 15 * tile_size, 10 * tile_size),
"Room 103": pygame.Rect(27 * tile_size, 2 * tile_size, 15 * tile_size, 10 * tile_size),
"Room 105": pygame.Rect(44 * tile_size, 2 * tile_size, 15 * tile_size, 10 * tile_size),
}
# soll automatisch einen Tisch ind er MItte des Raumes erstellen
self.desks: dict[str, list[Desk]] = {}
for room_name, room_rect in self.rooms.items():
# berechnet die Mitte des Raumes, zieht die Tischgröße ab, damit er wirklich zentriert ist
center_x = room_rect.centerx - DESK_WIDTH // 2
center_y = room_rect.centery - DESK_HEIGHT // 2
# erstell einen Tisch pro Raum und speichert ihn
self.desks[room_name] = [Desk(center_x, center_y)]
def get_tile(self, column: int, row: int):
# ein check, ob die Position innerhalb der Map liegt
if 0 <= row < len(self.map) and 0 <= column < len(self.map[row]):
# gibt den Buchstaben der Position zurück
return self.map[row][column]
# falls Außerhalb der Map, ein return als Wand
return "W"
def is_accessible(self, column: int, row: int) -> bool:
# gibt True zurück, wenn der Spieler das Tile betreten darf
return self.get_tile(column, row) in ("R", "D", "H", "S")
# Funktion, um die Map zu erstellen
def draw_map(self, surface: pygame.Surface, font: pygame.font.Font, cam_x: int = 0, cam_y: int = 0) -> None:
# Dict, dass jedem Buchstaben eine Farbe zuordnet
color_for = {
"W": color_wall,
"R": color_room,
"H": color_hall,
"D": color_door,
"S": color_start,
}
# äußere Schleife Zeile für Zeile
for row_nr in range(len(self.map)):
# innerer Loop für jedes Zeichen in der Zeile
for column_nr in range(len(self.map[row_nr])):
# holt sich den Buchstaben und speichert ihn in der Variable mark
mark = self.map[row_nr][column_nr]
# sucht die Farbe für den Buchstaben - falls unbekannt -> color_void
color = color_for.get(mark, color_void)
# errechnet die Position des Tiles auf dem Bildschirm mit "column_nr * tile_size", "- cam_x" verschiebt alles mit der Kamera
rect = pygame.Rect(
column_nr * tile_size - cam_x,
row_nr * tile_size - cam_y,
# Tile-Breite
tile_size,
# Tile-Höhe
tile_size,
)
# das Rechteck ind er Farbe zeichnen
pygame.draw.rect(surface, color, rect)
# die Wände sollen einen zusätzlichen Rand haben mit 1 = Wandbreite in Pixel
if mark == "W":
pygame.draw.rect(surface, color_border, rect, 1)
# geht die Beschriftungen durch
for i in range(len(self.room_decription)):
# entpackt das Tupel in 3 Variablen: column, row, text
column, row, text = self.room_decription[i]
# die Tile-Koordinaten in Pixel umrechnen und addieren von 2, damit der Text nicht ganz am Rand klebt
px = column * tile_size - cam_x + 2
py = row * tile_size - cam_y + 2
# Text-Bild mit fon.render()
# True gibt eine glattere Schrift
# blit() fixiert den Text auf dem Bildschirm
surface.blit(font.render(text, True, color_text), (px, py))
# Desks werden gezeichnet
for desk_list in self.desks.values():
for desk in desk_list:
desk.draw(surface, cam_x, cam_y)
# Gibt ein Raum Rechteck zurück - zum Prüfen, ob eine gegebene Position im Raum ist
def get_room_rect(self, column: int, row: int):
# rechnet Tile Koordinaten in Pixel um
pixel_x = column * tile_size
pixel_y = row * tile_size
for room_rect in self.rooms.values():
# collidepoint prüft ob der Pixel-Punkt im Rechteck ist
if room_rect.collidepoint(pixel_x, pixel_y):
return room_rect
# return None, wenn Punkt in keinem Raum liegt (z.B. im Gang)
return None
# Gibt alle Tische im Raum zurück, damit keine Item-Spawns auf Tischen stattfinden
def get_desks_for_room(self, room_rect: pygame.Rect) -> list[Desk]:
for room_name, rect in self.rooms.items():
if rect == room_rect:
return self.desks[room_name]
# kein passender Raum gefunden
return []
# Gibt das Raum-Rechteck zurück, in dem sich der Spieler gerade befindet
# Gilt um zu wissen, ob der Spieler im Raum ist wegen den Item spawns
def get_current_room(self, player_rect: pygame.Rect) -> pygame.Rect:
for room_rect in self.rooms.values():
if room_rect.colliderect(player_rect):
return room_rect
# Spieler ist im Gang
return None
if __name__ == "__main__":
pygame.init()
screen = pygame.display.set_mode((screen_w, screen_h))
font = pygame.font.SysFont("monospace", 26, bold=True)
clock = pygame.time.Clock()
my_map = Map()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill(color_void)
my_map.draw_map(screen, font)
pygame.display.flip()
clock.tick(60)