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:
self.steps_needed = steps_needed
self.finished = finished
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):
......@@ -177,6 +177,9 @@ class Meal(Item):
class Soup(ProgressibleItem, Meal):
def __init__(self):
super().__init__(finished_name="CookedSoup")
def can_progress(self) -> bool:
return len(self.parts) == 3
......
......@@ -3,44 +3,28 @@ from pathlib import Path
import numpy as np
import pygame
import yaml
from overcooked_simulator import ROOT_DIR
from overcooked_simulator.counters import (
CuttingBoard,
Trash,
TomatoDispenser,
PlateReturn,
ServingWindow,
Stove,
)
from overcooked_simulator.game_items import (
ProgressibleItem,
Plate,
Item,
Pot,
Soup,
CookingEquipment,
Meal,
)
from overcooked_simulator.game_items import Tomato
from overcooked_simulator.overcooked_environment import Action
from overcooked_simulator.simulation_runner import Simulator
WHITE = (255, 255, 255)
GREY = (190, 190, 190)
BLACK = (0, 0, 0)
COUNTER_COLOR = (240, 240, 240)
LIGHTGREY = (220, 220, 220)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
BACKGROUND_COLOR = GREY
WHITE = (255, 255, 255)
BACKGROUND_COLOR = (190, 190, 190)
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:
......@@ -98,6 +82,9 @@ class PyGameGUI:
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")
def send_action(self, action: Action):
......@@ -163,28 +150,18 @@ class PyGameGUI:
state: The game state returned by the environment.
"""
for player in state["players"].values():
if USE_COOK_SPRITE:
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:
if PLAYER_DEBUG_VIZ:
pos = player.pos
size = player.radius
color1 = RED if player.name == "p1" else GREEN
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.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
facing = player.facing_direction
......@@ -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)),
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:
holding_item_pos = player.pos + (20 * player.facing_direction)
self.draw_item(holding_item_pos, player.holding)
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."""
if isinstance(item, Tomato):
if item.finished:
image = pygame.image.load(
self.images_path / "tomato_cut.png"
).convert_alpha()
else:
image = pygame.image.load(
self.images_path / "tomato.png"
).convert_alpha()
rect = image.get_rect()
rect.center = pos
self.screen.blit(image, rect)
"""Visualisation of an item at the specified position. On a counter or in the hands of the player.
The visual composition of the item is read in from visualization.yaml file, where it is specified as
different parts to be drawn.
Args:
item: The item do be drawn in the game.
"""
if item.name == "Tomato":
print(item)
if not isinstance(item, Meal):
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.center = pos
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:
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):
"""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
......@@ -268,6 +268,8 @@ class PyGameGUI:
def draw_counter(self, counter):
"""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:
counter: The counter to visualize.
......@@ -281,69 +283,29 @@ class PyGameGUI:
)
pygame.draw.rect(self.screen, COUNTER_COLOR, counter_rect_outline)
if isinstance(counter, CuttingBoard):
board_size = 30
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, 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 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)
for part in self.visualization_config[counter.__class__.__name__]["parts"]:
if part["type"] == "rect":
height = part["height"]
width = part["width"]
color = part["color"]
if "center_offset" in part:
dx, dy = part["center_offset"]
rect = pygame.Rect(counter.pos[0] + dx, counter.pos[1] + dy, 5, 20)
pygame.draw.rect(self.screen, color, rect)
else:
rect = pygame.Rect(
counter.pos[0] - (height / 2),
counter.pos[1] - (width / 2),
height,
width,
)
pygame.draw.rect(self.screen, color, rect)
elif part["type"] == "circle":
radius = part["radius"]
color = part["color"]
pygame.draw.circle(self.screen, color, counter.pos, radius)
if counter.occupied_by is not None:
if isinstance(counter.occupied_by, list):
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