"""Tastatur und Controller → abstrakte Aktionen. Die Aktionen sind absichtlich generisch gehalten. Die spätere Namenseingabe per Controller benutzt dieselben Richtungen (Buchstabe weiter/zurück, Position wechseln), deshalb gibt es hier keine spielspezifischen Namen. """ from __future__ import annotations import enum import pygame from . import config class Action(enum.Enum): """Abstrakte Eingabe – unabhängig davon, ob Tastatur oder Controller.""" PRIMARY = "primary" # Space / Enter / Controller A LEFT = "left" # Pfeil links / D-Pad links RIGHT = "right" # Pfeil rechts / D-Pad rechts UP = "up" # Pfeil hoch / D-Pad hoch DOWN = "down" # Pfeil runter / D-Pad runter BACK = "back" # Esc / Controller B #: Tastaturbelegung KEY_ACTIONS: dict[int, Action] = { pygame.K_SPACE: Action.PRIMARY, pygame.K_RETURN: Action.PRIMARY, pygame.K_KP_ENTER: Action.PRIMARY, pygame.K_LEFT: Action.LEFT, pygame.K_RIGHT: Action.RIGHT, pygame.K_UP: Action.UP, pygame.K_DOWN: Action.DOWN, pygame.K_ESCAPE: Action.BACK, } #: Controller-Tasten (Xbox-Layout: 0=A, 1=B, 2=X, 3=Y) BUTTON_ACTIONS: dict[int, Action] = { 0: Action.PRIMARY, 1: Action.BACK, 2: Action.LEFT, 3: Action.UP, } #: D-Pad, das als Hat gemeldet wird HAT_ACTIONS: dict[tuple[int, int], Action] = { (-1, 0): Action.LEFT, (1, 0): Action.RIGHT, (0, -1): Action.UP, (0, 1): Action.DOWN, } #: Analogstick: ab diesem Ausschlag gilt eine Richtung als gewollt AXIS_DEADZONE = 0.6 def actions_from_event(event: pygame.event.Event) -> list[Action]: """Übersetzt ein pygame-Event in null bis eine Aktion.""" if event.type == pygame.KEYDOWN: action = KEY_ACTIONS.get(event.key) return [action] if action else [] if event.type == pygame.JOYBUTTONDOWN: action = BUTTON_ACTIONS.get(event.button) return [action] if action else [] if event.type == pygame.JOYHATMOTION: action = HAT_ACTIONS.get(tuple(event.value)) return [action] if action else [] if event.type == pygame.JOYAXISMOTION: if event.axis == 0 and abs(event.value) >= AXIS_DEADZONE: return [Action.RIGHT if event.value > 0 else Action.LEFT] if event.axis == 1 and abs(event.value) >= AXIS_DEADZONE: return [Action.DOWN if event.value > 0 else Action.UP] return [] def connected_controllers() -> list[str]: """Namen aller angeschlossenen Controller (leer, wenn keiner da ist).""" names = [] for index in range(pygame.joystick.get_count()): try: stick = pygame.joystick.Joystick(index) stick.init() names.append(stick.get_name()) except pygame.error: continue return names def describe_controller_setup() -> str: names = connected_controllers() if not names: return "Controller: keiner erkannt (Tastatur: Space=Snap, ←=Drehen, ↑=OnTop, Esc=Ende)" return "Controller: " + ", ".join(names) def controller_hint_lines() -> list[str]: """Kurzhilfe fürs Log beim Start.""" return [ describe_controller_setup(), f"Zielauflösung {config.SCREEN_WIDTH}x{config.SCREEN_HEIGHT}, " f"{config.FPS} fps", ]