109 lines
3.2 KiB
Python
109 lines
3.2 KiB
Python
"""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",
|
||
]
|