diff --git a/overcooked_simulator/gui_2d_vis/drawing.py b/overcooked_simulator/gui_2d_vis/drawing.py
index d2f44c42de154e0f98b59bb02c572518422c7a63..d2d96231c56d2338d9e790e011eb86faac0c3527 100644
--- a/overcooked_simulator/gui_2d_vis/drawing.py
+++ b/overcooked_simulator/gui_2d_vis/drawing.py
@@ -67,9 +67,10 @@ class Visualizer:
 
     def draw_gamescreen(
         self,
-        screen,
-        state,
-        grid_size,
+        screen: pygame.Surface,
+        state: dict,
+        grid_size: int,
+        controlled_player_idxs: list[int],
     ):
         width = int(np.ceil(state["kitchen"]["width"] * grid_size))
         height = int(np.ceil(state["kitchen"]["height"] * grid_size))
@@ -85,14 +86,20 @@ class Visualizer:
             grid_size,
         )
 
+        for idx, col in zip(controlled_player_idxs, [colors["blue"], colors["red"]]):
+            pygame.draw.circle(
+                screen,
+                col,
+                np.array(state["players"][idx]["pos"]) * grid_size + (grid_size // 2),
+                (grid_size / 2),
+            )
+
         self.draw_players(
             screen,
             state["players"],
             grid_size,
         )
 
-        print(state)
-
     def draw_background(self, surface, width, height, grid_size):
         """Visualizes a game background."""
         block_size = grid_size // 2  # Set the size of the grid block
@@ -152,7 +159,7 @@ class Visualizer:
             if USE_PLAYER_COOK_SPRITES:
                 pygame.draw.circle(
                     screen,
-                    self.player_colors[p_idx],
+                    colors[self.player_colors[p_idx]],
                     pos - facing * grid_size * 0.25,
                     grid_size * 0.2,
                 )
diff --git a/overcooked_simulator/gui_2d_vis/gui_theme.json b/overcooked_simulator/gui_2d_vis/gui_theme.json
index cabbe0368805a697727c738673b1783ac1e56e7e..37c116f45629adcf8aa960e01ac0bc1a60c0a564 100644
--- a/overcooked_simulator/gui_2d_vis/gui_theme.json
+++ b/overcooked_simulator/gui_2d_vis/gui_theme.json
@@ -92,5 +92,10 @@
       "normal_border": "#000000",
       "normal_text": "#000000"
     }
+  },
+  "#players": {
+    "colours": {
+      "normal_bg": "#fffacd"
+    }
   }
 }
\ No newline at end of file
diff --git a/overcooked_simulator/gui_2d_vis/overcooked_gui.py b/overcooked_simulator/gui_2d_vis/overcooked_gui.py
index 7922bc2fedf5de237a620e01ef0ad2496e942da9..c50760996cc3092f942ae80fe17ce10453fb1c3d 100644
--- a/overcooked_simulator/gui_2d_vis/overcooked_gui.py
+++ b/overcooked_simulator/gui_2d_vis/overcooked_gui.py
@@ -45,7 +45,14 @@ 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,
+        move_keys: list[pygame.key],
+        interact_key: pygame.key,
+        pickup_key: pygame.key,
+        switch_key: pygame.key,
+        players: list[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
@@ -54,14 +61,26 @@ class PlayerKeySet:
             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.
         """
-        self.name = player_name
-        self.player_keys = keys
-        self.move_vectors = [[-1, 0], [1, 0], [0, -1], [0, 1]]
-        self.key_to_movement = {
-            key: vec for (key, vec) in zip(self.player_keys[:-2], self.move_vectors)
+        self.move_vectors: list[list[int]] = [[-1, 0], [1, 0], [0, -1], [0, 1]]
+        self.key_to_movement: dict[pygame.key, list[int]] = {
+            key: vec for (key, vec) in zip(move_keys, self.move_vectors)
         }
-        self.interact_key = self.player_keys[-2]
-        self.pickup_key = self.player_keys[-1]
+        self.move_keys: list[pygame.key] = move_keys
+        self.interact_key: pygame.key = interact_key
+        self.pickup_key: pygame.key = pickup_key
+        self.switch_key: pygame.key = switch_key
+        self.controlled_players: list[int] = players
+        self.current_player: int = players[0]
+
+    def set_controlled_players(self, controlled_players: list[int]) -> None:
+        self.controlled_players = controlled_players
+        self.current_player = self.controlled_players[0]
+
+    def next_player(self) -> None:
+        self.current_player += 1
+        if self.current_player > self.controlled_players[-1]:
+            self.current_player = self.controlled_players[0]
+        print(self.current_player, self.controlled_players)
 
 
 class PyGameGUI:
@@ -69,8 +88,6 @@ class PyGameGUI:
 
     def __init__(
         self,
-        player_names: list[str | int],
-        player_keys: list[pygame.key],
         url: str,
         port: int,
         manager_ids: list[str],
@@ -79,15 +96,8 @@ class PyGameGUI:
         self.FPS = 60
         self.running = True
 
-        self.player_names = player_names
-        self.player_keys = player_keys
-
-        self.player_key_sets: list[PlayerKeySet] = [
-            PlayerKeySet(player_name, keys)
-            for player_name, keys in zip(
-                self.player_names, self.player_keys[: len(self.player_names)]
-            )
-        ]
+        self.reset_gui_values()
+        self.key_sets: list[PlayerKeySet] = self.setup_player_keys(1)
 
         self.websocket_url = f"ws://{url}:{port}/ws/player/"
         self.websockets = {}
@@ -124,7 +134,6 @@ class PyGameGUI:
         self.manager: pygame_gui.UIManager
 
         self.vis = Visualizer(self.visualization_config)
-        self.vis.create_player_colors(len(self.player_names))
 
     def get_window_sizes(self, state: dict):
         kitchen_width = state["kitchen"]["width"]
@@ -167,23 +176,53 @@ class PyGameGUI:
             grid_size,
         )
 
+    def setup_player_keys(self, n=1, disjunct=False):
+        key_set1 = PlayerKeySet(
+            move_keys=[pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s],
+            interact_key=pygame.K_f,
+            pickup_key=pygame.K_e,
+            switch_key=pygame.K_SPACE,
+            players=list(range(self.number_humans_to_be_added)),
+        )
+        key_set2 = PlayerKeySet(
+            move_keys=[pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN],
+            interact_key=pygame.K_i,
+            pickup_key=pygame.K_o,
+            switch_key=pygame.K_p,
+            players=list(range(self.number_humans_to_be_added)),
+        )
+        key_sets = [key_set1, key_set2]
+
+        if disjunct:
+            split_idx = int(np.ceil(self.number_humans_to_be_added / 2))
+            key_set1.set_controlled_players(list(range(0, split_idx)))
+            key_set2.set_controlled_players(
+                list(range(split_idx, self.number_humans_to_be_added))
+            )
+        return key_sets[:n]
+
     def handle_keys(self):
         """Handles keyboard inputs. Sends action for the respective players. When a key is held down, every frame
         an action is sent in this function.
         """
+
         keys = pygame.key.get_pressed()
-        for player_idx, key_set in enumerate(self.player_key_sets):
-            relevant_keys = [keys[k] for k in key_set.player_keys]
-            if any(relevant_keys[:-2]):
+        for key_set in self.key_sets:
+            current_player_name = str(key_set.current_player)
+            relevant_keys = [keys[k] for k in key_set.move_keys]
+            if any(relevant_keys):
                 move_vec = np.zeros(2)
-                for idx, pressed in enumerate(relevant_keys[:-2]):
+                for idx, pressed in enumerate(relevant_keys):
                     if pressed:
                         move_vec += key_set.move_vectors[idx]
                 if np.linalg.norm(move_vec) != 0:
                     move_vec = move_vec / np.linalg.norm(move_vec)
 
                 action = Action(
-                    key_set.name, ActionType.MOVEMENT, move_vec, duration=1 / self.FPS
+                    current_player_name,
+                    ActionType.MOVEMENT,
+                    move_vec,
+                    duration=1 / self.FPS,
                 )
                 self.send_action(action)
 
@@ -195,22 +234,27 @@ class PyGameGUI:
         Args:
             event: Pygame event for extracting the key action.
         """
-        for key_set in self.player_key_sets:
+
+        for key_set in self.key_sets:
+            current_player_name = str(key_set.current_player)
             if event.key == key_set.pickup_key and event.type == pygame.KEYDOWN:
-                action = Action(key_set.name, ActionType.PUT, "pickup")
+                action = Action(current_player_name, ActionType.PUT, "pickup")
                 self.send_action(action)
 
             if event.key == key_set.interact_key:
                 if event.type == pygame.KEYDOWN:
                     action = Action(
-                        key_set.name, ActionType.INTERACT, InterActionData.START
+                        current_player_name, ActionType.INTERACT, InterActionData.START
                     )
                     self.send_action(action)
                 elif event.type == pygame.KEYUP:
                     action = Action(
-                        key_set.name, ActionType.INTERACT, InterActionData.STOP
+                        current_player_name, ActionType.INTERACT, InterActionData.STOP
                     )
                     self.send_action(action)
+            if event.key == key_set.switch_key:
+                if event.type == pygame.KEYDOWN:
+                    key_set.next_player()
 
     def init_ui_elements(self):
         self.manager = pygame_gui.UIManager((self.window_width, self.window_height))
@@ -218,28 +262,28 @@ class PyGameGUI:
 
         self.start_button = pygame_gui.elements.UIButton(
             relative_rect=pygame.Rect(
-                (
-                    (self.window_width // 2) - self.buttons_width // 2,
-                    (self.window_height / 2) - self.buttons_height // 2,
-                ),
-                (self.buttons_width, self.buttons_height),
+                (0, 0), (self.buttons_width, self.buttons_height)
             ),
             text="Start Game",
             manager=self.manager,
+            anchors={"center": "center"},
         )
         self.start_button.can_hover()
 
-        self.quit_button = pygame_gui.elements.UIButton(
-            relative_rect=pygame.Rect(
-                (
-                    (self.window_width - self.buttons_width),
-                    0,
-                ),
-                (self.buttons_width, self.buttons_height),
+        quit_rect = pygame.Rect(
+            (
+                0,
+                0,
             ),
+            (self.buttons_width, self.buttons_height),
+        )
+        quit_rect.topright = (0, 0)
+        self.quit_button = pygame_gui.elements.UIButton(
+            relative_rect=quit_rect,
             text="Quit Game",
             manager=self.manager,
             object_id="#quit_button",
+            anchors={"right": "right", "top": "top"},
         )
         self.quit_button.can_hover()
 
@@ -340,6 +384,148 @@ class PyGameGUI:
             object_id="#score_label",
         )
 
+        player_selection_rect = pygame.Rect(
+            (0, 0),
+            (
+                self.window_width,
+                (self.window_height // 2) - (self.buttons_height // 2),
+            ),
+        )
+        player_selection_rect.bottom = 0
+        self.player_selection_container = pygame_gui.elements.UIPanel(
+            player_selection_rect,
+            manager=self.manager,
+            object_id="#players",
+            anchors={"bottom": "bottom", "centerx": "centerx"},
+        )
+
+        multiple_keysets_button_rect = pygame.Rect((0, 0), (210, 50))
+        self.multiple_keysets_button = pygame_gui.elements.UIButton(
+            relative_rect=multiple_keysets_button_rect,
+            manager=self.manager,
+            container=self.player_selection_container,
+            text="not set",
+            anchors={"left": "left", "centery": "centery"},
+            object_id="#wasd",
+        )
+
+        split_players_button_rect = pygame.Rect((0, 0), (210, 50))
+        self.split_players_button = pygame_gui.elements.UIButton(
+            relative_rect=split_players_button_rect,
+            manager=self.manager,
+            container=self.player_selection_container,
+            text="not set",
+            anchors={"centerx": "centerx", "centery": "centery"},
+            object_id="#checkbox_split",
+        )
+        if self.multiple_keysets:
+            self.split_players_button.show()
+        else:
+            self.split_players_button.hide()
+
+        xbox_controller_button_rect = pygame.Rect((0, 0), (210, 50))
+        xbox_controller_button_rect.right = 0
+        self.xbox_controller_button = pygame_gui.elements.UIButton(
+            relative_rect=xbox_controller_button_rect,
+            manager=self.manager,
+            container=self.player_selection_container,
+            text="Use game controller?",
+            anchors={"right": "right", "centery": "centery"},
+            object_id="#controller",
+        )
+
+        players_container_rect = pygame.Rect(
+            (0, 0),
+            (500, self.player_selection_container.get_abs_rect().height // 3),
+        )
+        self.players_container = pygame_gui.elements.UIPanel(
+            relative_rect=players_container_rect,
+            manager=self.manager,
+            object_id="#players_players",
+            container=self.player_selection_container,
+            anchors={"top": "top", "centerx": "centerx"},
+        )
+
+        bot_container_rect = pygame.Rect(
+            (0, 0),
+            (500, self.player_selection_container.get_abs_rect().height // 3),
+        )
+        bot_container_rect.bottom = 0
+        self.bots_container = pygame_gui.elements.UIPanel(
+            relative_rect=bot_container_rect,
+            manager=self.manager,
+            object_id="#players_bots",
+            container=self.player_selection_container,
+            anchors={"bottom": "bottom", "centerx": "centerx"},
+        )
+
+        number_players_rect = pygame.Rect((0, 0), (200, 200))
+        self.added_players_label = pygame_gui.elements.UILabel(
+            number_players_rect,
+            manager=self.manager,
+            container=self.players_container,
+            text=f"Humans to be added: {self.number_humans_to_be_added}",
+            anchors={"center": "center"},
+        )
+
+        number_bots_rect = pygame.Rect((0, 0), (200, 200))
+        self.added_bots_label = pygame_gui.elements.UILabel(
+            number_bots_rect,
+            manager=self.manager,
+            container=self.bots_container,
+            text=f"Bots to be added: {self.number_bots_to_be_added}",
+            anchors={"center": "center"},
+        )
+
+        size = 70
+        add_player_button_rect = pygame.Rect((0, 0), (size, size))
+        add_player_button_rect.right = 0
+        self.add_human_player_button = pygame_gui.elements.UIButton(
+            relative_rect=add_player_button_rect,
+            text="+",
+            manager=self.manager,
+            object_id="#add_player",
+            container=self.players_container,
+            anchors={"right": "right", "centery": "centery"},
+        )
+        self.add_human_player_button.can_hover()
+
+        remove_player_button_rect = pygame.Rect((0, 0), (size, size))
+        remove_player_button_rect.left = 0
+        self.remove_human_button = pygame_gui.elements.UIButton(
+            relative_rect=remove_player_button_rect,
+            text="-",
+            manager=self.manager,
+            object_id="#remove_player",
+            container=self.players_container,
+            anchors={"left": "left", "centery": "centery"},
+        )
+        self.remove_human_button.can_hover()
+
+        add_bot_button_rect = pygame.Rect((0, 0), (size, size))
+        add_bot_button_rect.right = 0
+        self.add_bot_button = pygame_gui.elements.UIButton(
+            relative_rect=add_bot_button_rect,
+            text="+",
+            manager=self.manager,
+            object_id="#add_bot",
+            container=self.bots_container,
+            anchors={"right": "right", "centery": "centery"},
+        )
+        self.add_bot_button.can_hover()
+
+        remove_bot_button_rect = pygame.Rect((0, 0), (size, size))
+        remove_bot_button_rect.left = 0
+        self.remove_bot_button = pygame_gui.elements.UIButton(
+            relative_rect=remove_bot_button_rect,
+            text="-",
+            manager=self.manager,
+            object_id="#remove_bot",
+            container=self.bots_container,
+            anchors={"left": "left", "centery": "centery"},
+        )
+        self.remove_bot_button.can_hover()
+
     def draw(self, state):
         """Main visualization function.
 
@@ -348,6 +534,7 @@ class PyGameGUI:
             self.game_screen,
             state,
             self.grid_size,
+            [k.current_player for k in self.key_sets],
         )
 
         # self.manager.draw_ui(self.main_window)
@@ -414,6 +601,8 @@ class PyGameGUI:
                 self.timer_label.hide()
                 self.orders_label.hide()
                 self.conclusion_label.hide()
+
+                self.player_selection_container.show()
             case MenuStates.Game:
                 self.start_button.hide()
                 self.back_button.hide()
@@ -425,6 +614,9 @@ class PyGameGUI:
                 self.timer_label.show()
                 self.orders_label.show()
                 self.conclusion_label.hide()
+
+                self.player_selection_container.hide()
+
             case MenuStates.End:
                 self.start_button.hide()
                 self.back_button.show()
@@ -436,6 +628,8 @@ class PyGameGUI:
                 self.orders_label.hide()
                 self.conclusion_label.show()
 
+                self.player_selection_container.hide()
+
     def update_score_label(self, state):
         score = state["score"]
         self.score_label.set_text(f"Score {score}")
@@ -460,9 +654,10 @@ class PyGameGUI:
             layout = file.read()
         with open(environment_config_path, "r") as file:
             environment_config = file.read()
+
         creation_json = CreateEnvironmentConfig(
             manager_id=self.manager_id,
-            number_players=2,
+            number_players=self.number_players,
             environment_settings={"all_player_can_pause_game": False},
             item_info_config=item_info,
             environment_config=environment_config,
@@ -503,6 +698,20 @@ class PyGameGUI:
     def start_button_press(self):
         self.menu_state = MenuStates.Game
 
+        self.number_players = (
+            self.number_humans_to_be_added + self.number_bots_to_be_added
+        )
+        self.vis.create_player_colors(self.number_players)
+
+        if self.split_players:
+            assert (
+                self.number_humans_to_be_added > 1
+            ), "Not enough players for key configuration."
+        num_key_set = 2 if self.multiple_keysets else 1
+        self.key_sets = self.setup_player_keys(
+            max(self.number_players, num_key_set), self.split_players
+        )
+
         self.setup_environment()
 
         self.set_window_size()
@@ -515,6 +724,9 @@ class PyGameGUI:
     def back_button_press(self):
         self.menu_state = MenuStates.Start
         self.reset_window_size()
+
+        self.reset_gui_values()
+
         log.debug("Pressed back button")
 
     def quit_button_press(self):
@@ -523,6 +735,8 @@ class PyGameGUI:
         log.debug("Pressed quit button")
 
     def reset_button_press(self):
+        # self.reset_gui_values()
+
         requests.post(
             f"{self.request_url}/manage/stop_env",
             json={
@@ -548,6 +762,31 @@ class PyGameGUI:
         self.reset_window_size()
         log.debug("Pressed finished button")
 
+    def reset_gui_values(self):
+        self.currently_controlled_player_idx = 0
+        self.number_humans_to_be_added = 1
+        self.number_bots_to_be_added = 0
+        self.split_players = False
+        self.multiple_keysets = False
+
+    def update_selection_elements(self):
+        text = "WASD+ARROW" if self.multiple_keysets else "WASD"
+        self.multiple_keysets_button.set_text(text)
+        self.split_players_button
+        self.added_players_label.set_text(
+            f"Humans to be added: {self.number_humans_to_be_added}"
+        )
+        self.added_bots_label.set_text(
+            f"Bots to be added: {self.number_bots_to_be_added}"
+        )
+        text = "Yes" if self.split_players else "No"
+        self.split_players_button.set_text(f"Split players: {text}")
+
+        if self.multiple_keysets:
+            self.split_players_button.show()
+        else:
+            self.split_players_button.hide()
+
     def send_action(self, action: Action):
         """Sends an action to the game environment.
 
@@ -583,8 +822,6 @@ class PyGameGUI:
                 }
             )
         )
-        # self.websocket.send(json.dumps("get_state"))
-        # state_dict = json.loads(self.websocket.recv())
         state = json.loads(self.websockets[self.state_player_id].recv())
         return state
 
@@ -606,6 +843,8 @@ class PyGameGUI:
         self.init_ui_elements()
         self.manage_button_visibility()
 
+        self.update_selection_elements()
+
         # Game loop
         self.running = True
         while self.running:
@@ -636,6 +875,28 @@ class PyGameGUI:
                                 self.disconnect_websockets()
                                 self.start_button_press()
 
+                            case self.add_human_player_button:
+                                self.number_humans_to_be_added += 1
+                            case self.remove_human_button:
+                                self.number_humans_to_be_added = max(
+                                    0, self.number_humans_to_be_added - 1
+                                )
+                            case self.add_bot_button:
+                                self.number_bots_to_be_added += 1
+                            case self.remove_bot_button:
+                                self.number_bots_to_be_added = max(
+                                    0, self.number_bots_to_be_added - 1
+                                )
+                            case self.multiple_keysets_button:
+                                self.multiple_keysets = not self.multiple_keysets
+                                self.split_players = False
+                            case self.split_players_button:
+                                self.split_players = not self.split_players
+                            case self.xbox_controller_button:
+                                print("xbox_controller_button pressed.")
+
+                        self.update_selection_elements()
+
                         self.manage_button_visibility()
 
                     if (
@@ -693,21 +954,7 @@ class PyGameGUI:
 
 
 def main(url: str, port: int, manager_ids: list[str]):
-    # TODO maybe read the player names and keyboard keys from config file?
-    keys1 = [
-        pygame.K_LEFT,
-        pygame.K_RIGHT,
-        pygame.K_UP,
-        pygame.K_DOWN,
-        pygame.K_SPACE,
-        pygame.K_i,
-    ]
-    keys2 = [pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s, pygame.K_f, pygame.K_e]
-
-    number_players = 2
     gui = PyGameGUI(
-        list(map(str, range(number_players))),
-        [keys1, keys2],
         url=url,
         port=port,
         manager_ids=manager_ids,