diff --git a/pman.py b/pman.py index 0c1970f..2c1a795 100644 --- a/pman.py +++ b/pman.py @@ -1,5 +1,5 @@ import pygame -import pygameController as PC +import pygameControls as PC from actors.enums import Colors, PlayerDirection from actors.pacman import ActorPacman from actors.ghost import Blinky, Pinky, Inky, Clyde # adjust import path as needed @@ -7,7 +7,7 @@ from actors.ghost_mode_controller import GhostModeController from hud import HUD from maze import Maze -__version__ = "0.3.1" +__version__ = "0.3.2" def spawn_ghosts(center_position): diff --git a/pygameController/__init__.py b/pygameController/__init__.py deleted file mode 100644 index 5397a56..0000000 --- a/pygameController/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import controller diff --git a/pygameController/controller.py b/pygameController/controller.py deleted file mode 100644 index 5167912..0000000 --- a/pygameController/controller.py +++ /dev/null @@ -1,29 +0,0 @@ -import pygame -from .controlsbase import ControlsBase -from .dualsense_controller import DualSenseController -from .dualsense_edge_controller import DualSenseEdgeController -from .logitech_f310_controller import LogitechF310Controller -from .logitech_f510_controller import LogitechF510Controller -from .logitech_f710_controller import LogitechF710Controller -from .xbox_series_x_controller import XboxSeriesXController -from .generic_controller import GenericController -from .logitech_dual_action_controller import LogitechDualActionController - -CONTROLLERS = { - "DualSense Wireless Controller": DualSenseController, - "DualSense Edge Wireless Controller": DualSenseEdgeController, - "Logitech Gamepad F310": LogitechF310Controller, - "Logitech Gamepad F510": LogitechF510Controller, - "Logitech Gamepad F710": LogitechF710Controller, - "Logitech Dual Action": LogitechDualActionController, - "X box Series X Controller": XboxSeriesXController - } - -class Controllers: - def __init__(self, joy): - self.controllers = [] - if not joy.get_name() in CONTROLLERS: - self.controllers.append(GenericController(joy)) - else: - self.controllers.append(CONTROLLERS[joy.get_name()](joy)) - \ No newline at end of file diff --git a/pygameController/controlsbase.py b/pygameController/controlsbase.py deleted file mode 100644 index 8285cae..0000000 --- a/pygameController/controlsbase.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -This is an abstract baseclass for the controls of snake. -""" -from abc import ABC, abstractmethod - -class ControlsBase(ABC): - @abstractmethod - def handle_input(self, event): - pass - - @abstractmethod - def left(self): - pass - - @abstractmethod - def right(self): - pass - - @abstractmethod - def up(self): - pass - - @abstractmethod - def down(self): - pass - - @abstractmethod - def pause(self): - pass - - @abstractmethod - def rumble(self): - pass \ No newline at end of file diff --git a/pygameController/dualsense_audio.py b/pygameController/dualsense_audio.py deleted file mode 100644 index 430ca5e..0000000 --- a/pygameController/dualsense_audio.py +++ /dev/null @@ -1,70 +0,0 @@ -import os -import time -import numpy as np -import sounddevice as sd -import alsaaudio -import pulsectl - -class DualSenseAudio: - def __init__(self): - self.alsa_devices = self._get_alsa_devices() - self.pulse_devices = self._get_pulseaudio_devices() - self.dualsense_device = self._detect_dualsense() - - def _get_alsa_devices(self): - try: - cards = alsaaudio.cards() - return cards - except Exception as e: - print("ALSA detection failed:", e) - return [] - - def _get_pulseaudio_devices(self): - try: - pulse = pulsectl.Pulse("dualsense-audio") - sinks = pulse.sink_list() - return sinks - except Exception as e: - print("PulseAudio detection failed:", e) - return [] - - def _detect_dualsense(self): - # Check ALSA names - for card in self.alsa_devices: - if "DualSense" in card: - return {'type': 'alsa', 'name': card} - - # Check PulseAudio sinks - for sink in self.pulse_devices: - if "dualsense" in sink.description.lower(): - return {'type': 'pulse', 'name': sink.name} - - return None - - def play_tone(self, frequency=440.0, duration=2.0, volume=0.5): - if not self.dualsense_device: - print("DualSense speaker not found.") - return - - print(f"Playing tone on DualSense ({self.dualsense_device['type']})...") - - fs = 48000 # Sample rate - t = np.linspace(0, duration, int(fs * duration), False) - tone = np.sin(frequency * 2 * np.pi * t) * volume - audio = tone.astype(np.float32) - - if self.dualsense_device['type'] == 'pulse': - sd.play(audio, samplerate=fs, device=self.dualsense_device['name']) - elif self.dualsense_device['type'] == 'alsa': - device_index = self.alsa_devices.index(self.dualsense_device['name']) - sd.play(audio, samplerate=fs, device=device_index) - sd.wait() - - def list_devices(self): - print("ALSA Devices:") - for card in self.alsa_devices: - print(f" - {card}") - print("\nPulseAudio Devices:") - for sink in self.pulse_devices: - print(f" - {sink.name} ({sink.description})") - diff --git a/pygameController/dualsense_controller.py b/pygameController/dualsense_controller.py deleted file mode 100644 index 075fda6..0000000 --- a/pygameController/dualsense_controller.py +++ /dev/null @@ -1,74 +0,0 @@ -from pygameController.controlsbase import ControlsBase -from pydualsense import * - -BATTERY_STATE = { - "0": "Discharging", - "1": "Charging", - "2": "Full", - "11": "Not charging", - "15": "Error", - "10": "Temp or voltage out of range" - } - -class DualSenseController(ControlsBase): - def __init__(self, joy): - self.device = pydualsense() - self.device.init() - self.name = self.device.device.get_product_string() - self.powerlevel = self.device.battery.Level - self.batterystate = BATTERY_STATE[str(self.device.battery.State)] - self.set_player_id(PlayerID.PLAYER_1) - print(f"{self.name} connected") - print(f"Power level: {self.powerlevel}") - print(f"Battery state: {self.batterystate}") - - def handle_input(self, event): - pass - - def set_led(self, red: int, green: int, blue: int): - self.device.light.setColorI(red, green, blue) - - def set_player_id(self, playerid: PlayerID): - self.device.light.setPlayerID(playerid) - - def left(self): - pass - - def right(self): - pass - - def up(self): - pass - - def down(self): - pass - - def pause(self): - pass - - def rumble(self): - pass - - @property - def name(self) -> str: - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - - @property - def powerlevel(self) -> str: - return self._powerlevel - - @powerlevel.setter - def powerlevel(self, lvl: str) -> None: - self._powerlevel = lvl - - @property - def batterystate(self) -> int: - return self._batterystate - - @batterystate.setter - def batterystate(self, state) -> None: - self._batterystate = state \ No newline at end of file diff --git a/pygameController/dualsense_edge_controller.py b/pygameController/dualsense_edge_controller.py deleted file mode 100644 index 46bfb50..0000000 --- a/pygameController/dualsense_edge_controller.py +++ /dev/null @@ -1,199 +0,0 @@ -import time -import threading -import numpy as np -import sounddevice as sd -import alsaaudio -import pulsectl -from pydualsense import * - - -class DualSenseEdgeController: - def __init__(self): - # DualSense input/output interface - self.ds = pydualsense() - self.ds.init() - self._listening = False - self._bindings = {} - - # Audio detection - self.alsa_devices = self._get_alsa_devices() - self.pulse_devices = self._get_pulseaudio_devices() - self.dualsense_audio_device = self._detect_dualsense_audio() - - print("DualSense initialized.") - - # ---------------------- Device Controls ---------------------- - - def set_rumble(self, small_motor: int, big_motor: int): - self.ds.setRumble(small_motor, big_motor) - - def stop_rumble(self): - self.set_rumble(0, 0) - - def set_led_color(self, r: int, g: int, b: int): - self.ds.setLightBarColor(r, g, b) - - def set_trigger_effects(self, left_mode='Off', right_mode='Off', force=0): - left = getattr(TriggerModes, left_mode.upper(), TriggerModes.Off) - right = getattr(TriggerModes, right_mode.upper(), TriggerModes.Off) - self.ds.triggerL.setMode(left) - self.ds.triggerR.setMode(right) - if force > 0: - self.ds.triggerL.setForce(force) - self.ds.triggerR.setForce(force) - - # ---------------------- Predefined Rumble Patterns ---------------------- - - def rumble_pattern(self, pattern: str, duration: float = 1.0): - patterns = { - "pulse": self._pulse_rumble, - "heartbeat": self._heartbeat_rumble, - "buzz": self._buzz_rumble, - "wave": self._wave_rumble, - "alarm": self._alarm_rumble, - } - if pattern in patterns: - threading.Thread(target=patterns[pattern], args=(duration,), daemon=True).start() - else: - print(f"Unknown rumble pattern: {pattern}") - - def _pulse_rumble(self, duration): - end = time.time() + duration - while time.time() < end: - self.set_rumble(50, 150) - time.sleep(0.2) - self.stop_rumble() - time.sleep(0.2) - - def _heartbeat_rumble(self, duration): - end = time.time() + duration - while time.time() < end: - self.set_rumble(200, 200) - time.sleep(0.1) - self.stop_rumble() - time.sleep(0.1) - self.set_rumble(100, 100) - time.sleep(0.1) - self.stop_rumble() - time.sleep(0.4) - - def _buzz_rumble(self, duration): - self.set_rumble(80, 255) - time.sleep(duration) - self.stop_rumble() - - def _wave_rumble(self, duration): - start = time.time() - while time.time() - start < duration: - for i in range(0, 256, 25): - self.set_rumble(i, 255 - i) - time.sleep(0.05) - for i in reversed(range(0, 256, 25)): - self.set_rumble(i, 255 - i) - time.sleep(0.05) - self.stop_rumble() - - def _alarm_rumble(self, duration): - end = time.time() + duration - while time.time() < end: - self.set_rumble(255, 0) - time.sleep(0.1) - self.set_rumble(0, 255) - time.sleep(0.1) - self.stop_rumble() - - # ---------------------- Input Listener + Bindings ---------------------- - - def bind(self, button: str, action: callable): - """Bind a button to a callable. Ex: controller.bind('cross', lambda: rumble_pattern('buzz'))""" - self._bindings[button] = action - - def start_input_listener(self): - def listen(): - while self._listening: - #self.ds.update() - for button, action in self._bindings.items(): - if getattr(self.ds, button, False): - action() - self._listening = True - thread = threading.Thread(target=listen, daemon=True) - thread.start() - - def stop_input_listener(self): - self._listening = False - - # ---------------------- Audio Output ---------------------- - - def _get_alsa_devices(self): - try: - return alsaaudio.cards() - except Exception: - return [] - - def _get_pulseaudio_devices(self): - try: - pulse = pulsectl.Pulse("dualsense-audio") - return pulse.sink_list() - except Exception: - return [] - - def _detect_dualsense_audio(self): - # Check ALSA names - for card in self.alsa_devices: - if "DualSense" in card: - return {'type': 'alsa', 'name': card} - - # Check PulseAudio sinks - for sink in self.pulse_devices: - if "dualsense" in sink.description.lower(): - return {'type': 'pulse', 'name': sink.name} - - return None - - def play_tone(self, frequency=440.0, duration=2.0, volume=0.5): - if not self.dualsense_audio_device: - print("DualSense speaker not detected.") - return - - print(f"Playing tone on DualSense ({self.dualsense_audio_device['type']})...") - - fs = 48000 # Sample rate - t = np.linspace(0, duration, int(fs * duration), False) - tone = np.sin(frequency * 2 * np.pi * t) * volume - audio = tone.astype(np.float32) - - try: - if self.dualsense_audio_device['type'] == 'pulse': - sd.play(audio, samplerate=fs, device=self.dualsense_audio_device['name']) - elif self.dualsense_audio_device['type'] == 'alsa': - device_index = self.alsa_devices.index(self.dualsense_audio_device['name']) - sd.play(audio, samplerate=fs, device=device_index) - sd.wait() - except Exception as e: - print("Failed to play tone:", e) - - def list_audio_devices(self): - print("ALSA Devices:") - for card in self.alsa_devices: - print(f" - {card}") - print("\nPulseAudio Devices:") - for sink in self.pulse_devices: - print(f" - {sink.name} ({sink.description})") - - # ---------------------- Cleanup ---------------------- - - def close(self): - self.ds.close() - -if __name__ == "__main__": - - controller = DualSenseController() - - # Bind buttons to patterns - controller.bind("cross", lambda: controller.rumble_pattern("heartbeat", 1.5)) - controller.bind("circle", lambda: controller.rumble_pattern("buzz", 0.5)) - controller.bind("triangle", lambda: controller.rumble_pattern("pulse", 2)) - controller.bind("square", lambda: controller.set_led_color(255, 0, 0)) - - # Start listening - controller.start_input_listener() diff --git a/pygameController/generic_controller.py b/pygameController/generic_controller.py deleted file mode 100644 index e6bb0b2..0000000 --- a/pygameController/generic_controller.py +++ /dev/null @@ -1,50 +0,0 @@ -import pygame -from pygameController.controlsbase import ControlsBase - -class GenericController(ControlsBase): - def __init__(self, joy): - self.device = joy - self.instance_id: int = self.device.get_instance_id() - self.name = self.device.get_name() - self.guid = self.device.get_guid() - self.numaxis: int = self.device.get_numaxes() - self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)] - self.numhats: int = self.device.get_numhats() - self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)] - self.numbuttons: int = self.device.get_numbuttons() - self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)] - print(f"{self.name} connected") - print("GUID:", self.guid) - print("Axis:", self.numaxis, self.axis) - print("Hats:", self.numhats, self.hats) - print("Buttons:", self.numbuttons, self.buttons) - - def handle_input(self, event): - pass - - def left(self): - pass - - def right(self): - pass - - def up(self): - pass - - def down(self): - pass - - def pause(self): - pass - - def rumble(self): - pass - - @property - def name(self) -> str: - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - \ No newline at end of file diff --git a/pygameController/logitech_dual_action_controller.py b/pygameController/logitech_dual_action_controller.py deleted file mode 100644 index e380a83..0000000 --- a/pygameController/logitech_dual_action_controller.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -Logitech F310 Controller class. -This controller is a usb controller, with the following features. -(XInput mode) -6 axis -11 buttons -1 hat - -(DirectInput mode) -4 axis -12 buttons -1 hat -""" - -import pygame -from pygameController.controlsbase import ControlsBase -from enum import Enum - -class InputMode(Enum): - DirectInput = 1 - XInput = 2 - -class LogitechDualActionController(ControlsBase): - def __init__(self, joy): - self.device = joy - self.instance_id: int = self.device.get_instance_id() - self.name = self.device.get_name() - self.guid = self.device.get_guid() - self.powerlevel = self.device.get_power_level() - self.numaxis: int = self.device.get_numaxes() - self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)] - self.numhats: int = self.device.get_numhats() - self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)] - self.numbuttons: int = self.device.get_numbuttons() - self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)] - self.input_mode = InputMode.DirectInput - print(f"{self.name} connected") - print("GUID:", self.guid) - print("Axis:", self.numaxis, self.axis) - print("Hats:", self.numhats, self.hats) - print("Buttons:", self.numbuttons, self.buttons) - print("Input mode:", self.input_mode) - - def handle_input(self, event): - pass - - def left(self): - pass - - def right(self): - pass - - def up(self): - pass - - def down(self): - pass - - def pause(self): - pass - - def rumble(self): - pass - - @property - def name(self) -> str: - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - - @property - def input_mode(self) -> int: - return self._inputmode - - @input_mode.setter - def input_mode(self, mode: int) -> None: - self._inputmode = mode - \ No newline at end of file diff --git a/pygameController/logitech_f310_controller.py b/pygameController/logitech_f310_controller.py deleted file mode 100644 index be34092..0000000 --- a/pygameController/logitech_f310_controller.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -Logitech F310 Controller class. -This controller is a usb controller, with the following features. -(XInput mode) -6 axis -11 buttons -1 hat - -(DirectInput mode) -4 axis -12 buttons -1 hat -""" - -import pygame -from pygameController.controlsbase import ControlsBase -from enum import Enum - -class InputMode(Enum): - DirectInput = 1 - XInput = 2 - -class LogitechF310Controller(ControlsBase): - def __init__(self, joy): - self.device = joy - self.instance_id: int = self.device.get_instance_id() - self.name = self.device.get_name() - self.guid = self.device.get_guid() - self.powerlevel = self.device.get_power_level() - self.numaxis: int = self.device.get_numaxes() - self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)] - self.numhats: int = self.device.get_numhats() - self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)] - self.numbuttons: int = self.device.get_numbuttons() - self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)] - self.input_mode = InputMode.XInput - print(f"{self.name} connected") - print("GUID:", self.guid) - print("Axis:", self.numaxis, self.axis) - print("Hats:", self.numhats, self.hats) - print("Buttons:", self.numbuttons, self.buttons) - print("Input mode:", self.input_mode) - - def handle_input(self, event): - pass - - def left(self): - pass - - def right(self): - pass - - def up(self): - pass - - def down(self): - pass - - def pause(self): - pass - - def rumble(self): - pass - - @property - def name(self) -> str: - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - - @property - def input_mode(self) -> int: - return self._inputmode - - @input_mode.setter - def input_mode(self, mode: int) -> None: - self._inputmode = mode - \ No newline at end of file diff --git a/pygameController/logitech_f510_controller.py b/pygameController/logitech_f510_controller.py deleted file mode 100644 index a3d8a09..0000000 --- a/pygameController/logitech_f510_controller.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Logitech F310 Controller class. -This controller is a usb controller, with the following features. -(XInput mode) -6 axis -11 buttons -1 hat - -(DirectInput mode) -4 axis -12 buttons -1 hat -""" - -import pygame -from pygameController.controlsbase import ControlsBase -from enum import Enum - -class InputMode(Enum): - DirectInput = 1 - XInput = 2 - -class ConnectionType(Enum): - WIRED = 1 - WIRELESS = 2 - -class LogitechF510Controller(ControlsBase): - def __init__(self, joy): - self.device = joy - self.instance_id: int = self.device.get_instance_id() - self.name = self.device.get_name() - self.numaxis: int = self.device.get_numaxis() - self.axis: list = [] - self.numhats: int = self.device.get_numhats() - self.hats: list = [] - self.numbuttons: int = self.device.get_numbuttons() - self.buttons: list = [] - self.input_mode: InputMode.DirectInput - self.input_connection: ConnectionType.WIRED - - def handle_input(self, event): - pass - - def left(self): - pass - - def right(self): - pass - - def up(self): - pass - - def down(self): - pass - - def pause(self): - pass - - def rumble(self): - pass - - @property - def name(self) -> str: - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - - @property - def axis(self) -> list: - return self._axis - - @axis.setter - def axis(self) -> None: - self._axis = [self.device.get_axis(a) for a in range(self.numaxis)] - - @property - def hats(self) -> list: - return self._hats - - @hats.setter - def hats(self) -> None: - self.hats = [self.device.get_hats(h) for h in range(self.numhats)] - - @property - def buttons(self) -> list: - return self._buttons - - @buttons.setter - def buttons(self) -> None: - self._buttons = [self.device.get_buttons(b) for b in range(self.numbuttons)] - - @property - def input_mode(self) -> int: - return self._inputmode - - @input_mode.setter - def input_mode(self, mode: int) -> None: - self._inputmode = mode - - @property - def input_connection(self) -> int: - return self._input_connection - - @input_connection.setter - def input_connection(self, conn: int) -> None: - self._input_connection = conn \ No newline at end of file diff --git a/pygameController/logitech_f710_controller.py b/pygameController/logitech_f710_controller.py deleted file mode 100644 index 1df528c..0000000 --- a/pygameController/logitech_f710_controller.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Logitech F310 Controller class. -This controller is a usb controller, with the following features. -(XInput mode) -6 axis -11 buttons -1 hat - -(DirectInput mode) -4 axis -12 buttons -1 hat -""" - -import pygame -from pygameController.controlsbase import ControlsBase -from enum import Enum - -class InputMode(Enum): - DirectInput = 1 - XInput = 2 - -class ConnectionType(Enum): - WIRED = 1 - WIRELESS = 2 - -class LogitechF710Controller(ControlsBase): - def __init__(self, joy): - self.device = joy - self.instance_id: int = self.device.get_instance_id() - self.name = self.device.get_name() - self.numaxis: int = self.device.get_numaxis() - self.axis: list = [] - self.numhats: int = self.device.get_numhats() - self.hats: list = [] - self.numbuttons: int = self.device.get_numbuttons() - self.buttons: list = [] - self.input_mode: InputMode.DirectInput - self.input_connection: ConnectionType.WIRED - - def handle_input(self, event): - pass - - def left(self): - pass - - def right(self): - pass - - def up(self): - pass - - def down(self): - pass - - def pause(self): - pass - - def rumble(self): - pass - - @property - def name(self) -> str: - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - - @property - def axis(self) -> list: - return self._axis - - @axis.setter - def axis(self) -> None: - self._axis = [self.device.get_axis(a) for a in range(self.numaxis)] - - @property - def hats(self) -> list: - return self._hats - - @hats.setter - def hats(self) -> None: - self.hats = [self.device.get_hats(h) for h in range(self.numhats)] - - @property - def buttons(self) -> list: - return self._buttons - - @buttons.setter - def buttons(self) -> None: - self._buttons = [self.device.get_buttons(b) for b in range(self.numbuttons)] - - @property - def input_mode(self) -> int: - return self._inputmode - - @input_mode.setter - def input_mode(self, mode: int) -> None: - self._inputmode = mode - - @property - def input_connection(self) -> int: - return self._input_connection - - @input_connection.setter - def input_connection(self, conn: int) -> None: - self._input_connection = conn \ No newline at end of file diff --git a/pygameController/xbox_series_x_controller.py b/pygameController/xbox_series_x_controller.py deleted file mode 100644 index 7ed608f..0000000 --- a/pygameController/xbox_series_x_controller.py +++ /dev/null @@ -1,50 +0,0 @@ -import time -import threading - -class XboxSeriesXController: - def __init__(self, joy): - self.device = joy - self.instance_id: int = self.device.get_instance_id() - self.name = self.device.get_name() - self.guid = self.device.get_guid() - self.numaxis: int = self.device.get_numaxes() - self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)] - self.numhats: int = self.device.get_numhats() - self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)] - self.numbuttons: int = self.device.get_numbuttons() - self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)] - print(f"{self.name} connected") - print("GUID:", self.guid) - print("Axis:", self.numaxis, self.axis) - print("Hats:", self.numhats, self.hats) - print("Buttons:", self.numbuttons, self.buttons) - - def handle_input(self, event): - pass - - def left(self): - pass - - def right(self): - pass - - def up(self): - pass - - def down(self): - pass - - def pause(self): - pass - - def rumble(self): - pass - - @property - def name(self) -> str: - return self._name - - @name.setter - def name(self, name: str) -> None: - self._name = name - \ No newline at end of file