Skip to content
Snippets Groups Projects
Commit 44093722 authored by Florian Schröder's avatar Florian Schröder
Browse files

Merge remote-tracking branch 'origin/main' into 55-environment-has-internal-time-not-datetime-now

# Conflicts:
#	overcooked_simulator/overcooked_environment.py
parents a03b1511 2b8de833
No related branches found
No related tags found
1 merge request!24Resolve "Environment has internal time not datetime now"
Pipeline #43014 passed
counter_side_length: 40
world_width: 800
world_height: 600
plates:
clean_plates: 3
dirty_plates: 2
......
_________________
_#QU#TNLB#_______
_#_______M_______
_#_______#_______
_W_______________
_#__A__A_________
_C_______________
_C_______#_______
_#_______X_______
_#P#S+#S+#_______
_________________
#QU#TNLB#
#_______M
#_______#
W________
#__A__A__
C________
C_______#
#_______X
#P#S+#S+#
\ No newline at end of file
radius: 0.4
move_dist: 5
move_dist: 0.2
interaction_range: 1.6
\ No newline at end of file
......@@ -84,7 +84,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()
......@@ -120,6 +120,9 @@ class Environment:
"+": SinkAddon,
}
self.kitchen_height: int = 0
self.kitchen_width: int = 0
(
self.counters,
self.designated_player_positions,
......@@ -130,9 +133,6 @@ class Environment:
self.score: int = 0
self.world_width: int = environment_config["world_width"]
self.world_height: int = environment_config["world_height"]
self.env_time = create_init_env_time()
def load_item_info(self) -> dict[str, ItemInfo]:
......@@ -160,16 +160,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])
......@@ -184,8 +188,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 + 2.5)
self.kitchen_width = int(self.kitchen_width + 0.5)
return counters, designated_player_positions, free_positions
......@@ -335,9 +344,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))
......@@ -355,10 +362,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 any(map(collide, other_players))
......@@ -392,16 +396,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:
......@@ -424,12 +427,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
......@@ -472,9 +472,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)
......
......@@ -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,
......
......@@ -89,12 +89,6 @@ class PyGameGUI:
self.screen = None
self.FPS = 60
self.simulator = simulator
self.counter_size = self.simulator.env.counter_side_length
self.window_width, self.window_height = (
simulator.env.world_width,
simulator.env.world_height,
)
self.player_names = player_names
self.player_keys = player_keys
......@@ -109,6 +103,20 @@ class PyGameGUI:
with open(ROOT_DIR / "pygame_gui" / "visualization.yaml", "r") as file:
self.visualization_config = yaml.safe_load(file)
if self.visualization_config["GameWindow"]["WhatIsFixed"] == "window_width":
self.window_width = self.visualization_config["GameWindow"]["size"]
kitchen_aspect_ratio = (
simulator.env.kitchen_height / simulator.env.kitchen_width
)
self.window_height = int(self.window_width * kitchen_aspect_ratio)
self.grid_size = int(self.window_width / simulator.env.kitchen_width)
elif self.visualization_config["GameWindow"]["WhatIsFixed"] == "grid":
self.grid_size = self.visualization_config["GameWindow"]["size"]
self.window_width, self.window_height = (
simulator.env.kitchen_width * self.grid_size,
simulator.env.kitchen_height * self.grid_size,
)
self.images_path = ROOT_DIR / "pygame_gui" / "images"
self.player_colors = self.create_player_colors()
......@@ -183,7 +191,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 +227,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 +248,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,26 +269,31 @@ 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)
holding_item_pos = (player.pos * self.grid_size) + (
20 * player.facing_direction
)
self.draw_item(holding_item_pos, player.holding)
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 +308,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,
)
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,
match part_type:
case "image":
self.draw_image(
parts[0]["path"],
parts[0]["size"] * scale * self.grid_size,
pos,
)
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 + (np.array(part["center_offset"])*self.grid_size),
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 +382,11 @@ 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
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 +401,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 +417,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 +431,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.
......
# colors: https://www.webucator.com/article/python-color-constants-module/
GameWindow:
WhatIsFixed: window_width # entweder grid oder window_width
size: 600
Kitchen:
ground_tiles_color: sgigray76
background_lines: gray79
......@@ -172,11 +176,11 @@ ChoppedLettuce:
- type: circle
radius: 0.3
color: black
center_offset: [ -5, 0 ]
center_offset: [ -0.125, 0 ]
- type: circle
radius: 0.25
color: emeraldgreen
center_offset: [ -5, 0 ]
center_offset: [ -0.125, 0 ]
- type: circle
radius: 0.3
color: black
......@@ -186,11 +190,11 @@ ChoppedLettuce:
- type: circle
radius: 0.3
color: black
center_offset: [ 5, 0 ]
center_offset: [ 0.125, 0 ]
- type: circle
radius: 0.25
color: emeraldgreen
center_offset: [ 5, 0 ]
center_offset: [ 0.125, 0 ]
ChoppedTomato:
parts:
......@@ -203,11 +207,11 @@ ChoppedOnion:
- type: circle
radius: 0.3
color: black
center_offset: [ -5, 0 ]
center_offset: [ -0.125, 0 ]
- type: circle
radius: 0.25
color: deeppink4
center_offset: [ -5, 0 ]
center_offset: [ -0.125, 0 ]
- type: circle
radius: 0.3
color: black
......@@ -217,22 +221,22 @@ ChoppedOnion:
- type: circle
radius: 0.3
color: black
center_offset: [ 5, 0 ]
center_offset: [ 0.125, 0 ]
- type: circle
radius: 0.25
color: deeppink4
center_offset: [ 5, 0 ]
center_offset: [ 0.125, 0 ]
ChoppedMeat:
parts:
- type: circle
radius: 0.3
color: black
center_offset: [ -5, 0 ]
center_offset: [ -0.125, 0 ]
- type: circle
radius: 0.25
color: indianred1
center_offset: [ -5, 0 ]
center_offset: [ -0.125, 0 ]
- type: circle
radius: 0.3
color: black
......
......@@ -86,7 +86,7 @@ def test_movement():
200,
)
player_name = "p1"
start_pos = np.array([50, 50])
start_pos = np.array([1, 2])
sim.register_player(player_name, start_pos)
move_direction = np.array([1, 0])
move_action = Action(player_name, "movement", move_direction)
......@@ -98,8 +98,8 @@ def test_movement():
move_direction * sim.env.players[player_name].move_dist
)
assert (
np.linalg.norm(expected - sim.env.players[player_name].pos) == 0
assert np.isclose(
np.linalg.norm(expected - sim.env.players[player_name].pos), 0
), "Should be here?"
......@@ -109,11 +109,11 @@ def test_collision_detection():
layouts_folder / "basic.layout",
200,
)
counter_pos = np.array([50, 100])
counter_pos = np.array([1, 2])
counter = Counter(counter_pos)
sim.env.counters = [counter]
sim.register_player("p1", np.array([50, 50]))
sim.register_player("p2", np.array([50, 200])) # same player name
sim.register_player("p1", np.array([1, 1]))
sim.register_player("p2", np.array([1, 4])) # same player name
player1 = sim.env.players["p1"]
player2 = sim.env.players["p2"]
......@@ -146,10 +146,10 @@ def test_player_reach():
200,
)
counter_pos = np.array([100, 100])
counter_pos = np.array([2, 2])
counter = Counter(counter_pos)
sim.env.counters = [counter]
sim.register_player("p1", np.array([100, 200]))
sim.register_player("p1", np.array([2, 4]))
player = sim.env.players["p1"]
assert not player.can_reach(counter), "Player is too far away."
......@@ -167,12 +167,12 @@ def test_pickup():
200,
)
counter_pos = np.array([100, 100])
counter_pos = np.array([2, 2])
counter = Counter(counter_pos)
counter.occupied_by = CuttableItem(name="Tomato", item_info=None)
sim.env.counters = [counter]
sim.register_player("p1", np.array([100, 160]))
sim.register_player("p1", np.array([2, 3]))
player = sim.env.players["p1"]
move_down = Action("p1", "movement", np.array([0, -1]))
......@@ -218,12 +218,12 @@ def test_processing():
)
sim.start()
counter_pos = np.array([100, 100])
counter_pos = np.array([2, 2])
counter = CuttingBoard(counter_pos)
sim.env.counters.append(counter)
tomato = CuttableItem(name="Tomato", item_info=None)
sim.register_player("p1", np.array([100, 150]))
sim.register_player("p1", np.array([2, 3]))
player = sim.env.players["p1"]
player.holding = tomato
......
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