Skip to content
Snippets Groups Projects
Commit 43e2ed9e authored by Fabian Heinrich's avatar Fabian Heinrich
Browse files

Renamed Cutted... to Chopped...,

Moved item und counter visualization composition to yaml file. For now directly read in from yaml dict.
parent d0d9e558
No related branches found
No related tags found
1 merge request!1340-visualisierungsregeln
Pipeline #41836 passed
...@@ -62,7 +62,7 @@ class ProgressibleItem: ...@@ -62,7 +62,7 @@ class ProgressibleItem:
self.steps_needed = steps_needed self.steps_needed = steps_needed
self.finished = finished self.finished = finished
self.finished_name = ( self.finished_name = (
f"Cutted{self.name}" if finished_name is None else finished_name f"Chopped{self.name}" if finished_name is None else finished_name
) )
def progress(self): def progress(self):
...@@ -177,6 +177,9 @@ class Meal(Item): ...@@ -177,6 +177,9 @@ class Meal(Item):
class Soup(ProgressibleItem, Meal): class Soup(ProgressibleItem, Meal):
def __init__(self):
super().__init__(finished_name="CookedSoup")
def can_progress(self) -> bool: def can_progress(self) -> bool:
return len(self.parts) == 3 return len(self.parts) == 3
......
...@@ -3,44 +3,28 @@ from pathlib import Path ...@@ -3,44 +3,28 @@ from pathlib import Path
import numpy as np import numpy as np
import pygame import pygame
import yaml
from overcooked_simulator import ROOT_DIR from overcooked_simulator import ROOT_DIR
from overcooked_simulator.counters import (
CuttingBoard,
Trash,
TomatoDispenser,
PlateReturn,
ServingWindow,
Stove,
)
from overcooked_simulator.game_items import ( from overcooked_simulator.game_items import (
ProgressibleItem, ProgressibleItem,
Plate, Plate,
Item, Item,
Pot, CookingEquipment,
Soup, Meal,
) )
from overcooked_simulator.game_items import Tomato
from overcooked_simulator.overcooked_environment import Action from overcooked_simulator.overcooked_environment import Action
from overcooked_simulator.simulation_runner import Simulator from overcooked_simulator.simulation_runner import Simulator
WHITE = (255, 255, 255)
GREY = (190, 190, 190)
BLACK = (0, 0, 0)
COUNTER_COLOR = (240, 240, 240) COUNTER_COLOR = (240, 240, 240)
LIGHTGREY = (220, 220, 220)
GREEN = (0, 255, 0) GREEN = (0, 255, 0)
RED = (255, 0, 0) RED = (255, 0, 0)
BLUE = (0, 0, 255) BLUE = (0, 0, 255)
YELLOW = (255, 255, 0) WHITE = (255, 255, 255)
BACKGROUND_COLOR = GREY BACKGROUND_COLOR = (190, 190, 190)
BACKGROUND_LINES_COLOR = (200, 200, 200) BACKGROUND_LINES_COLOR = (200, 200, 200)
KNIFE_COLOR = (120, 120, 120)
PLATE_RETURN_COLOR = (170, 170, 240)
BOARD_COLOR = (239, 193, 151)
POT_COLOR = (130, 130, 130)
USE_COOK_SPRITE = True PLAYER_DEBUG_VIZ = True
class PlayerKeySet: class PlayerKeySet:
...@@ -98,6 +82,9 @@ class PyGameGUI: ...@@ -98,6 +82,9 @@ class PyGameGUI:
for player_name, keys in zip(self.player_names, self.player_keys) for player_name, keys in zip(self.player_names, self.player_keys)
] ]
with open(ROOT_DIR / "pygame_gui/visualization.yaml", "r") as file:
self.visualization_config = yaml.safe_load(file)
self.images_path = Path(ROOT_DIR, "pygame_gui", "images") self.images_path = Path(ROOT_DIR, "pygame_gui", "images")
def send_action(self, action: Action): def send_action(self, action: Action):
...@@ -163,28 +150,18 @@ class PyGameGUI: ...@@ -163,28 +150,18 @@ class PyGameGUI:
state: The game state returned by the environment. state: The game state returned by the environment.
""" """
for player in state["players"].values(): for player in state["players"].values():
if USE_COOK_SPRITE: if PLAYER_DEBUG_VIZ:
image = pygame.image.load(
self.images_path / "pixel_cook.png"
).convert_alpha()
rel_x, rel_y = player.facing_direction
angle = -np.rad2deg(math.atan2(rel_y, rel_x)) + 90
image = pygame.transform.scale(image, (40, 40))
image = pygame.transform.rotate(image, angle)
rect = image.get_rect()
rect.center = player.pos
self.screen.blit(image, rect)
else:
pos = player.pos pos = player.pos
size = player.radius size = player.radius
color1 = RED if player.name == "p1" else GREEN color1 = RED if player.name == "p1" else GREEN
color2 = WHITE color2 = WHITE
rect = pygame.Rect(pos[0] - (size / 2), pos[1] - (size / 2), size, size)
pygame.draw.circle(self.screen, color2, pos, size) pygame.draw.circle(self.screen, color2, pos, size)
pygame.draw.rect(self.screen, color1, rect) pygame.draw.circle(self.screen, BLUE, pos, size, width=1)
pygame.draw.circle(
self.screen, BLUE, pos, player.interaction_range, width=1
)
pygame.draw.circle(self.screen, color1, pos, size // 2)
pos = player.pos pos = player.pos
facing = player.facing_direction facing = player.facing_direction
...@@ -194,67 +171,90 @@ class PyGameGUI: ...@@ -194,67 +171,90 @@ class PyGameGUI:
( (
(pos[0] + (facing[1] * 5), pos[1] - (facing[0] * 5)), (pos[0] + (facing[1] * 5), pos[1] - (facing[0] * 5)),
(pos[0] - (facing[1] * 5), pos[1] + (facing[0] * 5)), (pos[0] - (facing[1] * 5), pos[1] + (facing[0] * 5)),
player.pos + (facing * 20), player.pos + (facing * 25),
), ),
) )
else:
img_path = self.visualization_config["Cook"]["parts"][0]["path"]
image = pygame.image.load(
ROOT_DIR / Path("pygame_gui") / img_path
).convert_alpha()
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"]
image = pygame.transform.scale(image, (size, size))
image = pygame.transform.rotate(image, angle)
rect = image.get_rect()
rect.center = player.pos
self.screen.blit(image, rect)
if player.holding is not None: if player.holding is not None:
holding_item_pos = player.pos + (20 * player.facing_direction) holding_item_pos = player.pos + (20 * player.facing_direction)
self.draw_item(holding_item_pos, player.holding) self.draw_item(holding_item_pos, player.holding)
def draw_item(self, pos, item: Item): def draw_item(self, pos, item: Item):
"""Visualisation of an item at the specified position. On a counter or in the hands of the player.""" """Visualisation of an item at the specified position. On a counter or in the hands of the player.
if isinstance(item, Tomato): The visual composition of the item is read in from visualization.yaml file, where it is specified as
if item.finished: different parts to be drawn.
image = pygame.image.load(
self.images_path / "tomato_cut.png" Args:
).convert_alpha() item: The item do be drawn in the game.
else: """
image = pygame.image.load(
self.images_path / "tomato.png" if item.name == "Tomato":
).convert_alpha() print(item)
rect = image.get_rect()
rect.center = pos if not isinstance(item, Meal):
self.screen.blit(image, rect) image = pygame.image.load(
ROOT_DIR
/ Path("pygame_gui")
/ self.visualization_config[item.name]["parts"][0]["path"]
).convert_alpha()
size = self.visualization_config[item.name]["parts"][0]["size"]
image = pygame.transform.scale(image, (size, size))
if isinstance(item, Plate):
image = pygame.image.load(self.images_path / "plate.png").convert_alpha()
rect = image.get_rect() rect = image.get_rect()
rect.center = pos rect.center = pos
self.screen.blit(image, rect) self.screen.blit(image, rect)
if item.holds is not None:
self.draw_item(pos, item.holds)
if isinstance(item, Pot):
pot_size = 15
pygame.draw.circle(self.screen, GREY, pos, pot_size)
pygame.draw.circle(self.screen, POT_COLOR, pos, pot_size, width=2)
if item.content:
self.draw_item(pos, item.content)
if isinstance(item, Soup):
if not item.finished:
match len(item.parts):
case 1:
pygame.draw.circle(self.screen, RED, pos, 4)
case 2:
pygame.draw.circle(self.screen, RED, pos, 8)
case 3:
pygame.draw.circle(self.screen, RED, pos, 12)
else:
"""https://www.readersdigest.ca/wp-content/uploads/2020/11/The-Best-Ever-Tomato-Soup_EXPS_THSO18_222724_D03_06_5b-4.jpg"""
image = pygame.image.load(
self.images_path / "tomato_soup.png"
).convert_alpha()
image = pygame.transform.scale(image, (24, 24))
rect = image.get_rect()
rect.center = pos
self.screen.blit(image, rect)
if isinstance(item, ProgressibleItem) and not item.finished: if isinstance(item, ProgressibleItem) and not item.finished:
self.draw_progress_bar(pos, item.progressed_steps, item.steps_needed) self.draw_progress_bar(pos, item.progressed_steps, item.steps_needed)
if isinstance(item, Plate) and item.holds:
self.draw_item(pos, item.holds)
if isinstance(item, CookingEquipment) and item.content:
self.draw_item(pos, item.content)
if isinstance(item, Meal) and item.parts:
if (
isinstance(item, Meal)
and isinstance(item, ProgressibleItem)
and item.parts
):
if not item.finished:
match len(item.parts):
case 1:
pygame.draw.circle(self.screen, RED, pos, 4)
case 2:
pygame.draw.circle(self.screen, RED, pos, 8)
case 3:
pygame.draw.circle(self.screen, RED, pos, 12)
else:
image = pygame.image.load(
ROOT_DIR
/ Path("pygame_gui")
/ self.visualization_config[item.name]["parts"][0]["path"]
).convert_alpha()
image = pygame.transform.scale(image, (24, 24))
rect = image.get_rect()
rect.center = pos
self.screen.blit(image, rect)
def draw_progress_bar(self, pos, current, needed): def draw_progress_bar(self, pos, current, needed):
"""Visualize progress of progressing item as a green bar under the item."""
if current != 0: if current != 0:
bar_height = self.counter_size * 0.2 bar_height = self.counter_size * 0.2
progress_width = (current / needed) * self.counter_size progress_width = (current / needed) * self.counter_size
...@@ -268,6 +268,8 @@ class PyGameGUI: ...@@ -268,6 +268,8 @@ class PyGameGUI:
def draw_counter(self, counter): def draw_counter(self, counter):
"""Visualisation of a counter at its position. If it is occupied by an item, it is also shown. """Visualisation of a counter at its position. If it is occupied by an item, it is also shown.
The visual composition of the counter is read in from visualization.yaml file, where it is specified as
different parts to be drawn.
Args: Args:
counter: The counter to visualize. counter: The counter to visualize.
...@@ -281,69 +283,29 @@ class PyGameGUI: ...@@ -281,69 +283,29 @@ class PyGameGUI:
) )
pygame.draw.rect(self.screen, COUNTER_COLOR, counter_rect_outline) pygame.draw.rect(self.screen, COUNTER_COLOR, counter_rect_outline)
if isinstance(counter, CuttingBoard): for part in self.visualization_config[counter.__class__.__name__]["parts"]:
board_size = 30 if part["type"] == "rect":
board_rect = pygame.Rect( height = part["height"]
counter.pos[0] - (board_size / 2), width = part["width"]
counter.pos[1] - (board_size / 2), color = part["color"]
board_size, if "center_offset" in part:
board_size, dx, dy = part["center_offset"]
) rect = pygame.Rect(counter.pos[0] + dx, counter.pos[1] + dy, 5, 20)
pygame.draw.rect(self.screen, BOARD_COLOR, board_rect) pygame.draw.rect(self.screen, color, rect)
else:
knife_rect = pygame.Rect(counter.pos[0] + 6, counter.pos[1] - 8, 5, 20) rect = pygame.Rect(
pygame.draw.rect(self.screen, KNIFE_COLOR, knife_rect) counter.pos[0] - (height / 2),
counter.pos[1] - (width / 2),
if isinstance(counter, PlateReturn): height,
size = 38 width,
inner = pygame.Rect( )
counter.pos[0] - (size / 2), pygame.draw.rect(self.screen, color, rect)
counter.pos[1] - (size / 2),
size, elif part["type"] == "circle":
size, radius = part["radius"]
) color = part["color"]
pygame.draw.rect(self.screen, PLATE_RETURN_COLOR, inner) pygame.draw.circle(self.screen, color, counter.pos, radius)
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 isinstance(counter, Stove):
stove_width = 35
stove_height = 25
stove_rect = pygame.Rect(
counter.pos[0] - (stove_width / 2),
counter.pos[1] - (stove_height / 2),
stove_width,
stove_height,
)
pygame.draw.rect(self.screen, BLACK, stove_rect)
pygame.draw.circle(self.screen, RED, center=counter.pos, radius=10)
if counter.occupied_by is not None: if counter.occupied_by is not None:
if isinstance(counter.occupied_by, list): if isinstance(counter.occupied_by, list):
for i, o in enumerate(counter.occupied_by): for i, o in enumerate(counter.occupied_by):
......
Counter:
parts:
- type: "rect"
height: 40
width: 40
color: [ 240, 240, 240 ]
CuttingBoard:
parts:
- type: "rect"
height: 30
width: 30
color: [ 239, 193, 151 ]
- type: "rect"
height: 5
width: 20
center_offset: [ +6, -8 ]
color: [ 120, 120, 120 ]
PlateReturn:
parts:
- type: "rect"
height: 38
width: 38
color: [ 170, 170, 240 ]
Trash:
parts:
- type: "circle"
radius: 16
color: [ 0, 0, 0 ]
- type: "circle"
radius: 15
color: [ 80, 80, 80 ]
TomatoDispenser:
parts:
- color: [ 255, 0, 0 ]
type: "rect"
height: 32
width: 32
ServingWindow:
parts:
- color: [ 255, 255, 0 ]
type: "rect"
height: 33
width: 33
Stove:
parts:
- color: [ 0, 0, 0 ]
type: "rect"
height: 35
width: 25
- color: [ 255, 0, 0 ]
type: "circle"
radius: 10
# Items
Tomato:
parts:
- type: "image"
path: "images/tomato.png"
size: 40
ChoppedTomato:
parts:
- type: "image"
path: "images/tomato_cut.png"
size: 40
CookedSoup:
parts:
- type: "image"
path: "images/tomato_soup.png"
size: 24
Soup:
parts:
- type: "image"
path: "images/tomato_soup.png"
size: 24
Cook:
parts:
- type: "image"
path: "images/pixel_cook.png"
size: 40
Plate:
parts:
- type: "image"
path: "images/plate.png"
size: 40
Pot:
parts:
- type: "image"
path: "images/pot.png"
size: 32
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment