diff --git a/overcooked_simulator/game_content/environment_config.yaml b/overcooked_simulator/game_content/environment_config.yaml index e9db3f39d2c831ed0e9381455a9c92044dafd4af..158a22290759fa0415806ee59ce968972e07029c 100644 --- a/overcooked_simulator/game_content/environment_config.yaml +++ b/overcooked_simulator/game_content/environment_config.yaml @@ -1,6 +1,3 @@ -counter_side_length: 40 -world_width: 800 -world_height: 600 plates: clean_plates: 3 dirty_plates: 2 diff --git a/overcooked_simulator/game_content/layouts/basic.layout b/overcooked_simulator/game_content/layouts/basic.layout index 8b46829b755b1963fde61a396d395618070b3a21..9d755936dc28aebad0439d25e9d039c539393ab9 100644 --- a/overcooked_simulator/game_content/layouts/basic.layout +++ b/overcooked_simulator/game_content/layouts/basic.layout @@ -1,11 +1,10 @@ -_________________ -_#QU#TNLB#_______ -_#_______M_______ -_#_______#_______ -_W_______________ -_#__A__A_________ -_C_______________ -_C_______#_______ -_#_______X_______ -_#P#S+#S+#_______ -_________________ +#QU#TNLB# +#_______M +#_______# +W________ +#__A__A__ +C________ +C_______# +#_______X +#P#S+#S+# + diff --git a/overcooked_simulator/game_content/player_config.yaml b/overcooked_simulator/game_content/player_config.yaml index fb73f2d714674061cfb3626bc516071b23fd7b93..4ae0190c2e26d9925e43716d64a24f67c4880b82 100644 --- a/overcooked_simulator/game_content/player_config.yaml +++ b/overcooked_simulator/game_content/player_config.yaml @@ -1,3 +1,3 @@ radius: 0.4 -move_dist: 5 +move_dist: 0.1 interaction_range: 1.6 \ No newline at end of file diff --git a/overcooked_simulator/overcooked_environment.py b/overcooked_simulator/overcooked_environment.py index 8a51ecf4570d6eb912c7be00db3a2560a0ebe759..cd869d03c17f48f6584dfec36f65b2fddab04517 100644 --- a/overcooked_simulator/overcooked_environment.py +++ b/overcooked_simulator/overcooked_environment.py @@ -82,7 +82,7 @@ class Environment: with open(env_config_path, "r") as file: environment_config = yaml.safe_load(file) self.layout_path: Path = layout_path - self.counter_side_length = environment_config["counter_side_length"] + # self.counter_side_length = 1 # -> this changed! is 1 now self.item_info_path: Path = item_info_path self.item_info = self.load_item_info() @@ -118,6 +118,9 @@ class Environment: "+": SinkAddon, } + self.kitchen_height: int = 0 + self.kitchen_width: int = 0 + ( self.counters, self.designated_player_positions, @@ -128,9 +131,6 @@ class Environment: self.score: int = 0 - self.world_width: int = environment_config["world_width"] - self.world_height: int = environment_config["world_height"] - def load_item_info(self) -> dict[str, ItemInfo]: with open(self.item_info_path, "r") as file: item_lookup = yaml.safe_load(file) @@ -156,16 +156,20 @@ class Environment: Args: layout_file: Path to the layout file. """ - current_y: float = self.counter_side_length / 2 + current_y: float = 1.5 counters: list[Counter] = [] designated_player_positions: list[npt.NDArray] = [] free_positions: list[npt.NDArray] = [] + self.kitchen_width = 0 + with open(layout_file, "r") as layout_file: lines = layout_file.readlines() + self.kitchen_height = len(lines) + for line in lines: line = line.replace("\n", "").replace(" ", "") # remove newline char - current_x = self.counter_side_length / 2 + current_x = 1.5 for character in line: character = character.capitalize() pos = np.array([current_x, current_y]) @@ -180,8 +184,13 @@ class Environment: ) elif counter_class == "Free": free_positions.append(np.array([current_x, current_y])) - current_x += self.counter_side_length - current_y += self.counter_side_length + current_x += 1 + if current_x > self.kitchen_width: + self.kitchen_width = current_x + current_y += 1 + + self.kitchen_height = int(self.kitchen_height + 1.5) + self.kitchen_width = int(self.kitchen_width + 0.5) return counters, designated_player_positions, free_positions @@ -331,9 +340,7 @@ class Environment: other_players = filter(lambda p: p.name != player.name, self.players.values()) def collide(p): - return np.linalg.norm(player.pos - p.pos) <= ( - player.radius * self.counter_side_length - ) + (p.radius * self.counter_side_length) + return np.linalg.norm(player.pos - p.pos) <= (player.radius) + (p.radius) return list(filter(collide, other_players)) @@ -388,16 +395,15 @@ class Environment: Returns: True if player and counter overlap, False if not. """ - size = self.counter_side_length cx, cy = player.pos - dx = max(np.abs(cx - counter.pos[0]) - size / 2, 0) - dy = max(np.abs(cy - counter.pos[1]) - size / 2, 0) + dx = max(np.abs(cx - counter.pos[0]) - 1 / 2, 0) + dy = max(np.abs(cy - counter.pos[1]) - 1 / 2, 0) distance = np.linalg.norm([dx, dy]) - return distance < (player.radius * self.counter_side_length) + return distance < (player.radius) def add_player(self, player_name: str, pos: npt.NDArray = None): log.debug(f"Add player {player_name} to the game") - player = Player(player_name, self.counter_side_length, pos) + player = Player(player_name, pos) self.players[player.name] = player if player.pos is None: if len(self.designated_player_positions) > 0: @@ -420,12 +426,9 @@ class Environment: Returns: True if the player touches the world bounds, False if not. """ - collisions_lower = any( - (player.pos - (player.radius * self.counter_side_length)) < 0 - ) + collisions_lower = any((player.pos - (player.radius)) < 0) collisions_upper = any( - (player.pos + (player.radius * self.counter_side_length)) - > [self.world_width, self.world_height] + (player.pos + (player.radius)) > [self.kitchen_width, self.kitchen_height] ) return collisions_lower or collisions_upper @@ -467,9 +470,7 @@ class Environment: case Sink(pos=pos): assert len(sink_addons) > 0, "No SinkAddon but normal Sink" closest_addon = self.get_closest(pos, sink_addons) - assert self.counter_side_length - ( - self.counter_side_length * 0.05 - ) <= np.linalg.norm( + assert 1 - (1 * 0.05) <= np.linalg.norm( closest_addon.pos - pos ), f"No SinkAddon connected to Sink at pos {pos}" counter.set_addon(closest_addon) diff --git a/overcooked_simulator/player.py b/overcooked_simulator/player.py index c4b5fbaaf3db37ec31c9b18ccc5ced63f93dceb9..4f85046ff9a100c8b0b95a43246a9acccaff4b04 100644 --- a/overcooked_simulator/player.py +++ b/overcooked_simulator/player.py @@ -24,7 +24,6 @@ class Player: def __init__( self, name: str, - grid_size: int, pos: Optional[npt.NDArray[float]] = None, ): self.name: str = name @@ -42,7 +41,6 @@ class Player: self.player_config = yaml.safe_load(file) self.radius: float = self.player_config["radius"] - self.grid_size: int = grid_size self.move_dist: int = self.player_config["move_dist"] self.interaction_range: int = self.player_config["interaction_range"] self.facing_direction: npt.NDArray[float] = np.array([0, 1]) @@ -85,9 +83,7 @@ class Player: self.update_facing_point() def update_facing_point(self): - self.facing_point = self.pos + ( - self.facing_direction * self.radius * self.grid_size * 0.5 - ) + self.facing_point = self.pos + (self.facing_direction * self.radius * 0.5) def can_reach(self, counter: Counter): """Checks whether the player can reach the counter in question. Simple check if the distance is not larger @@ -99,9 +95,7 @@ class Player: Returns: True if the counter is in range of the player, False if not. """ - return np.linalg.norm(counter.pos - self.facing_point) <= ( - self.interaction_range * self.grid_size - ) + return np.linalg.norm(counter.pos - self.facing_point) <= self.interaction_range def pick_action(self, counter: Counter): """Performs the pickup-action with the counter. Handles the logic of what the player is currently holding, diff --git a/overcooked_simulator/pygame_gui/pygame_gui.py b/overcooked_simulator/pygame_gui/pygame_gui.py index a723373f619811ed24b4d4d10e0cb348239ad677..9c4dc97e43ee2aeeab85988cff58fc749e2fa841 100644 --- a/overcooked_simulator/pygame_gui/pygame_gui.py +++ b/overcooked_simulator/pygame_gui/pygame_gui.py @@ -89,10 +89,10 @@ class PyGameGUI: self.screen = None self.FPS = 60 self.simulator = simulator - self.counter_size = self.simulator.env.counter_side_length + self.grid_size = 40 self.window_width, self.window_height = ( - simulator.env.world_width, - simulator.env.world_height, + simulator.env.kitchen_width * self.grid_size, + simulator.env.kitchen_height * self.grid_size, ) self.player_names = player_names @@ -183,7 +183,7 @@ class PyGameGUI: def draw_background(self): """Visualizes a game background.""" - block_size = self.counter_size // 2 # Set the size of the grid block + block_size = self.grid_size // 2 # Set the size of the grid block for x in range(0, self.window_width, block_size): for y in range(0, self.window_height, block_size): rect = pygame.Rect(x, y, block_size, block_size) @@ -219,19 +219,20 @@ class PyGameGUI: state: The game state returned by the environment. """ for p_idx, player in enumerate(state["players"].values()): + pos = player.pos * self.grid_size + if USE_PLAYER_COOK_SPRITES: img_path = self.visualization_config["Cook"]["parts"][0]["path"] rel_x, rel_y = player.facing_direction angle = -np.rad2deg(math.atan2(rel_y, rel_x)) + 90 size = ( self.visualization_config["Cook"]["parts"][0]["size"] - * self.counter_size + * self.grid_size ) - self.draw_image(img_path, size, player.pos, angle) + self.draw_image(img_path, size, pos, angle) else: - pos = player.pos - size = player.radius * self.counter_size + size = player.radius * self.grid_size color1 = self.player_colors[p_idx] color2 = colors["white"] @@ -239,21 +240,20 @@ class PyGameGUI: pygame.draw.circle(self.screen, BLUE, pos, size, width=1) pygame.draw.circle(self.screen, colors[color1], pos, size // 2) - pos = player.pos facing = player.facing_direction pygame.draw.polygon( self.screen, BLUE, ( ( - pos[0] + (facing[1] * 0.1 * self.counter_size), - pos[1] - (facing[0] * 0.1 * self.counter_size), + pos[0] + (facing[1] * 0.1 * self.grid_size), + pos[1] - (facing[0] * 0.1 * self.grid_size), ), ( - pos[0] - (facing[1] * 0.1 * self.counter_size), - pos[1] + (facing[0] * 0.1 * self.counter_size), + pos[0] - (facing[1] * 0.1 * self.grid_size), + pos[1] + (facing[0] * 0.1 * self.grid_size), ), - player.pos + (facing * 0.5 * self.counter_size), + pos + (facing * 0.5 * self.grid_size), ), ) @@ -261,11 +261,13 @@ class PyGameGUI: pygame.draw.circle( self.screen, BLUE, - player.facing_point, - player.interaction_range * self.counter_size, + player.facing_point * self.grid_size, + player.interaction_range * self.grid_size, width=1, ) - pygame.draw.circle(self.screen, colors["red1"], player.facing_point, 4) + pygame.draw.circle( + self.screen, colors["red1"], player.facing_point * self.grid_size, 4 + ) if player.holding is not None: holding_item_pos = player.pos + (20 * player.facing_direction) @@ -273,14 +275,15 @@ class PyGameGUI: if player.current_nearest_counter: counter: Counter = player.current_nearest_counter + pos = counter.pos * self.grid_size pygame.draw.rect( self.screen, colors[self.player_colors[p_idx]], rect=pygame.Rect( - counter.pos[0] - (self.counter_size // 2), - counter.pos[1] - (self.counter_size // 2), - self.counter_size, - self.counter_size, + pos[0] - (self.grid_size // 2), + pos[1] - (self.grid_size // 2), + self.grid_size, + self.grid_size, ), width=2, ) @@ -295,40 +298,44 @@ class PyGameGUI: parts: The visual parts to draw. scale: Rescale the item by this factor. """ + for part in parts: part_type = part["type"] - if part_type == "image": - self.draw_image( - parts[0]["path"], parts[0]["size"] * scale * self.counter_size, pos - ) - elif part_type == "rect": - height = part["height"] * self.counter_size - width = part["width"] * self.counter_size - color = part["color"] - if "center_offset" in part: - dx, dy = np.array(part["center_offset"]) * self.counter_size - rect = pygame.Rect(pos[0] + dx, pos[1] + dy, height, width) - pygame.draw.rect(self.screen, color, rect) - else: - rect = pygame.Rect( - pos[0] - (height / 2), - pos[1] - (width / 2), - height, - width, + match part_type: + case "image": + self.draw_image( + parts[0]["path"], + parts[0]["size"] * scale * self.grid_size, + pos, ) - pygame.draw.rect(self.screen, color, rect) - elif part_type == "circle": - radius = part["radius"] * self.counter_size - color = colors[part["color"]] - if "center_offset" in part: - pygame.draw.circle( - self.screen, - color, - pos + np.array(part["center_offset"]), - radius, - ) - else: - pygame.draw.circle(self.screen, color, pos, radius) + case "rect": + height = part["height"] * self.grid_size + width = part["width"] * self.grid_size + color = part["color"] + if "center_offset" in part: + dx, dy = np.array(part["center_offset"]) * self.grid_size + rect = pygame.Rect(pos[0] + dx, pos[1] + dy, height, width) + pygame.draw.rect(self.screen, color, rect) + else: + rect = pygame.Rect( + pos[0] - (height / 2), + pos[1] - (width / 2), + height, + width, + ) + pygame.draw.rect(self.screen, color, rect) + case "circle": + radius = part["radius"] * self.grid_size + color = colors[part["color"]] + if "center_offset" in part: + pygame.draw.circle( + self.screen, + color, + (pos * self.grid_size) + np.array(part["center_offset"]), + radius, + ) + else: + pygame.draw.circle(self.screen, color, pos, radius) def draw_item(self, pos: npt.NDArray[float], item: Item, scale: float = 1.0): """Visualization of an item at the specified position. On a counter or in the hands of the player. @@ -365,11 +372,12 @@ class PyGameGUI: def draw_progress_bar(self, pos, current, needed): """Visualize progress of progressing item as a green bar under the item.""" if current != 0: - bar_height = self.counter_size * 0.2 - progress_width = (current / needed) * self.counter_size + pos = pos * self.grid_size + bar_height = self.grid_size * 0.2 + progress_width = (current / needed) * self.grid_size progress_bar = pygame.Rect( - pos[0] - (self.counter_size / 2), - pos[1] - (self.counter_size / 2) + self.counter_size - bar_height, + pos[0] - (self.grid_size / 2), + pos[1] - (self.grid_size / 2) + self.grid_size - bar_height, progress_width, bar_height, ) @@ -384,14 +392,14 @@ class PyGameGUI: counter: The counter to visualize. """ - self.draw_thing(counter.pos, self.visualization_config["Counter"]["parts"]) + pos = counter.pos * self.grid_size + + self.draw_thing(pos, self.visualization_config["Counter"]["parts"]) if str(counter) in self.visualization_config: - self.draw_thing( - counter.pos, self.visualization_config[str(counter)]["parts"] - ) + self.draw_thing(pos, self.visualization_config[str(counter)]["parts"]) else: self.draw_thing( - counter.pos, + pos, self.visualization_config[counter.__class__.__name__]["parts"], ) @@ -400,12 +408,10 @@ class PyGameGUI: if isinstance(counter.occupied_by, (list, deque)): with self.simulator.env.lock: for i, o in enumerate(counter.occupied_by): - self.draw_item( - np.abs([counter.pos[0], counter.pos[1] - (i * 3)]), o - ) + self.draw_item(np.abs([pos[0], pos[1] - (i * 3)]), o) # All other items: else: - self.draw_item(counter.pos, counter.occupied_by) + self.draw_item(pos, counter.occupied_by) def draw_counters(self, state): """Visualizes the counters in the environment. @@ -416,7 +422,9 @@ class PyGameGUI: for counter in state["counters"]: self.draw_counter(counter) if SHOW_COUNTER_CENTERS: - pygame.draw.circle(self.screen, colors["green1"], counter.pos, 3) + pygame.draw.circle( + self.screen, colors["green1"], counter.pos * self.grid_size, 3 + ) def draw(self, state): """Main visualization function.