import pygame import random import time from kart import Kart, Item # ------------------------- # Einstellungen # ------------------------- WIDTH = 1000 HEIGHT = 700 FPS = 60 BACKGROUND = (40, 40, 40) import pygame import random import time from pathlib import Path from kart import Kart, Item # ------------------------- # Einstellungen # ------------------------- WIDTH = 1000 HEIGHT = 700 FPS = 60 BACKGROUND = (40, 40, 40) # Breite des Kart-Bildes auf dem Bildschirm. # Die Höhe wird automatisch passend zum Seitenverhältnis berechnet. KART_IMAGE_WIDTH = 60 # Falls die Vorderseite von car.jpg nicht nach rechts zeigt, kann dieser # Wert angepasst werden, z. B. 90, -90 oder 180. KART_IMAGE_ROTATION_OFFSET = 0 # Das Originalbild und bereits eingefärbte Varianten werden zwischengespeichert. CAR_IMAGE = None CAR_IMAGE_CACHE = {} # ------------------------- # Hilfsfunktionen zum Zeichnen # ------------------------- def load_car_image(): """Lädt car.jpg aus demselben Ordner wie main.py.""" global CAR_IMAGE image_path = Path(__file__).resolve().with_name("car.jpg") image = pygame.image.load(str(image_path)).convert_alpha() # Seitenverhältnis des Bildes beibehalten. scale = KART_IMAGE_WIDTH / image.get_width() new_height = max(1, round(image.get_height() * scale)) CAR_IMAGE = pygame.transform.smoothscale( image, (KART_IMAGE_WIDTH, new_height) ) def get_colored_car_image(color): """ Gibt car.jpg in der gewünschten Kartfarbe zurück. Reine Grautöne bleiben unverändert. Rote Bereiche werden durch die gewünschte Farbe ersetzt. Ein kleiner Toleranzbereich sorgt dafür, dass auch durch JPEG-Kompression veränderte rote Randpixel mitgefärbt werden. """ color = tuple(color) if color in CAR_IMAGE_CACHE: return CAR_IMAGE_CACHE[color] image = CAR_IMAGE.copy() pixels = pygame.PixelArray(image) for x in range(image.get_width()): for y in range(image.get_height()): pixel = image.unmap_rgb(pixels[x, y]) r, g, b = pixel.r, pixel.g, pixel.b # Grautöne haben ungefähr r == g == b. # Nur deutlich rotlastige Pixel werden eingefärbt. gray = (g + b) / 2 redness = r - max(g, b) if redness > 10: # Stärke des roten Anteils. # (255, 0, 0) -> 1.0, rote Übergangspixel entsprechend weniger. strength = min(1.0, max(0.0, (r - gray) / 255.0)) new_r = round(gray + (color[0] - gray) * strength) new_g = round(gray + (color[1] - gray) * strength) new_b = round(gray + (color[2] - gray) * strength) pixels[x, y] = (new_r, new_g, new_b) del pixels CAR_IMAGE_CACHE[color] = image return image def draw_kart(screen, kart, car_image, car_cache): color_key = tuple(kart.color) # Eingefärbtes Bild nur einmal pro Farbe erstellen if color_key not in car_cache: colored = colorize_car(car_image, kart.color) # Vergrößern ohne Glättung -> Pixel-Look bleibt erhalten scale = 4 new_size = ( colored.get_width() * scale, colored.get_height() * scale ) car_cache[color_key] = pygame.transform.scale( colored, new_size ) surface = car_cache[color_key] # Kart entsprechend seiner Rotation drehen rotated = pygame.transform.rotate(surface, -kart.rotation) rect = rotated.get_rect( center=(int(kart.position[0]), int(kart.position[1])) ) screen.blit(rotated, rect) # ------------------------- # Pool zeichnen # ------------------------- def draw_pool(screen, pool): pygame.draw.ellipse( screen, pool.color, ( int(pool.position[0] - pool.size), int(pool.position[1] - pool.size / 2), int(pool.size * 2), int(pool.size) ) ) def colorize_car(image, color): colored = image.copy() for x in range(colored.get_width()): for y in range(colored.get_height()): r, g, b, a = colored.get_at((x, y)) # Nur reines Rot wird durch die Kart-Farbe ersetzt if (r, g, b) == (255, 0, 0): colored.set_at((x, y), (*color, a)) return colored # ------------------------- # Main # ------------------------- def main(): pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Kart Game") # car.jpg erst nach dem Erzeugen des Fensters laden, damit convert_alpha() # das Bild für die aktuelle Anzeige optimieren kann. load_car_image() clock = pygame.time.Clock() car_image = pygame.image.load("car.png").convert_alpha() car_cache = {} # ------------------------- # Karts erzeugen # ------------------------- kart1 = Kart( "Player 1", (255, 50, 50), acceleration=0.2, vMax=5, handling=4 ) kart2 = Kart( "Player 2", (50, 100, 255), acceleration=0.2, vMax=5, handling=4 ) # Startpositionen kart1.position = [250, 350] kart1.rotation = 0 kart2.position = [750, 350] kart2.rotation = 180 # ------------------------- # Pool # ------------------------- pool = None # Zeitpunkt, wann der nächste Pool erscheint nextPoolTime = time.time() + random.uniform(3, 8) running = True while running: # ------------------------- # Events # ------------------------- for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # ------------------------- # Pool erzeugen / entfernen # ------------------------- currentTime = time.time() # Wenn momentan kein Pool existiert # und die Wartezeit vorbei ist if pool is None and currentTime >= nextPoolTime: pool = Item("pool") pool.typ() # Zufällige Position pool.position = [ random.randint(80, WIDTH - 80), random.randint(80, HEIGHT - 80) ] # Zufällige Größe pool.size = random.randint(40, 80) # Pool bleibt unterschiedlich lange sichtbar poolEndTime = currentTime + random.uniform(3, 7) # Pool verschwinden lassen if pool is not None and currentTime >= poolEndTime: pool = None # Unregelmäßige Zeit bis zum nächsten Pool nextPoolTime = currentTime + random.uniform(3, 10) keys = pygame.key.get_pressed() # ------------------------- # Kart 1 # WASD + E # ------------------------- # W = Gas if keys[pygame.K_w]: kart1.acc(False) # S = Rückwärts / Bremsen elif keys[pygame.K_s]: kart1.acc(True) # Wenn kein Gas/Bremse -> langsam abbremsen else: kart1.speed *= 0.98 # A = links if keys[pygame.K_a]: kart1.turn(-1) # D = rechts if keys[pygame.K_d]: kart1.turn(1) # E = Rammen if keys[pygame.K_e]: kart1.ram(kart2) # ------------------------- # Kart 2 # IJKL + O # ------------------------- # I = Gas if keys[pygame.K_i]: kart2.acc(False) # K = Rückwärts / Bremsen elif keys[pygame.K_k]: kart2.acc(True) else: kart2.speed *= 0.98 # J = links if keys[pygame.K_j]: kart2.turn(-1) # L = rechts if keys[pygame.K_l]: kart2.turn(1) # O = Rammen if keys[pygame.K_o]: kart2.ram(kart1) # ------------------------- # Position aktualisieren # ------------------------- kart1.pos() kart2.pos() # ------------------------- # Bildschirm verlassen? # -> auf andere Seite wechseln # ------------------------- # Abstand zum Bildschirmrand border = 20 for kart in [kart1, kart2]: # Linker Rand if kart.position[0] < border: kart.position[0] = border # Rechter Rand if kart.position[0] > WIDTH - border: kart.position[0] = WIDTH - border # Oberer Rand if kart.position[1] < border: kart.position[1] = border # Unterer Rand if kart.position[1] > HEIGHT - border: kart.position[1] = HEIGHT - border # ------------------------- # Zeichnen # ------------------------- screen.fill(BACKGROUND) # Pool zeichnen if pool is not None: draw_pool(screen, pool) draw_kart(screen, kart1, car_image, car_cache) draw_kart(screen, kart2, car_image, car_cache) # Namen anzeigen font = pygame.font.Font(None, 28) text1 = font.render( f"{kart1.name}: {kart1.speed:.1f}", True, kart1.color ) text2 = font.render( f"{kart2.name}: {kart2.speed:.1f}", True, kart2.color ) screen.blit(text1, (20, 20)) screen.blit(text2, (20, 50)) pygame.display.flip() # FPS clock.tick(FPS) pygame.quit() if __name__ == "__main__": main() # ------------------------- # Hilfsfunktion zum Zeichnen # ------------------------- def draw_kart(screen, kart): # Kart als Rechteck width = 40 height = 25 surface = pygame.Surface((width, height), pygame.SRCALPHA) pygame.draw.rect(surface, kart.color, (0, 0, width, height)) # Richtung des Karts rotated = pygame.transform.rotate(surface, -kart.rotation) rect = rotated.get_rect( center=(int(kart.position[0]), int(kart.position[1])) ) screen.blit(rotated, rect) # ------------------------- # Pool zeichnen # ------------------------- def draw_pool(screen, pool): pygame.draw.ellipse( screen, pool.color, ( int(pool.position[0] - pool.size), int(pool.position[1] - pool.size / 2), int(pool.size * 2), int(pool.size) ) ) def apply_pool_slow(kart, pool): if pool is None: return dx = kart.position[0] - pool.position[0] dy = kart.position[1] - pool.position[1] # Prüfen, ob das Kart innerhalb der Ellipse liegt inside = ( (dx / pool.size) ** 2 + (dy / (pool.size / 2)) ** 2 <= 1 ) if inside: kart.speed *= 0.8 # ------------------------- # Main # ------------------------- def main(): pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Kart Game") clock = pygame.time.Clock() # ------------------------- # Karts erzeugen # ------------------------- kart1 = Kart( "Player 1", (255, 50, 50), acceleration=0.2, vMax=5, handling=4 ) kart2 = Kart( "Player 2", (50, 100, 255), acceleration=0.2, vMax=5, handling=4 ) # Startpositionen kart1.position = [250, 350] kart1.rotation = 0 kart2.position = [750, 350] kart2.rotation = 180 # ------------------------- # Pool # ------------------------- pool = None # Zeitpunkt, wann der nächste Pool erscheint nextPoolTime = time.time() + random.uniform(3, 8) running = True while running: # ------------------------- # Events # ------------------------- for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # ------------------------- # Pool erzeugen / entfernen # ------------------------- currentTime = time.time() # Wenn momentan kein Pool existiert # und die Wartezeit vorbei ist if pool is None and currentTime >= nextPoolTime: pool = Item("pool") pool.typ() # Zufällige Position pool.position = [ random.randint(80, WIDTH - 80), random.randint(80, HEIGHT - 80) ] # Zufällige Größe pool.size = random.randint(40, 80) # Pool bleibt unterschiedlich lange sichtbar poolEndTime = currentTime + random.uniform(3, 7) # Pool verschwinden lassen if pool is not None and currentTime >= poolEndTime: pool = None # Unregelmäßige Zeit bis zum nächsten Pool nextPoolTime = currentTime + random.uniform(3, 10) keys = pygame.key.get_pressed() # ------------------------- # Kart 1 # WASD + E # ------------------------- # W = Gas if keys[pygame.K_w]: kart1.acc(False) # S = Rückwärts / Bremsen elif keys[pygame.K_s]: kart1.acc(True) # Wenn kein Gas/Bremse -> langsam abbremsen else: kart1.acc(None) # A = links if keys[pygame.K_a]: kart1.turn(-1) # D = rechts if keys[pygame.K_d]: kart1.turn(1) # E = Rammen if keys[pygame.K_e]: kart1.ram(kart2) # ------------------------- # Kart 2 # IJKL + O # ------------------------- # I = Gas if keys[pygame.K_i]: kart2.acc(False) # K = Rückwärts / Bremsen elif keys[pygame.K_k]: kart2.acc(True) else: kart1.acc(None) # J = links if keys[pygame.K_j]: kart2.turn(-1) # L = rechts if keys[pygame.K_l]: kart2.turn(1) # O = Rammen if keys[pygame.K_o]: kart2.ram(kart1) # ------------------------- # Position aktualisieren # ------------------------- # Pool-Effekt apply_pool_slow(kart1, pool) apply_pool_slow(kart2, pool) # Position aktualisieren kart1.pos() kart2.pos() # ------------------------- # Bildschirm verlassen? # -> auf andere Seite wechseln # ------------------------- # Abstand zum Bildschirmrand border = 20 for kart in [kart1, kart2]: # Linker Rand if kart.position[0] < border: kart.position[0] = border # Rechter Rand if kart.position[0] > WIDTH - border: kart.position[0] = WIDTH - border # Oberer Rand if kart.position[1] < border: kart.position[1] = border # Unterer Rand if kart.position[1] > HEIGHT - border: kart.position[1] = HEIGHT - border # ------------------------- # Zeichnen # ------------------------- screen.fill(BACKGROUND) # Pool zeichnen if pool is not None: draw_pool(screen, pool) draw_kart(screen, kart1) draw_kart(screen, kart2) # Namen anzeigen font = pygame.font.Font(None, 28) text1 = font.render( f"{kart1.name}: {kart1.speed:.1f}", True, kart1.color ) text2 = font.render( f"{kart2.name}: {kart2.speed:.1f}", True, kart2.color ) screen.blit(text1, (20, 20)) screen.blit(text2, (20, 50)) pygame.display.flip() # FPS clock.tick(FPS) pygame.quit() if __name__ == "__main__": main()