From 8bbb78ce28d8397065b0f017335220e49da267b1 Mon Sep 17 00:00:00 2001
From: fheinrich <fheinrich@techfak.uni-bielefeld.de>
Date: Thu, 22 Feb 2024 18:22:26 +0100
Subject: [PATCH] View restrictions for both players

---
 .../game_content/environment_config.yaml      |   2 +-
 .../study/level2/level2_config.yaml           |   4 +-
 .../game_content/study/study_config.yaml      |   8 +-
 overcooked_simulator/gui_2d_vis/drawing.py    | 136 ++++++++++--------
 .../overcooked_environment.py                 |  22 +--
 overcooked_simulator/state_representation.py  |   2 +-
 6 files changed, 100 insertions(+), 74 deletions(-)

diff --git a/overcooked_simulator/game_content/environment_config.yaml b/overcooked_simulator/game_content/environment_config.yaml
index 00716059..42d8dd53 100644
--- a/overcooked_simulator/game_content/environment_config.yaml
+++ b/overcooked_simulator/game_content/environment_config.yaml
@@ -99,7 +99,7 @@ player_config:
   interaction_range: 1.6
   restricted_view: False
   view_angle: 70
-  view_range: 5.5  # in grid units, can be "null"
+  view_range: 4  # in grid units, can be "null"
 
 effect_manager:
   FireManager:
diff --git a/overcooked_simulator/game_content/study/level2/level2_config.yaml b/overcooked_simulator/game_content/study/level2/level2_config.yaml
index 22f75107..bea2049e 100644
--- a/overcooked_simulator/game_content/study/level2/level2_config.yaml
+++ b/overcooked_simulator/game_content/study/level2/level2_config.yaml
@@ -98,8 +98,8 @@ player_config:
   player_speed_units_per_seconds: 8
   interaction_range: 1.6
   restricted_view: True
-  view_angle: 75
-  view_range: 6  # in grid units, can be "null"
+  view_angle: 50
+  view_range: 5  # in grid units, can be "null"
 
 effect_manager:
   FireManager:
diff --git a/overcooked_simulator/game_content/study/study_config.yaml b/overcooked_simulator/game_content/study/study_config.yaml
index 57c46cf9..5df5da43 100644
--- a/overcooked_simulator/game_content/study/study_config.yaml
+++ b/overcooked_simulator/game_content/study/study_config.yaml
@@ -3,10 +3,10 @@
 
 
 levels:
-  - config_path: study/level1/level1_config.yaml
-    layout_path: overcooked-1/1-1-far-apart.layout
-    item_info_path: study/level1/level1_item_info.yaml
-    name: "Level 1-1: Far Apart"
+  #  - config_path: study/level1/level1_config.yaml
+  #    layout_path: overcooked-1/1-1-far-apart.layout
+  #    item_info_path: study/level1/level1_item_info.yaml
+  #    name: "Level 1-1: Far Apart"
 
   - config_path: study/level2/level2_config.yaml
     layout_path: overcooked-1/1-4-bottleneck.layout
diff --git a/overcooked_simulator/gui_2d_vis/drawing.py b/overcooked_simulator/gui_2d_vis/drawing.py
index f382a9b9..16926192 100644
--- a/overcooked_simulator/gui_2d_vis/drawing.py
+++ b/overcooked_simulator/gui_2d_vis/drawing.py
@@ -137,7 +137,8 @@ class Visualizer:
             pygame.draw.circle(
                 screen,
                 col,
-                np.array(state["players"][int(idx)]["pos"]) * grid_size + (grid_size // 2),
+                np.array(state["players"][int(idx)]["pos"]) * grid_size
+                + (grid_size // 2),
                 (grid_size / 2),
             )
 
@@ -147,73 +148,92 @@ class Visualizer:
             grid_size,
         )
 
-        if "view_restriction" in state and state["view_restriction"]:
-            # rotate direction vector in both direction with the angel
-            # draw 2 large rect which are rotated so that one edge is the viewing border
+        mask = pygame.Surface(screen.get_size(), pygame.SRCALPHA)
+        mask.fill((0, 0, 0, 0))
+        mask_color = (0, 0, 0, 0)
+        if "view_restrictions" in state and state["view_restrictions"]:
+            for idx, restriction in enumerate(state["view_restrictions"]):
+                # if idx != 0:
+                #     break
+                # rotate direction vector in both direction with the angel
+                # draw 2 large rect which are rotated so that one edge is the viewing border
+
+                direction = pygame.math.Vector2(restriction["direction"])
+                pos = pygame.math.Vector2(restriction["position"])
+                angle = restriction["angle"] / 2
+                range = restriction["range"]
+
+                angle = min(angle, 180)
+
+                pos = pos * grid_size + pygame.math.Vector2(
+                    [grid_size / 2, grid_size / 2]
+                )
 
-            direction = pygame.math.Vector2(state["view_restriction"]["direction"])
-            pos = pygame.math.Vector2(state["view_restriction"]["position"])
-            angle = state["view_restriction"]["angle"] / 2
-            range = state["view_restriction"]["range"]
+                rect_scale = max(width, height) * 2
+                # rect_scale = 2 * grid_size
 
-            angle = min(angle, 180)
+                left_beam = pos + (direction.rotate(angle) * rect_scale * 2)
+                right_beam = pos + (direction.rotate(-angle) * rect_scale * 2)
 
-            pos = pos * grid_size + pygame.math.Vector2([grid_size / 2, grid_size / 2])
+                cone_mask = pygame.surface.Surface(screen.get_size(), pygame.SRCALPHA)
+                cone_mask.fill((255, 255, 255, 255))
 
-            rect_scale = max(width, height) * 2
-            # rect_scale = 2 * grid_size
+                offset_front = direction * grid_size * 0.7
+                if angle != 180:
+                    pygame.draw.polygon(
+                        cone_mask,
+                        mask_color,
+                        (
+                            pos - offset_front,
+                            left_beam - offset_front,
+                            left_beam + (direction.rotate(90) * rect_scale),
+                            pos
+                            - (direction * rect_scale * 2)
+                            + (direction.rotate(90) * rect_scale),
+                            pos
+                            - (direction * rect_scale * 2)
+                            + (direction.rotate(-90) * rect_scale),
+                            right_beam + (direction.rotate(-90) * rect_scale),
+                            right_beam - offset_front,
+                        ),
+                    )
+                if range:
+                    n_circle_points = 40
 
-            left_beam = pos + (direction.rotate(angle) * rect_scale * 2)
-            right_beam = pos + (direction.rotate(-angle) * rect_scale * 2)
+                    start_vec = np.array(-direction * range)
+                    points = (
+                        np.array(create_polygon(n_circle_points, start_vec)) * grid_size
+                    ) + pos
 
-            offset_front = direction * grid_size * 0.7
-            if angle != 180:
-                pygame.draw.polygon(
-                    screen,
-                    colors["black"],
-                    (
-                        pos - offset_front,
-                        left_beam - offset_front,
-                        left_beam + (direction.rotate(90) * rect_scale),
+                    circle_closed = np.concatenate([points, points[0:1]], axis=0)
+
+                    corners = [
+                        pos - (direction * rect_scale),
+                        *circle_closed,
+                        pos - (direction * rect_scale),
+                        pos
+                        - (direction * rect_scale)
+                        + (direction.rotate(90) * rect_scale),
                         pos
-                        - (direction * rect_scale * 2)
+                        + (direction * rect_scale)
                         + (direction.rotate(90) * rect_scale),
                         pos
-                        - (direction * rect_scale * 2)
+                        + (direction * rect_scale)
                         + (direction.rotate(-90) * rect_scale),
-                        right_beam + (direction.rotate(-90) * rect_scale),
-                        right_beam - offset_front,
-                    ),
-                )
-            if range:
-                n_circle_points = 40
-
-                start_vec = np.array(-direction * range)
-                points = (
-                    np.array(create_polygon(n_circle_points, start_vec)) * grid_size
-                ) + pos
-
-                circle_closed = np.concatenate([points, points[0:1]], axis=0)
-
-                corners = [
-                    pos - (direction * rect_scale),
-                    *circle_closed,
-                    pos - (direction * rect_scale),
-                    pos
-                    - (direction * rect_scale)
-                    + (direction.rotate(90) * rect_scale),
-                    pos
-                    + (direction * rect_scale)
-                    + (direction.rotate(90) * rect_scale),
-                    pos
-                    + (direction * rect_scale)
-                    + (direction.rotate(-90) * rect_scale),
-                    pos
-                    - (direction * rect_scale)
-                    + (direction.rotate(-90) * rect_scale),
-                ]
-
-                pygame.draw.polygon(screen, colors["black"], [*corners])
+                        pos
+                        - (direction * rect_scale)
+                        + (direction.rotate(-90) * rect_scale),
+                    ]
+
+                    pygame.draw.polygon(cone_mask, mask_color, [*corners])
+
+                mask.blit(cone_mask, (0, 0), special_flags=pygame.BLEND_MAX)
+
+            screen.blit(
+                mask,
+                mask.get_rect(),
+                special_flags=pygame.BLEND_RGBA_MULT,
+            )
 
     def draw_background(
         self, surface: pygame.Surface, width: int, height: int, grid_size: int
diff --git a/overcooked_simulator/overcooked_environment.py b/overcooked_simulator/overcooked_environment.py
index 5fb8c791..5efbd158 100644
--- a/overcooked_simulator/overcooked_environment.py
+++ b/overcooked_simulator/overcooked_environment.py
@@ -813,7 +813,10 @@ class Environment:
             "remaining_time": max(self.env_time_end - self.env_time, timedelta(0)),
         }
 
-    def get_json_state(self, player_id: str = None,) -> str:
+    def get_json_state(
+        self,
+        player_id: str = None,
+    ) -> str:
         """Return the current state of the game formatted in json dict.
 
         Args:
@@ -837,13 +840,16 @@ class Environment:
                 "remaining_time": max(
                     self.env_time_end - self.env_time, timedelta(0)
                 ).total_seconds(),
-                "view_restriction": {
-                    "direction": self.players[player_id].facing_direction.tolist(),
-                    "position": self.players[player_id].pos.tolist(),
-                    "angle": self.player_view_angle,
-                    "counter_mask": None,
-                    "range": self.player_view_range,
-                }
+                "view_restrictions": [
+                    {
+                        "direction": player.facing_direction.tolist(),
+                        "position": player.pos.tolist(),
+                        "angle": self.player_view_angle,
+                        "counter_mask": None,
+                        "range": self.player_view_range,
+                    }
+                    for player in self.players.values()
+                ]
                 if self.player_view_restricted
                 else None,
                 "info_msg": [
diff --git a/overcooked_simulator/state_representation.py b/overcooked_simulator/state_representation.py
index fe587ca6..319e15ce 100644
--- a/overcooked_simulator/state_representation.py
+++ b/overcooked_simulator/state_representation.py
@@ -99,7 +99,7 @@ class StateRepresentation(BaseModel):
     ended: bool
     env_time: datetime  # isoformat str
     remaining_time: float
-    view_restriction: None | ViewRestriction
+    view_restrictions: None | list[ViewRestriction]
     info_msg: list[tuple[str, str]]
 
 
-- 
GitLab