import pygame from spiel.game import Game from spiel.compute import rot_3D, project_ortho class CubeGame(Game): """Ein interaktiver 3D-Würfel-Spiel basierend auf der MatrixMania-Aufgabenstellung.""" def __init__(self) -> None: super().__init__( title="MatrixMania - Rotierender Würfel", fps=60, size=(800, 600) ) # Die 8 Eckpunkte des Würfels laut Aufgabenstellung (Mittelpunkt im Ursprung) self.vertices = [ [-1, -1, -1], [1, -1, -1], [1, 1, -1], [-1, 1, -1], [-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1] ] # Die 12 Kanten des Würfels (verbinden jeweils zwei Indizes) self.edges = [ (0, 1), (1, 2), (2, 3), (3, 0), # Hinteres Quadrat (4, 5), (5, 6), (6, 7), (7, 4), # Vorderes Quadrat (0, 4), (1, 5), (2, 6), (3, 7) # Verbindungskanten ] # Startwinkel für x- und y-Achse sind 0 self.angle_x = 0.0 self.angle_y = 0.0 def handle_event(self, event: pygame.event.Event) -> bool: """Verarbeitet Events (z. B. Schließen des Fensters, ESC oder Mausbewegung).""" if event.type == pygame.QUIT: return False if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: return False # Maussteuerung: Wenn die linke Maustaste gedrückt gehalten wird, Würfel drehen if event.type == pygame.MOUSEMOTION: # Prüfen, ob die linke Maustaste (Index 0) gedrückt gehalten wird if pygame.mouse.get_pressed()[0]: dx, dy = event.rel # Relativer Maus-Versatz seit dem letzten Event self.angle_y += dx * 0.01 self.angle_x += dy * 0.01 return True def update_game(self) -> bool: """Aktualisiert das Spiel (hier keine automatische Drehung mehr nötig).""" return True def draw_game(self) -> None: """Berechnet die Rotationen, projiziert orthogonal und zeichnet den Würfel.""" if self.screen is None: return # Hintergrund füllen (dunkles Blau/Grau) self.screen.fill((20, 20, 30)) center_x = self.size[0] // 2 center_y = self.size[1] // 2 projected_points = [] scale_factor = 100.0 # Skalierungsfaktor, damit der Würfel groß genug ist for vertex in self.vertices: # 1. Rotationsmatrix für x-Achse generieren und anwenden rx_mat = rot_3D(self.angle_x, 'x') v_rx = [ rx_mat[0][0] * vertex[0] + rx_mat[0][1] * vertex[1] + rx_mat[0][2] * vertex[2], rx_mat[1][0] * vertex[0] + rx_mat[1][1] * vertex[1] + rx_mat[1][2] * vertex[2], rx_mat[2][0] * vertex[0] + rx_mat[2][1] * vertex[1] + rx_mat[2][2] * vertex[2] ] # 2. Rotationsmatrix für y-Achse generieren und anwenden ry_mat = rot_3D(self.angle_y, 'y') v_rot = [ ry_mat[0][0] * v_rx[0] + ry_mat[0][1] * v_rx[1] + ry_mat[0][2] * v_rx[2], ry_mat[1][0] * v_rx[0] + ry_mat[1][1] * v_rx[1] + ry_mat[1][2] * v_rx[2], ry_mat[2][0] * v_rx[0] + ry_mat[2][1] * v_rx[1] + ry_mat[2][2] * v_rx[2] ] # 3. Orthogonale Projektion auf die Bildschirmebene proj_x, proj_y = project_ortho(v_rot) # 4. Skalieren und in Bildschirmkoordinaten zentrieren screen_x = center_x + proj_x * scale_factor screen_y = center_y + proj_y * scale_factor projected_points.append((screen_x, screen_y)) # Kanten des Würfels zeichnen (Neon-Türkis) for edge in self.edges: p1 = projected_points[edge[0]] p2 = projected_points[edge[1]] pygame.draw.line(self.screen, (0, 255, 180), p1, p2, 2) # Eckpunkte als weiße Kreise zeichnen for p in projected_points: pygame.draw.circle(self.screen, (255, 255, 255), (int(p[0]), int(p[1])), 4) # Aufruf der Basisklasse für das Display-Update (flip) super().draw_game()