diff --git a/overcooked_simulator/counters.py b/overcooked_simulator/counters.py index 742b9bb166953ebf2c4a9f1ec535fc2042cdb873..aa372ed9d4beb57dda8a34097fa967497eca375c 100644 --- a/overcooked_simulator/counters.py +++ b/overcooked_simulator/counters.py @@ -2,7 +2,13 @@ from typing import Optional import numpy as np -from overcooked_simulator.game_items import CuttableItem, HoldableItem +from overcooked_simulator.game_items import ( + CuttableItem, + HoldableItem, + ProgressibleItem, + Plate, + Tomato, +) class Counter: @@ -90,3 +96,72 @@ class CuttingBoard(Counter): def __repr__(self): return f"CuttingBoard({self.occupied_by})" + + +class ServingWindow(Counter): + def drop_off(self, item): + return 5 + + def can_score(self, item): + if isinstance(item, Plate) and isinstance(item.holds, ProgressibleItem): + return item.holds.finished + + def can_drop_off(self, item: HoldableItem): + return self.can_score(item) + + def pick_up(self): + return None + + def __repr__(self): + return "ServingWindow" + + +class PlateReturn(Counter): + def __init__(self, pos): + super().__init__(pos) + self.occupied_by = Plate() + + def pick_up(self): + return Plate() + + def drop_off(self, item): + return 0 + + def can_drop_off(self, item): + return False + + def __repr__(self): + return "PlateReturn" + + +class TomatoDispenser(Counter): + def __init__(self, pos): + super().__init__(pos) + + def pick_up(self): + return Tomato() + + def drop_off(self, item: HoldableItem): + return 0 + + def can_drop_off(self, item: HoldableItem): + return False + + def __repr__(self): + return f"{self.occupied_by}Dispenser" + + +class Trash(Counter): + def pick_up(self): + pass + + def drop_off(self, item: HoldableItem): + if isinstance(item, Plate): + item.holds = None + return -1 + + def can_drop_off(self, item: HoldableItem): + return True + + def __repr__(self): + return "Trash" diff --git a/overcooked_simulator/game_items.py b/overcooked_simulator/game_items.py index a40ad99dfa52abe17e6f2552c59cbc10dd54af7b..b713fbfdab08d1e5cd666e4cd0fac8c79327753c 100644 --- a/overcooked_simulator/game_items.py +++ b/overcooked_simulator/game_items.py @@ -17,10 +17,8 @@ class Plate(HoldableItem): super().__init__() - def can_combine(self, other): - if self.holds is None: - if isinstance(other, HoldableItem): - return True + def can_combine(self, other: HoldableItem): + return self.holds is None def combine(self, other): self.holds = other diff --git a/overcooked_simulator/layouts/basic.layout b/overcooked_simulator/layouts/basic.layout index beb5fc01cf72d2bb19013bbfa5e0ed89cde2e76f..d4d883fc230af82331dec09ce59a95c7d205da68 100644 --- a/overcooked_simulator/layouts/basic.layout +++ b/overcooked_simulator/layouts/basic.layout @@ -1,11 +1,11 @@ EEEEEEEEEEE -ECCCCCCCCCE +ECCCCTCCCCE ECEEEEEEECE ECEEEEEEECE +EWEEEEEEEEE ECEEEEEEEEE -ECEEEEEEEEE -ECEEEEEEEEE -ECEEEEEEECE +EPEEEEEEEEE ECEEEEEEECE +ECEEEEEEEXE ECCBBCCCCCE EEEEEEEEEEE diff --git a/overcooked_simulator/main.py b/overcooked_simulator/main.py index 9530a40e3a6ed17f61ee486627d19ec5543f8224..b3fa9d422547a6355eb8e0b2a07b71e820b89c0e 100644 --- a/overcooked_simulator/main.py +++ b/overcooked_simulator/main.py @@ -15,13 +15,8 @@ def main(): simulator = Simulator(Path(ROOT_DIR, "layouts", "basic.layout"), 600) player_one_name = "p1" player_two_name = "p2" - simulator.register_player(Player(player_one_name, np.array([100, 200]))) - simulator.register_player(Player(player_two_name, np.array([200, 100]))) - - simulator.env.counters[3].occupied_by = Tomato() - simulator.env.counters[4].occupied_by = Tomato() - simulator.env.counters[6].occupied_by = Plate() - simulator.env.counters[7].occupied_by = Plate() + simulator.register_player(Player(player_one_name, np.array([200, 200]))) + simulator.register_player(Player(player_two_name, np.array([100, 200]))) # TODO maybe read the player names and keyboard keys from config file? keys1 = [ diff --git a/overcooked_simulator/overcooked_environment.py b/overcooked_simulator/overcooked_environment.py index 8aa9f198f2f51e6da32f4eea9cf825dd9c0554c7..8245fafabcba77786f4b940edea04bfe8bc55224 100644 --- a/overcooked_simulator/overcooked_environment.py +++ b/overcooked_simulator/overcooked_environment.py @@ -7,7 +7,24 @@ if TYPE_CHECKING: from pathlib import Path import numpy as np from scipy.spatial import distance_matrix -from overcooked_simulator.counters import Counter, CuttingBoard +from overcooked_simulator.counters import ( + Counter, + CuttingBoard, + Trash, + ServingWindow, + TomatoDispenser, + PlateReturn, +) + +SYMBOL_TO_CHARACTER_MAP = { + "C": Counter, + "B": CuttingBoard, + "X": Trash, + "W": ServingWindow, + "T": TomatoDispenser, + "P": PlateReturn, + "E": None, +} class Action: @@ -62,15 +79,11 @@ class Environment: current_x = self.counter_side_length / 2 for character in line: character = character.capitalize() - match character: - case "C": - counter = Counter(np.array([current_x, current_y])) - counters.append(counter) - case "B": - counter = CuttingBoard(np.array([current_x, current_y])) - counters.append(counter) - case "E": - pass + pos = np.array([current_x, current_y]) + counter_class = SYMBOL_TO_CHARACTER_MAP[character] + if counter_class is not None: + counter = counter_class(pos) + counters.append(counter) current_x += self.counter_side_length current_y += self.counter_side_length return counters @@ -183,9 +196,9 @@ class Environment: Returns: True if the player is intersecting with any object in the environment. """ return ( - self.detect_player_collision(player) - or self.detect_collision_counters(player) - or self.detect_collision_world_bounds(player) + self.detect_player_collision(player) + or self.detect_collision_counters(player) + or self.detect_collision_world_bounds(player) ) def detect_player_collision(self, player: Player): diff --git a/overcooked_simulator/player.py b/overcooked_simulator/player.py index 48dd8c443b7d59e4721d4e2f4f4e405a1c58ee39..971f90241d5d81144bf7432170c893b6c54759bd 100644 --- a/overcooked_simulator/player.py +++ b/overcooked_simulator/player.py @@ -2,8 +2,8 @@ from typing import Optional import numpy as np -from overcooked_simulator.counters import Counter -from overcooked_simulator.game_items import HoldableItem +from overcooked_simulator.counters import Counter, Trash +from overcooked_simulator.game_items import HoldableItem, Plate class Player: @@ -72,12 +72,16 @@ class Player: Args: counter: The counter to pick things up from or put things down. """ + if self.holding is None: self.holding = counter.pick_up() elif counter.can_drop_off(self.holding): - counter.drop_off(self.holding) - self.holding = None + if isinstance(counter, Trash) and isinstance(self.holding, Plate): + self.holding.holds = None + else: + counter.drop_off(self.holding) + self.holding = None elif self.holding.can_combine(counter.occupied_by): returned_by_counter = counter.pick_up() diff --git a/overcooked_simulator/pygame_gui/images/plate.png b/overcooked_simulator/pygame_gui/images/plate.png new file mode 100644 index 0000000000000000000000000000000000000000..7d4aee53f95bf58477937de9e00ab78f87850144 Binary files /dev/null and b/overcooked_simulator/pygame_gui/images/plate.png differ diff --git a/overcooked_simulator/pygame_gui/pygame_gui.py b/overcooked_simulator/pygame_gui/pygame_gui.py index 440cdd37a42a63703dfe000a4cd56f6c34fc1dc6..6151e63514156bd20961b7a41295a8128e694642 100644 --- a/overcooked_simulator/pygame_gui/pygame_gui.py +++ b/overcooked_simulator/pygame_gui/pygame_gui.py @@ -4,7 +4,13 @@ import numpy as np import pygame from overcooked_simulator import ROOT_DIR -from overcooked_simulator.counters import CuttingBoard +from overcooked_simulator.counters import ( + CuttingBoard, + Trash, + TomatoDispenser, + PlateReturn, + ServingWindow, +) from overcooked_simulator.game_items import ProgressibleItem, Plate from overcooked_simulator.game_items import Tomato from overcooked_simulator.overcooked_environment import Action @@ -22,6 +28,8 @@ YELLOW = (255, 255, 0) BACKGROUND_COLOR = GREY BACKGROUND_LINES_COLOR = (200, 200, 200) KNIFE_COLOR = (120, 120, 120) +PLATE_RETURN_COLOR = (170, 170, 240) +BOARD_COLOR = (239, 193, 151) class PlayerKeyset: @@ -231,12 +239,49 @@ class PyGameGUI: board_size, board_size, ) - BOARD_COLOR = (239, 193, 151) pygame.draw.rect(self.screen, BOARD_COLOR, board_rect) knife_rect = pygame.Rect(counter.pos[0] + 6, counter.pos[1] - 8, 5, 20) pygame.draw.rect(self.screen, KNIFE_COLOR, knife_rect) + if isinstance(counter, PlateReturn): + size = 38 + inner = pygame.Rect( + counter.pos[0] - (size / 2), + counter.pos[1] - (size / 2), + size, + size, + ) + pygame.draw.rect(self.screen, PLATE_RETURN_COLOR, inner) + + if isinstance(counter, Trash): + pygame.draw.circle( + self.screen, + (80, 80, 80), + counter.pos, + self.counter_size * 0.4, + ) + pygame.draw.circle(self.screen, BLACK, counter.pos, self.counter_size * 0.3) + if isinstance(counter, TomatoDispenser): + board_size = 32 + board_rect = pygame.Rect( + counter.pos[0] - (board_size / 2), + counter.pos[1] - (board_size / 2), + board_size, + board_size, + ) + pygame.draw.rect(self.screen, RED, board_rect) + self.draw_item(counter.pos, Tomato()) + if isinstance(counter, ServingWindow): + board_size = 33 + board_rect = pygame.Rect( + counter.pos[0] - (board_size / 2), + counter.pos[1] - (board_size / 2), + board_size, + board_size, + ) + pygame.draw.rect(self.screen, YELLOW, board_rect) + if counter.occupied_by is not None: self.draw_item(counter.pos, counter.occupied_by)