Files
matrixmania/wuerfel/spiel/cube_game.py
T
2026-10-22 13:44:28 +02:00

111 lines
4.1 KiB
Python

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()