diff --git a/overcooked_simulator/gui_2d_vis/overcooked_gui.py b/overcooked_simulator/gui_2d_vis/overcooked_gui.py index 4235ad634e603aadb60b268a2210a2e7363f9333..ba9e79a63ba897028bf2b3075b9eadff1cad825a 100644 --- a/overcooked_simulator/gui_2d_vis/overcooked_gui.py +++ b/overcooked_simulator/gui_2d_vis/overcooked_gui.py @@ -45,7 +45,7 @@ class PlayerKeySet: First four keys are for movement. Order: Down, Up, Left, Right. 5th key is for interacting with counters. 6th key ist for picking up things or dropping them. """ - def __init__(self, player_name: str | int, keys: list[pygame.key]): + def __init__(self, player_name: str | int, keys: list[pygame.key], joystick: int): """Creates a player key set which contains information about which keyboard keys control the player. Movement keys in the following order: Down, Up, Left, Right @@ -53,6 +53,8 @@ class PlayerKeySet: Args: player_name: The name of the player to control. keys: The keys which control this player in the following order: Down, Up, Left, Right, Interact, Pickup. + # FIXME: not needed when player name is an index + joystick: number of joystick (later check if available) """ self.name = player_name self.player_keys = keys @@ -62,6 +64,7 @@ class PlayerKeySet: } self.interact_key = self.player_keys[-2] self.pickup_key = self.player_keys[-1] + self.joystick = joystick class PyGameGUI: @@ -83,10 +86,10 @@ class PyGameGUI: self.player_keys = player_keys self.player_key_sets: list[PlayerKeySet] = [ - PlayerKeySet(player_name, keys) - for player_name, keys in zip( + PlayerKeySet(player_name, keys, joystick=index) + for index, (player_name, keys) in enumerate(zip( self.player_names, self.player_keys[: len(self.player_names)] - ) + )) ] self.websocket_url = f"ws://{url}:{port}/ws/player/" @@ -195,29 +198,31 @@ class PyGameGUI: # Axis 0: joy stick left: -1 = left, ~0 = center, 1 = right # Axis 1: joy stick left: -1 = up, ~0 = center, 1 = down # see control stuff here (at the end of the page): https://www.pygame.org/docs/ref/joystick.html - for joystick in joysticks.values(): - # Usually axis run in pairs, up/down for one, and left/right for the other. Triggers count as axes. - move_vec = np.zeros(2) - # You may want to take into account some tolerance to handle jitter, - # and joystick drift may keep the joystick from centering at 0 or using the full range of position values. - # FIXME: hardcoded threshold for tolerance - tolerance_threshold = 0.2 - # axis 0 = joy stick left --> left & right - axis_left_right = joystick.get_axis(0) - if abs(axis_left_right) > tolerance_threshold: - move_vec[0] += axis_left_right - # axis 1 = joy stick right --> up & down - axis_up_down = joystick.get_axis(1) - if abs(axis_up_down) > tolerance_threshold: - move_vec[1] += axis_up_down - - if np.linalg.norm(move_vec) != 0: - move_vec = move_vec / np.linalg.norm(move_vec) - - action = Action( - "0", ActionType.MOVEMENT, move_vec, duration=1 / self.FPS - ) - self.send_action(action) + for key_set in self.player_key_sets: + # if a joystick is connected for current player + if joysticks[key_set.joystick]: + # Usually axis run in pairs, up/down for one, and left/right for the other. Triggers count as axes. + move_vec = np.zeros(2) + # You may want to take into account some tolerance to handle jitter, and + # joystick drift may keep the joystick from centering at 0 or using the full range of position values. + # FIXME: hardcoded threshold for tolerance + tolerance_threshold = 0.2 + # axis 0 = joy stick left --> left & right + axis_left_right = joysticks[key_set.joystick].get_axis(0) + if abs(axis_left_right) > tolerance_threshold: + move_vec[0] += axis_left_right + # axis 1 = joy stick right --> up & down + axis_up_down = joysticks[key_set.joystick].get_axis(1) + if abs(axis_up_down) > tolerance_threshold: + move_vec[1] += axis_up_down + + if np.linalg.norm(move_vec) != 0: + move_vec = move_vec / np.linalg.norm(move_vec) + + action = Action( + str(key_set.joystick), ActionType.MOVEMENT, move_vec, duration=1 / self.FPS + ) + self.send_action(action) def handle_key_event(self, event): """Handles key events for the pickup and interaction keys. Pickup is a single action, @@ -244,36 +249,39 @@ class PyGameGUI: ) self.send_action(action) - def handle_joy_stick_event(self, event): + def handle_joy_stick_event(self, event, joysticks): """Handles joy stick events for the pickup and interaction keys. Pickup is a single action, for interaction buttondown and buttonup is necessary, because the player has to be able to hold the button down. Args: event: Pygame event for extracting the button action. + joysticks: list of joysticks """ - if event.type == pygame.JOYBUTTONDOWN: - # pickup = Button A <-> 0 - if event.button == 0: - # FIXME: Name missing - action = Action("0", ActionType.PUT, "pickup") - self.send_action(action) + for key_set in self.player_key_sets: + # if a joystick is connected for current player + if joysticks[key_set.joystick]: + # pickup = Button A <-> 0 + if joysticks[key_set.joystick].get_button(0): + action = Action(str(key_set.joystick), ActionType.PUT, "pickup") + self.send_action(action) - # interact = Button X <-> 2 - if event.button == 2: - if event.type == pygame.JOYBUTTONDOWN: - # FIXME: Name missing - action = Action( - "0", ActionType.INTERACT, InterActionData.START - ) - self.send_action(action) - elif event.type == pygame.JOYBUTTONUP: - # FIXME: Name missing - action = Action( - "0", ActionType.INTERACT, InterActionData.STOP - ) - self.send_action(action) + # FIXME: when clicking X without cutboard and then A to lay it on the cutboard, + # it is automatically cutted when laying down + # FIXME: does it work with button up and down? + # interact = Button X <-> 2 + if joysticks[key_set.joystick].get_button(2): + if event.type == pygame.JOYBUTTONDOWN: + action = Action( + str(key_set.joystick), ActionType.INTERACT, InterActionData.START + ) + self.send_action(action) + elif event.type == pygame.JOYBUTTONUP: + action = Action( + str(key_set.joystick), ActionType.INTERACT, InterActionData.STOP + ) + self.send_action(action) def init_ui_elements(self): self.manager = pygame_gui.UIManager((self.window_width, self.window_height)) @@ -690,7 +698,7 @@ class PyGameGUI: # joystick, filling up the list without needing to create them manually. joy = pygame.joystick.Joystick(event.device_index) joysticks[joy.get_instance_id()] = joy - print(f"Joystick {joy.get_instance_id()} connencted") + print(f"Joystick {joy.get_instance_id()} connected") # UI Buttons: if event.type == pygame_gui.UI_BUTTON_PRESSED: @@ -721,7 +729,7 @@ class PyGameGUI: self.handle_key_event(event) if event.type in [pygame.JOYBUTTONDOWN, pygame.JOYBUTTONUP] and self.menu_state == MenuStates.Game: - self.handle_joy_stick_event(event) + self.handle_joy_stick_event(event, joysticks=joysticks) self.manager.process_events(event)