diff --git a/overcooked_simulator/counters.py b/overcooked_simulator/counters.py
index 9694c824906af718f34d321a807cd9b06fef5c45..616ad6949e266bf9a00207525ab8334054751c95 100644
--- a/overcooked_simulator/counters.py
+++ b/overcooked_simulator/counters.py
@@ -5,6 +5,8 @@ from collections import deque
 from datetime import datetime, timedelta
 from typing import TYPE_CHECKING, Optional
 
+from overcooked_simulator.utils import create_init_env_time
+
 if TYPE_CHECKING:
     from overcooked_simulator.overcooked_environment import (
         GameScore,
@@ -97,7 +99,7 @@ class CuttingBoard(Counter):
         self.progressing = False
         super().__init__(pos)
 
-    def progress(self):
+    def progress(self, passed_time: timedelta, now: datetime):
         """Called by environment step function for time progression"""
         if self.progressing:
             if isinstance(self.occupied_by, CuttableItem):
@@ -194,6 +196,7 @@ class PlateDispenser(Counter):
         self.plate_config = {"plate_delay": [5, 10]}
         self.plate_config.update(plate_config)
         self.next_plate_time = datetime.max
+        self.env_time = create_init_env_time()  # is overwritten in progress anyway
         self.setup_plates()
 
     def pick_up(self, on_hands: bool = True):
@@ -223,7 +226,8 @@ class PlateDispenser(Counter):
 
     def update_plate_out_of_kitchen(self):
         """Is called from the serving window to add a plate out of kitchen."""
-        time_plate_to_add = datetime.now() + timedelta(
+        # not perfect identical to datetime.now but based on framerate enough.
+        time_plate_to_add = self.env_time + timedelta(
             seconds=np.random.uniform(
                 low=self.plate_config["plate_delay"][0],
                 high=self.plate_config["plate_delay"][1],
@@ -251,9 +255,9 @@ class PlateDispenser(Counter):
                 ]
             )
 
-    def progress(self):
+    def progress(self, passed_time: timedelta, now: datetime):
         """Check if plates arrive from outside the kitchen and add a dirty plate accordingly"""
-        now = datetime.now()
+        self.env_time = now
         if self.next_plate_time < now:
             idx_delete = []
             for i, times in enumerate(self.out_of_kitchen_timer):
@@ -294,7 +298,7 @@ class Stove(Counter):
         else:
             return self.occupied_by.can_combine(item)
 
-    def progress(self):
+    def progress(self, passed_time: timedelta, now: datetime):
         """Called by environment step function for time progression"""
         if (
             self.occupied_by
@@ -311,7 +315,7 @@ class Sink(Counter):
         self.sink_addon: SinkAddon = sink_addon
         self.occupied_by = deque()
 
-    def progress(self):
+    def progress(self, passed_time: timedelta, now: datetime):
         """Called by environment step function for time progression"""
         if self.progressing:
             if self.occupied_by:
diff --git a/overcooked_simulator/game_content/environment_config.yaml b/overcooked_simulator/game_content/environment_config.yaml
index 073f4c70f4a8ee88d4071313b116f3135bfb9e83..158a22290759fa0415806ee59ce968972e07029c 100644
--- a/overcooked_simulator/game_content/environment_config.yaml
+++ b/overcooked_simulator/game_content/environment_config.yaml
@@ -1,7 +1,4 @@
-counter_side_length: 70
-world_width: 1000
-world_height: 800
 plates:
-  clean_plates: 0
-  dirty_plates: 10
+  clean_plates: 3
+  dirty_plates: 2
   plate_delay: [ 5, 10 ]
\ No newline at end of file
diff --git a/overcooked_simulator/game_content/layouts/basic.layout b/overcooked_simulator/game_content/layouts/basic.layout
index 8b46829b755b1963fde61a396d395618070b3a21..2e7395aa296304bae3d354eea5613affcc0ee6b0 100644
--- a/overcooked_simulator/game_content/layouts/basic.layout
+++ b/overcooked_simulator/game_content/layouts/basic.layout
@@ -1,11 +1,9 @@
-_________________
-_#QU#TNLB#_______
-_#_______M_______
-_#_______#_______
-_W_______________
-_#__A__A_________
-_C_______________
-_C_______#_______
-_#_______X_______
-_#P#S+#S+#_______
-_________________
+#QU#T###NLB#
+#__________M
+#__________#
+W___________
+#__A_____A__
+C___________
+C__________#
+#__________X
+#P#S+####S+#
\ No newline at end of file
diff --git a/overcooked_simulator/game_content/layouts/empty.layout b/overcooked_simulator/game_content/layouts/empty.layout
index de0f1b9eb58638cd6a2b94b6ae4591bc72e6144d..2fa1dd8c29c076e9d94e9a305843ff87bebb29f1 100644
--- a/overcooked_simulator/game_content/layouts/empty.layout
+++ b/overcooked_simulator/game_content/layouts/empty.layout
@@ -1,3 +1,7 @@
-_____
-_____
-____P
\ No newline at end of file
+______
+______
+______
+______
+______
+______
+_____P
\ No newline at end of file
diff --git a/overcooked_simulator/game_content/player_config.yaml b/overcooked_simulator/game_content/player_config.yaml
index 43cd56a89b915e37ae4eda4bb005c87bcf716cb1..7387659aa3919ca3315269cbe0ca97c3460aac89 100644
--- a/overcooked_simulator/game_content/player_config.yaml
+++ b/overcooked_simulator/game_content/player_config.yaml
@@ -1,3 +1,3 @@
 radius: 0.4
-move_dist: 7
+move_dist: 0.12
 interaction_range: 1.6
\ No newline at end of file
diff --git a/overcooked_simulator/pygame_gui/__init__.py b/overcooked_simulator/gui_2d_vis/__init__.py
similarity index 100%
rename from overcooked_simulator/pygame_gui/__init__.py
rename to overcooked_simulator/gui_2d_vis/__init__.py
diff --git a/overcooked_simulator/pygame_gui/game_colors.py b/overcooked_simulator/gui_2d_vis/game_colors.py
similarity index 100%
rename from overcooked_simulator/pygame_gui/game_colors.py
rename to overcooked_simulator/gui_2d_vis/game_colors.py
diff --git a/overcooked_simulator/gui_2d_vis/gui_theme.json b/overcooked_simulator/gui_2d_vis/gui_theme.json
new file mode 100644
index 0000000000000000000000000000000000000000..3ca11b55479e8d69bbbf8ab0e3fc4b46cad713e7
--- /dev/null
+++ b/overcooked_simulator/gui_2d_vis/gui_theme.json
@@ -0,0 +1,49 @@
+{
+  "defaults": {
+    "colours": {
+      "normal_bg": "#45494e",
+      "hovered_bg": "#35393e",
+      "disabled_bg": "#25292e",
+      "selected_bg": "#193754",
+      "dark_bg": "#15191e",
+      "normal_text": "#c5cbd8",
+      "hovered_text": "#FFFFFF",
+      "selected_text": "#FFFFFF",
+      "disabled_text": "#6d736f",
+      "link_text": "#0000EE",
+      "link_hover": "#2020FF",
+      "link_selected": "#551A8B",
+      "text_shadow": "#777777",
+      "normal_border": "#DDDDDD",
+      "hovered_border": "#B0B0B0",
+      "disabled_border": "#808080",
+      "selected_border": "#8080B0",
+      "active_border": "#8080B0",
+      "filled_bar": "#f4251b",
+      "unfilled_bar": "#CCCCCC"
+    }
+  },
+  "button": {
+    "colours": {
+      "normal_bg": "#45494e",
+      "hovered_bg": "#35393e",
+      "disabled_bg": "#25292e",
+      "selected_bg": "#193754",
+      "active_bg": "#193754",
+      "dark_bg": "#15191e",
+      "normal_text": "#c5cbd8",
+      "hovered_text": "#FFFFFF",
+      "selected_text": "#FFFFFF",
+      "disabled_text": "#6d736f",
+      "active_text": "#FFFFFF",
+      "normal_border": "#DDDDDD",
+      "hovered_border": "#B0B0B0",
+      "disabled_border": "#808080",
+      "selected_border": "#8080B0",
+      "active_border": "#8080B0"
+    },
+    "misc": {
+      "tool_tip_delay": "1.5"
+    }
+  }
+}
\ No newline at end of file
diff --git a/overcooked_simulator/pygame_gui/images/pixel_cook.png b/overcooked_simulator/gui_2d_vis/images/pixel_cook.png
similarity index 100%
rename from overcooked_simulator/pygame_gui/images/pixel_cook.png
rename to overcooked_simulator/gui_2d_vis/images/pixel_cook.png
diff --git a/overcooked_simulator/pygame_gui/images/plate.png b/overcooked_simulator/gui_2d_vis/images/plate.png
similarity index 100%
rename from overcooked_simulator/pygame_gui/images/plate.png
rename to overcooked_simulator/gui_2d_vis/images/plate.png
diff --git a/overcooked_simulator/pygame_gui/images/plate_clean.png b/overcooked_simulator/gui_2d_vis/images/plate_clean.png
similarity index 100%
rename from overcooked_simulator/pygame_gui/images/plate_clean.png
rename to overcooked_simulator/gui_2d_vis/images/plate_clean.png
diff --git a/overcooked_simulator/pygame_gui/images/plate_dirty.png b/overcooked_simulator/gui_2d_vis/images/plate_dirty.png
similarity index 100%
rename from overcooked_simulator/pygame_gui/images/plate_dirty.png
rename to overcooked_simulator/gui_2d_vis/images/plate_dirty.png
diff --git a/overcooked_simulator/pygame_gui/images/pot.png b/overcooked_simulator/gui_2d_vis/images/pot.png
similarity index 100%
rename from overcooked_simulator/pygame_gui/images/pot.png
rename to overcooked_simulator/gui_2d_vis/images/pot.png
diff --git a/overcooked_simulator/gui_2d_vis/images/tomato.png b/overcooked_simulator/gui_2d_vis/images/tomato.png
new file mode 100644
index 0000000000000000000000000000000000000000..84e063976d58e8a4aa194124409223e3c67c6834
Binary files /dev/null and b/overcooked_simulator/gui_2d_vis/images/tomato.png differ
diff --git a/overcooked_simulator/gui_2d_vis/images/tomato_cut.png b/overcooked_simulator/gui_2d_vis/images/tomato_cut.png
new file mode 100644
index 0000000000000000000000000000000000000000..18a12e7f7681856c15bc85bc3a7b2c9a6a42d71f
Binary files /dev/null and b/overcooked_simulator/gui_2d_vis/images/tomato_cut.png differ
diff --git a/overcooked_simulator/gui_2d_vis/images/tomato_soup.png b/overcooked_simulator/gui_2d_vis/images/tomato_soup.png
new file mode 100644
index 0000000000000000000000000000000000000000..2a0fbf6568ae68871136acb6c78fa734f0dc14ce
Binary files /dev/null and b/overcooked_simulator/gui_2d_vis/images/tomato_soup.png differ
diff --git a/overcooked_simulator/gui_2d_vis/overcooked_gui.py b/overcooked_simulator/gui_2d_vis/overcooked_gui.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c910c07f9b6fadfd571a64eaf6d4f606fee333f
--- /dev/null
+++ b/overcooked_simulator/gui_2d_vis/overcooked_gui.py
@@ -0,0 +1,755 @@
+import colorsys
+import logging
+import math
+import sys
+from collections import deque
+from enum import Enum
+
+import numpy as np
+import numpy.typing as npt
+import pygame
+import pygame_gui
+import yaml
+from scipy.spatial import KDTree
+
+from overcooked_simulator import ROOT_DIR
+from overcooked_simulator.counters import Counter
+from overcooked_simulator.game_items import (
+    ProgressibleItem,
+    Item,
+    CookingEquipment,
+    Meal,
+    Plate,
+)
+from overcooked_simulator.gui_2d_vis.game_colors import BLUE
+from overcooked_simulator.gui_2d_vis.game_colors import colors, Color
+from overcooked_simulator.overcooked_environment import Action
+from overcooked_simulator.simulation_runner import Simulator
+
+USE_PLAYER_COOK_SPRITES = True
+SHOW_INTERACTION_RANGE = False
+SHOW_COUNTER_CENTERS = False
+
+
+class MenuStates(Enum):
+    Start = "Start"
+    Game = "Game"
+    End = "End"
+
+
+def create_polygon(n, length):
+    if n == 0:
+        return np.array([0, 0])
+
+    vector = np.array([length, 0])
+    angle = (2 * np.pi) / n
+
+    rot_matrix = np.array(
+        [[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]]
+    )
+
+    vecs = [vector]
+    for i in range(n - 1):
+        vector = np.dot(rot_matrix, vector)
+        vecs.append(vector)
+
+    return vecs
+
+
+log = logging.getLogger(__name__)
+
+
+class PlayerKeySet:
+    """Set of keyboard keys for controlling a player.
+    First four keys are for movement. Order: Down, Up, Left, Right.
+    5th key is for interacting with counters.
+    6th key ist for picking up things or dropping them.
+
+    """
+
+    def __init__(self, player_name: str, keys: list[pygame.key]):
+        """Creates a player key set which contains information about which keyboard keys control the player.
+        Movement keys in the following order: Down, Up, Left, Right
+
+        Args:
+            player_name: The name of the player to control.
+            keys: The keys which control this player in the following order: Down, Up, Left, Right, Interact, Pickup.
+        """
+        self.name = player_name
+        self.player_keys = keys
+        self.move_vectors = [[-1, 0], [1, 0], [0, -1], [0, 1]]
+        self.key_to_movement = {
+            key: vec for (key, vec) in zip(self.player_keys[:-2], self.move_vectors)
+        }
+        self.interact_key = self.player_keys[-2]
+        self.pickup_key = self.player_keys[-1]
+
+
+class PyGameGUI:
+    """Visualisation of the overcooked environment and reading keyboard inputs using pygame."""
+
+    def __init__(
+        self,
+        simulator: Simulator,
+        player_names: list[str],
+        player_keys: list[pygame.key],
+    ):
+        self.game_screen = None
+        self.FPS = 60
+        self.simulator: Simulator = simulator
+        self.running = True
+
+        self.player_names = player_names
+        self.player_keys = player_keys
+
+        self.player_key_sets: list[PlayerKeySet] = [
+            PlayerKeySet(player_name, keys)
+            for player_name, keys in zip(
+                self.player_names, self.player_keys[: len(self.player_names)]
+            )
+        ]
+
+        # TODO cache loaded images?
+        with open(ROOT_DIR / "gui_2d_vis" / "visualization.yaml", "r") as file:
+            self.visualization_config = yaml.safe_load(file)
+
+        self.screen_margin = self.visualization_config["GameWindow"]["screen_margin"]
+        self.window_width = self.visualization_config["GameWindow"]["start_width"]
+        self.window_height = self.visualization_config["GameWindow"]["start_height"]
+
+        self.main_window = pygame.display.set_mode(
+            (
+                self.window_width,
+                self.window_height,
+            )
+        )
+
+        self.game_width, self.game_height = 0, 0
+
+        self.images_path = ROOT_DIR / "pygame_gui" / "images"
+
+        self.image_cache_dict = {}
+
+        self.menu_state = MenuStates.Start
+        self.manager: pygame_gui.UIManager
+
+    def init_window_sizes(self):
+        if self.visualization_config["GameWindow"]["WhatIsFixed"] == "window_width":
+            game_width = self.visualization_config["GameWindow"]["size"]
+            kitchen_aspect_ratio = (
+                self.simulator.env.kitchen_height / self.simulator.env.kitchen_width
+            )
+            game_height = int(game_width * kitchen_aspect_ratio)
+            grid_size = int(game_width / self.simulator.env.kitchen_width)
+        elif self.visualization_config["GameWindow"]["WhatIsFixed"] == "grid":
+            grid_size = self.visualization_config["GameWindow"]["size"]
+            game_width, game_height = (
+                self.simulator.env.kitchen_width * grid_size,
+                self.simulator.env.kitchen_height * grid_size,
+            )
+        else:
+            game_width, game_height = 0, 0
+            grid_size = 0
+
+        window_width, window_height = (
+            game_width + (2 * self.screen_margin),
+            game_height + (2 * self.screen_margin),
+        )
+
+        return window_width, window_height, game_width, game_height, grid_size
+
+    def create_player_colors(self) -> list[Color]:
+        number_player = len(self.simulator.env.players)
+        hue_values = np.linspace(0, 1, number_player + 1)
+
+        colors_vec = np.array([col for col in colors.values()])
+
+        tree = KDTree(colors_vec)
+
+        color_names = list(colors.keys())
+
+        player_colors = []
+        for hue in hue_values:
+            rgb = colorsys.hsv_to_rgb(hue, 1, 1)
+            query_color = np.array([int(c * 255) for c in rgb])
+            _, index = tree.query(query_color, k=1)
+            player_colors.append(color_names[index])
+
+        return player_colors
+
+    def send_action(self, action: Action):
+        """Sends an action to the game environment.
+
+        Args:
+            action: The action to be sent. Contains the player, action type and move direction if action is a movement.
+        """
+        self.simulator.enter_action(action)
+
+    def handle_keys(self):
+        """Handles keyboard inputs. Sends action for the respective players. When a key is held down, every frame
+        an action is sent in this function.
+        """
+        keys = pygame.key.get_pressed()
+        for player_idx, key_set in enumerate(self.player_key_sets):
+            relevant_keys = [keys[k] for k in key_set.player_keys]
+            if any(relevant_keys[:-2]):
+                move_vec = np.zeros(2)
+                for idx, pressed in enumerate(relevant_keys[:-2]):
+                    if pressed:
+                        move_vec += key_set.move_vectors[idx]
+                if np.linalg.norm(move_vec) != 0:
+                    move_vec = move_vec / np.linalg.norm(move_vec)
+
+                action = Action(key_set.name, "movement", move_vec)
+                self.send_action(action)
+
+    def handle_key_event(self, event):
+        """Handles key events for the pickup and interaction keys. Pickup is a single action,
+        for interaction keydown and keyup is necessary, because the player has to be able to hold
+        the key down.
+
+        Args:
+            event: Pygame event for extracting the key action.
+        """
+        for key_set in self.player_key_sets:
+            if event.key == key_set.pickup_key and event.type == pygame.KEYDOWN:
+                action = Action(key_set.name, "pickup", "pickup")
+                self.send_action(action)
+
+            if event.key == key_set.interact_key:
+                if event.type == pygame.KEYDOWN:
+                    action = Action(key_set.name, "interact", "keydown")
+                    self.send_action(action)
+                elif event.type == pygame.KEYUP:
+                    action = Action(key_set.name, "interact", "keyup")
+                    self.send_action(action)
+
+    def draw_background(self):
+        """Visualizes a game background."""
+        block_size = self.grid_size // 2  # Set the size of the grid block
+        self.game_screen.fill(
+            colors[self.visualization_config["Kitchen"]["ground_tiles_color"]]
+        )
+        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)
+                pygame.draw.rect(
+                    self.game_screen,
+                    self.visualization_config["Kitchen"]["background_lines"],
+                    rect,
+                    1,
+                )
+
+    def draw_image(self, img_path, size, pos, rot_angle=0):
+        cache_entry = f"{img_path}"
+        if cache_entry in self.image_cache_dict.keys():
+            image = self.image_cache_dict[cache_entry]
+        else:
+            image = pygame.image.load(
+                ROOT_DIR / "gui_2d_vis" / img_path
+            ).convert_alpha()
+            self.image_cache_dict[cache_entry] = image
+
+        image = pygame.transform.scale(image, (size, size))
+        if rot_angle != 0:
+            image = pygame.transform.rotate(image, rot_angle)
+        rect = image.get_rect()
+        rect.center = pos
+        self.game_screen.blit(image, rect)
+
+    def draw_players(self, state):
+        """Visualizes the players as circles with a triangle for the facing direction.
+        If the player holds something in their hands, it is displayed
+
+        Args:
+            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.grid_size
+                )
+                self.draw_image(img_path, size, pos, angle)
+
+            else:
+                size = player.radius * self.grid_size
+                color1 = self.player_colors[p_idx]
+                color2 = colors["white"]
+
+                pygame.draw.circle(self.game_screen, color2, pos, size)
+                pygame.draw.circle(self.game_screen, BLUE, pos, size, width=1)
+                pygame.draw.circle(self.game_screen, colors[color1], pos, size // 2)
+
+                facing = player.facing_direction
+                pygame.draw.polygon(
+                    self.game_screen,
+                    BLUE,
+                    (
+                        (
+                            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.grid_size),
+                            pos[1] + (facing[0] * 0.1 * self.grid_size),
+                        ),
+                        pos + (facing * 0.5 * self.grid_size),
+                    ),
+                )
+
+            if SHOW_INTERACTION_RANGE:
+                pygame.draw.circle(
+                    self.game_screen,
+                    BLUE,
+                    player.facing_point * self.grid_size,
+                    player.interaction_range * self.grid_size,
+                    width=1,
+                )
+                pygame.draw.circle(
+                    self.game_screen,
+                    colors["red1"],
+                    player.facing_point * self.grid_size,
+                    4,
+                )
+                pygame.draw.circle(
+                    self.game_screen, colors["red1"], player.facing_point, 4
+                )
+
+            if player.holding is not None:
+                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.game_screen,
+                    colors[self.player_colors[p_idx]],
+                    rect=pygame.Rect(
+                        pos[0] - (self.grid_size // 2),
+                        pos[1] - (self.grid_size // 2),
+                        self.grid_size,
+                        self.grid_size,
+                    ),
+                    width=2,
+                )
+
+    def draw_thing(
+        self, pos: npt.NDArray[float], parts: list[dict[str]], scale: float = 1.0
+    ):
+        """Draws an item, based on its visual parts specified in the visualization config.
+
+        Args:
+            pos: Where to draw the item parts.
+            parts: The visual parts to draw.
+            scale: Rescale the item by this factor.
+        """
+
+        for part in parts:
+            part_type = part["type"]
+            match part_type:
+                case "image":
+                    self.draw_image(
+                        parts[0]["path"],
+                        parts[0]["size"] * scale * self.grid_size,
+                        pos,
+                    )
+                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.game_screen, color, rect)
+                    else:
+                        rect = pygame.Rect(
+                            pos[0] - (height / 2),
+                            pos[1] - (width / 2),
+                            height,
+                            width,
+                        )
+                    pygame.draw.rect(self.game_screen, color, rect)
+                case "circle":
+                    radius = part["radius"] * self.grid_size
+                    color = colors[part["color"]]
+                    if "center_offset" in part:
+                        pygame.draw.circle(
+                            self.game_screen,
+                            color,
+                            pos + (np.array(part["center_offset"]) * self.grid_size),
+                            radius,
+                        )
+                    else:
+                        pygame.draw.circle(self.game_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.
+        The visual composition of the item is read in from visualization.yaml file, where it is specified as
+        different parts to be drawn.
+
+        Args:
+            pos: The position of the item to draw.
+            item: The item do be drawn in the game.
+            scale: Rescale the item by this factor.
+        """
+
+        if not isinstance(item, Meal):
+            if item.name in self.visualization_config:
+                self.draw_thing(
+                    pos, self.visualization_config[item.name]["parts"], scale=scale
+                )
+
+        if isinstance(item, (ProgressibleItem, Plate)) and not item.finished:
+            self.draw_progress_bar(pos, item.progressed_steps, item.steps_needed)
+
+        if isinstance(item, CookingEquipment) and item.content:
+            self.draw_item(pos, item.content)
+
+        if isinstance(item, Meal):
+            if item.finished:
+                if item.name in self.visualization_config:
+                    self.draw_thing(pos, self.visualization_config[item.name]["parts"])
+            else:
+                for idx, o in enumerate(item.parts):
+                    triangle_offsets = create_polygon(len(item.parts), length=10)
+                    self.draw_item(pos + triangle_offsets[idx], o, scale=0.6)
+
+    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.grid_size * 0.2
+            progress_width = (current / needed) * self.grid_size
+            progress_bar = pygame.Rect(
+                pos[0] - (self.grid_size / 2),
+                pos[1] - (self.grid_size / 2) + self.grid_size - bar_height,
+                progress_width,
+                bar_height,
+            )
+            pygame.draw.rect(self.game_screen, colors["green1"], progress_bar)
+
+    def draw_counter(self, counter):
+        """Visualization 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.
+        """
+
+        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(pos, self.visualization_config[str(counter)]["parts"])
+        else:
+            self.draw_thing(
+                pos,
+                self.visualization_config[counter.__class__.__name__]["parts"],
+            )
+
+        if counter.occupied_by is not None:
+            # Multiple plates on plate return:
+            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([pos[0], pos[1] - (i * 3)]), o)
+            # All other items:
+            else:
+                self.draw_item(pos, counter.occupied_by)
+
+    def draw_counters(self, state):
+        """Visualizes the counters in the environment.
+
+        Args:
+            state: The game state returned by the environment.
+        """
+        for counter in state["counters"]:
+            self.draw_counter(counter)
+            if SHOW_COUNTER_CENTERS:
+                pygame.draw.circle(self.game_screen, colors["green1"], counter.pos, 3)
+
+    def draw(self, state):
+        """Main visualization function.
+
+        Args:
+            state: The game state returned by the environment.
+        """
+
+        self.draw_background()
+
+        self.draw_counters(state)
+        self.draw_players(state)
+        self.manager.draw_ui(self.game_screen)
+
+    def init_ui_elements(self):
+        self.manager = pygame_gui.UIManager((self.window_width, self.window_height))
+        self.manager.get_theme().load_theme(ROOT_DIR / "gui_2d_vis" / "gui_theme.json")
+
+        button_width, button_height = 200, 60
+        self.start_button = pygame_gui.elements.UIButton(
+            relative_rect=pygame.Rect(
+                (
+                    (self.window_width // 2) - button_width // 2,
+                    (self.window_height / 2) - button_height // 2,
+                ),
+                (button_width, button_height),
+            ),
+            text="Start Game",
+            manager=self.manager,
+        )
+        self.start_button.can_hover()
+
+        self.quit_button = pygame_gui.elements.UIButton(
+            relative_rect=pygame.Rect(
+                (
+                    (self.window_width - button_width),
+                    0,
+                ),
+                (button_width, button_height),
+            ),
+            text="Quit Game",
+            manager=self.manager,
+        )
+        self.quit_button.can_hover()
+
+        self.finished_button = pygame_gui.elements.UIButton(
+            relative_rect=pygame.Rect(
+                (
+                    (self.window_width - button_width),
+                    (self.window_height - button_height),
+                ),
+                (button_width, button_height),
+            ),
+            text="End screen",
+            manager=self.manager,
+        )
+        self.finished_button.can_hover()
+
+        self.back_button = pygame_gui.elements.UIButton(
+            relative_rect=pygame.Rect(
+                (
+                    (0),
+                    (self.window_height - button_height),
+                ),
+                (button_width, button_height),
+            ),
+            text="Back to Start",
+            manager=self.manager,
+        )
+        self.back_button.can_hover()
+
+        self.score_rect = pygame.Rect(
+            (
+                (self.window_width // 2) - button_width // 2,
+                (self.window_height / 2) - button_height // 2,
+            ),
+            (button_width, button_height),
+        )
+
+        self.score_label = pygame_gui.elements.UILabel(
+            text=f"Your score: _",
+            relative_rect=self.score_rect,
+            manager=self.manager,
+            object_id="#score_label",
+        )
+
+        layout_file_paths = [
+            str(p.name)
+            for p in (ROOT_DIR / "game_content" / "layouts").glob("*.layout")
+        ]
+        assert len(layout_file_paths) != 0, "No layout files."
+        dropdown_width, dropdown_height = 200, 40
+        self.layout_selection = pygame_gui.elements.UIDropDownMenu(
+            relative_rect=pygame.Rect(
+                (
+                    0,
+                    0,
+                ),
+                (dropdown_width, dropdown_height),
+            ),
+            manager=self.manager,
+            options_list=layout_file_paths,
+            starting_option=layout_file_paths[-1],
+        )
+
+    def setup_windows(self):
+        (
+            self.window_width,
+            self.window_height,
+            self.game_width,
+            self.game_height,
+            self.grid_size,
+        ) = self.init_window_sizes()
+
+        self.game_screen = pygame.Surface(
+            (
+                self.game_width,
+                self.game_height,
+            ),
+        )
+
+        self.main_window = pygame.display.set_mode(
+            (
+                self.window_width,
+                self.window_height,
+            )
+        )
+        self.player_colors = self.create_player_colors()
+
+    def setup_simulation(self, config_path, layout_path):
+        self.simulator = Simulator(config_path, layout_path, 600)
+        number_player = len(self.player_names)
+        for i in range(number_player):
+            player_name = f"p{i}"
+            self.simulator.register_player(player_name)
+        self.simulator.start()
+
+    def manage_button_visibility(self):
+        match self.menu_state:
+            case MenuStates.Start:
+                self.back_button.hide()
+                self.quit_button.show()
+                self.start_button.show()
+                self.score_label.hide()
+                self.finished_button.hide()
+                self.layout_selection.show()
+            case MenuStates.Game:
+                self.start_button.hide()
+                self.back_button.show()
+                self.score_label.hide()
+                self.finished_button.show()
+                self.layout_selection.hide()
+            case MenuStates.End:
+                self.start_button.hide()
+                self.back_button.show()
+                self.score_label.show()
+                self.score_label.set_text(
+                    f"Your Score is {self.simulator.env.game_score.score}"
+                )
+                self.finished_button.hide()
+                self.layout_selection.hide()
+
+    def start_button_press(self):
+        self.menu_state = MenuStates.Game
+
+        layout_path = (
+            ROOT_DIR
+            / "game_content"
+            / "layouts"
+            / self.layout_selection.selected_option
+        )
+        config_path = ROOT_DIR / "game_content" / "environment_config.yaml"
+
+        self.setup_simulation(config_path, layout_path)
+        self.setup_windows()
+        self.init_ui_elements()
+        log.debug("Pressed start button")
+
+    def back_button_press(self):
+        self.simulator.stop()
+        self.menu_state = MenuStates.Start
+        log.debug("Pressed back button")
+
+    def quit_button_press(self):
+        self.simulator.stop()
+        self.running = False
+        log.debug("Pressed quit button")
+
+    def finished_button_press(self):
+        self.simulator.stop()
+        self.menu_state = MenuStates.End
+        log.debug("Pressed finished button")
+
+    def start_pygame(self):
+        """Starts pygame and the gui loop. Each frame the game state is visualized and keyboard inputs are read."""
+        log.debug(f"Starting pygame gui at {self.FPS} fps")
+        pygame.init()
+        pygame.font.init()
+
+        self.setup_windows()
+        self.init_ui_elements()
+
+        pygame.display.set_caption("Simple Overcooked Simulator")
+
+        clock = pygame.time.Clock()
+
+        self.manage_button_visibility()
+
+        # Game loop
+        self.running = True
+        while self.running:
+            try:
+                time_delta = clock.tick(self.FPS) / 1000.0
+
+                for event in pygame.event.get():
+                    if event.type == pygame.QUIT:
+                        self.running = False
+                    if event.type == pygame_gui.UI_BUTTON_PRESSED:
+                        match event.ui_element:
+                            case self.start_button:
+                                self.start_button_press()
+                            case self.back_button:
+                                self.back_button_press()
+                            case self.finished_button:
+                                self.finished_button_press()
+                            case self.quit_button:
+                                self.quit_button_press()
+
+                        self.manage_button_visibility()
+
+                    if (
+                        event.type in [pygame.KEYDOWN, pygame.KEYUP]
+                        and self.menu_state == MenuStates.Game
+                    ):
+                        self.handle_key_event(event)
+
+                    self.manager.process_events(event)
+
+                # drawing:
+
+                self.main_window.fill(colors["lemonchiffon1"])
+                self.manager.draw_ui(self.main_window)
+
+                match self.menu_state:
+                    case MenuStates.Start:
+                        pass
+                    case MenuStates.Game:
+                        self.draw_background()
+
+                        self.handle_keys()
+
+                        state = self.simulator.get_state()
+                        self.draw(state)
+
+                        game_screen_rect = self.game_screen.get_rect()
+                        game_screen_rect.center = [
+                            self.window_width // 2,
+                            self.window_height // 2,
+                        ]
+
+                        self.main_window.blit(self.game_screen, game_screen_rect)
+
+                    case MenuStates.End:
+                        pygame.draw.rect(
+                            self.game_screen, colors["cornsilk1"], self.score_rect
+                        )
+                self.manager.update(time_delta)
+                pygame.display.flip()
+
+            except KeyboardInterrupt:
+                self.simulator.stop()
+                pygame.quit()
+                sys.exit()
+
+        self.simulator.stop()
+        pygame.quit()
+        sys.exit()
diff --git a/overcooked_simulator/pygame_gui/visualization.yaml b/overcooked_simulator/gui_2d_vis/visualization.yaml
similarity index 96%
rename from overcooked_simulator/pygame_gui/visualization.yaml
rename to overcooked_simulator/gui_2d_vis/visualization.yaml
index f9f278ef76e63c7fd2524b5cbf82fb8aa3b029ce..5cef5d26cd8be74c201ed6c220d1e6b87cc4d5a8 100644
--- a/overcooked_simulator/pygame_gui/visualization.yaml
+++ b/overcooked_simulator/gui_2d_vis/visualization.yaml
@@ -1,5 +1,12 @@
 # colors: https://www.webucator.com/article/python-color-constants-module/
 
+GameWindow:
+  WhatIsFixed: window_width  # entweder grid oder window_width
+  size: 600
+  screen_margin: 100
+  start_width: 600
+  start_height: 600
+
 Kitchen:
   ground_tiles_color: sgigray76
   background_lines: gray79
diff --git a/overcooked_simulator/main.py b/overcooked_simulator/main.py
index 239779f471d534e3e9e4cb186735b01c24630226..86caba35763a863735582b4f0e0fb32c3402bae7 100644
--- a/overcooked_simulator/main.py
+++ b/overcooked_simulator/main.py
@@ -7,7 +7,7 @@ from datetime import datetime
 import pygame
 
 from overcooked_simulator import ROOT_DIR
-from overcooked_simulator.pygame_gui.pygame_gui import PyGameGUI
+from overcooked_simulator.gui_2d_vis.overcooked_gui import PyGameGUI
 from overcooked_simulator.simulation_runner import Simulator
 
 log = logging.getLogger(__name__)
@@ -50,12 +50,9 @@ def main():
         pygame.K_i,
     ]
     keys2 = [pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s, pygame.K_f, pygame.K_e]
-    gui = PyGameGUI(simulator, [f"p{i}" for i in range(number_player)], [keys1, keys2])
 
-    simulator.start()
+    gui = PyGameGUI(simulator, [f"p{i}" for i in range(number_player)], [keys1, keys2])
     gui.start_pygame()
-
-    simulator.stop()
     sys.exit()
 
 
diff --git a/overcooked_simulator/overcooked_environment.py b/overcooked_simulator/overcooked_environment.py
index 8a51ecf4570d6eb912c7be00db3a2560a0ebe759..8f5adf962fed07d207ac034821c4978edb3a3d47 100644
--- a/overcooked_simulator/overcooked_environment.py
+++ b/overcooked_simulator/overcooked_environment.py
@@ -2,6 +2,7 @@ from __future__ import annotations
 
 import logging
 import random
+from datetime import timedelta
 from pathlib import Path
 from threading import Lock
 
@@ -23,6 +24,7 @@ from overcooked_simulator.counters import (
 )
 from overcooked_simulator.game_items import ItemInfo, ItemType
 from overcooked_simulator.player import Player
+from overcooked_simulator.utils import create_init_env_time
 
 log = logging.getLogger(__name__)
 
@@ -82,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()
@@ -118,6 +120,9 @@ class Environment:
             "+": SinkAddon,
         }
 
+        self.kitchen_height: int = 0
+        self.kitchen_width: int = 0
+
         (
             self.counters,
             self.designated_player_positions,
@@ -128,8 +133,7 @@ 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]:
         with open(self.item_info_path, "r") as file:
@@ -156,16 +160,20 @@ class Environment:
         Args:
             layout_file: Path to the layout file.
         """
-        current_y: float = self.counter_side_length / 2
+        current_y: float = 0.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 = 0.5
             for character in line:
                 character = character.capitalize()
                 pos = np.array([current_x, current_y])
@@ -180,8 +188,12 @@ 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_width -= 0.5
 
         return counters, designated_player_positions, free_positions
 
@@ -331,9 +343,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))
 
@@ -351,10 +361,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))
 
@@ -388,16 +395,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:
@@ -420,23 +426,21 @@ 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
 
-    def step(self):
+    def step(self, passed_time: timedelta):
         """Performs a step of the environment. Affects time based events such as cooking or cutting things, orders
         and time limits.
         """
+        self.env_time += passed_time
         with self.lock:
             for counter in self.counters:
                 if isinstance(counter, (CuttingBoard, Stove, Sink, PlateDispenser)):
-                    counter.progress()
+                    counter.progress(passed_time=passed_time, now=self.env_time)
 
     def get_state(self):
         """Get the current state of the game environment. The state here is accessible by the current python objects.
@@ -467,9 +471,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)
@@ -484,3 +486,7 @@ class Environment:
         return list(
             filter(lambda counter: isinstance(counter, counter_type), self.counters)
         )
+
+    def reset_env_time(self):
+        self.env_time = create_init_env_time()
+        log.debug(f"Reset env time to {self.env_time}")
diff --git a/overcooked_simulator/player.py b/overcooked_simulator/player.py
index c4b5fbaaf3db37ec31c9b18ccc5ced63f93dceb9..4f85046ff9a100c8b0b95a43246a9acccaff4b04 100644
--- a/overcooked_simulator/player.py
+++ b/overcooked_simulator/player.py
@@ -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,
diff --git a/overcooked_simulator/pygame_gui/images/bun.png b/overcooked_simulator/pygame_gui/images/bun.png
deleted file mode 100644
index 2c2f180610dbfd664acb61d2d733d7a3df75e2e5..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/bun.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/cooked_patty.png b/overcooked_simulator/pygame_gui/images/cooked_patty.png
deleted file mode 100644
index 3d5b9270e569211eca7e971b21e8e9db944ac9bc..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/cooked_patty.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/cutting_board_large.png b/overcooked_simulator/pygame_gui/images/cutting_board_large.png
deleted file mode 100644
index 8f50132ce6b8646ec1f35f1599c7210f7d0e1c4f..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/cutting_board_large.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/lettuce.png b/overcooked_simulator/pygame_gui/images/lettuce.png
deleted file mode 100644
index 937a06b30c0bae8e0c28836f04450b68be21d5ff..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/lettuce.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/lettuce_cut.png b/overcooked_simulator/pygame_gui/images/lettuce_cut.png
deleted file mode 100644
index 70c5c623d3d09ef84ca41a167ec47b7b1b26690a..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/lettuce_cut.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/lettuce_cut_smaller.png b/overcooked_simulator/pygame_gui/images/lettuce_cut_smaller.png
deleted file mode 100644
index 0fc897f72a779a998a264fce5ed4363bd8813d32..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/lettuce_cut_smaller.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/lettuce_smaller.png b/overcooked_simulator/pygame_gui/images/lettuce_smaller.png
deleted file mode 100644
index 6c0abbda27f4ac859d8965d8c0828d0685277c08..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/lettuce_smaller.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/meat.png b/overcooked_simulator/pygame_gui/images/meat.png
deleted file mode 100644
index ff750e1c4858d0bab5dd2434966ee38c7f88e085..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/meat.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/onion_cut.png b/overcooked_simulator/pygame_gui/images/onion_cut.png
deleted file mode 100644
index f33ec9ab41c1aea7fbe6553891db86032346d29e..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/onion_cut.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/onion_large.png b/overcooked_simulator/pygame_gui/images/onion_large.png
deleted file mode 100644
index dd70c1a5dd8a271c353909e4717ebe3629e80d54..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/onion_large.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/onion_soup_plate.png b/overcooked_simulator/pygame_gui/images/onion_soup_plate.png
deleted file mode 100644
index 89a81f7b27509ce34005d3752949e1c4a1dd3084..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/onion_soup_plate.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/onion_soup_pot.png b/overcooked_simulator/pygame_gui/images/onion_soup_pot.png
deleted file mode 100644
index 35ee354b302c94fe9c70a3502a1ebbfd2616cb54..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/onion_soup_pot.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/pan.png b/overcooked_simulator/pygame_gui/images/pan.png
deleted file mode 100644
index afb288156faee0fdbb6917de0b18e0e1b698862d..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/pan.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/pot_smaller.png b/overcooked_simulator/pygame_gui/images/pot_smaller.png
deleted file mode 100644
index 5f8d29c3f66beba620e518b09e210783ff43ebe1..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/pot_smaller.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/raw_fish.png b/overcooked_simulator/pygame_gui/images/raw_fish.png
deleted file mode 100644
index a096f867280ade64f925c4fe61d1e445ab961508..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/raw_fish.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/raw_patty.png b/overcooked_simulator/pygame_gui/images/raw_patty.png
deleted file mode 100644
index 85a42e2a04efbddf49c99e23705f192e7d089e3b..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/raw_patty.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/sink.png b/overcooked_simulator/pygame_gui/images/sink.png
deleted file mode 100644
index b191df7d898ef980f082e6de1cae5b862c4d6757..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/sink.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/images/sink_large.png b/overcooked_simulator/pygame_gui/images/sink_large.png
deleted file mode 100644
index 0758d02bc6f4b2c80cfd4c984f8914b74bb0ff83..0000000000000000000000000000000000000000
Binary files a/overcooked_simulator/pygame_gui/images/sink_large.png and /dev/null differ
diff --git a/overcooked_simulator/pygame_gui/pygame_gui.py b/overcooked_simulator/pygame_gui/pygame_gui.py
deleted file mode 100644
index 9efaabe7e36f5749f68bf8f6b02675bf8b26f09c..0000000000000000000000000000000000000000
--- a/overcooked_simulator/pygame_gui/pygame_gui.py
+++ /dev/null
@@ -1,487 +0,0 @@
-import colorsys
-import logging
-import math
-import sys
-from collections import deque
-
-import numpy as np
-import numpy.typing as npt
-import pygame
-import yaml
-from scipy.spatial import KDTree
-
-from overcooked_simulator import ROOT_DIR
-from overcooked_simulator.counters import Counter
-from overcooked_simulator.game_items import (
-    ProgressibleItem,
-    Item,
-    CookingEquipment,
-    Meal,
-    Plate,
-)
-from overcooked_simulator.overcooked_environment import Action
-from overcooked_simulator.pygame_gui.game_colors import BLUE
-from overcooked_simulator.pygame_gui.game_colors import colors, Color
-from overcooked_simulator.simulation_runner import Simulator
-
-USE_PLAYER_COOK_SPRITES = True
-SHOW_INTERACTION_RANGE = False
-SHOW_COUNTER_CENTERS = False
-
-
-def create_polygon(n, length):
-    if n == 0:
-        return np.array([0, 0])
-
-    vector = np.array([length, 0])
-    angle = (2 * np.pi) / n
-
-    rot_matrix = np.array(
-        [[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]]
-    )
-
-    vecs = [vector]
-    for i in range(n - 1):
-        vector = np.dot(rot_matrix, vector)
-        vecs.append(vector)
-
-    return vecs
-
-
-log = logging.getLogger(__name__)
-
-
-class PlayerKeySet:
-    """Set of keyboard keys for controlling a player.
-    First four keys are for movement. Order: Down, Up, Left, Right.
-    5th key is for interacting with counters.
-    6th key ist for picking up things or dropping them.
-
-    """
-
-    def __init__(self, player_name: str, keys: list[pygame.key]):
-        """Creates a player key set which contains information about which keyboard keys control the player.
-        Movement keys in the following order: Down, Up, Left, Right
-
-        Args:
-            player_name: The name of the player to control.
-            keys: The keys which control this player in the following order: Down, Up, Left, Right, Interact, Pickup.
-        """
-        self.name = player_name
-        self.player_keys = keys
-        self.move_vectors = [[-1, 0], [1, 0], [0, -1], [0, 1]]
-        self.key_to_movement = {
-            key: vec for (key, vec) in zip(self.player_keys[:-2], self.move_vectors)
-        }
-        self.interact_key = self.player_keys[-2]
-        self.pickup_key = self.player_keys[-1]
-
-
-class PyGameGUI:
-    """Visualisation of the overcooked environment and reading keyboard inputs using pygame."""
-
-    def __init__(
-        self,
-        simulator: Simulator,
-        player_names: list[str],
-        player_keys: list[pygame.key],
-    ):
-        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
-
-        self.player_key_sets: list[PlayerKeySet] = [
-            PlayerKeySet(player_name, keys)
-            for player_name, keys in zip(
-                self.player_names, self.player_keys[: len(self.player_names)]
-            )
-        ]
-
-        # TODO cache loaded images?
-        with open(ROOT_DIR / "pygame_gui" / "visualization.yaml", "r") as file:
-            self.visualization_config = yaml.safe_load(file)
-
-        self.images_path = ROOT_DIR / "pygame_gui" / "images"
-
-        self.player_colors = self.create_player_colors()
-
-        self.image_cache_dict = {}
-
-    def create_player_colors(self) -> list[Color]:
-        number_player = len(self.simulator.env.players)
-        hue_values = np.linspace(0, 1, number_player + 1)
-
-        colors_vec = np.array([col for col in colors.values()])
-
-        tree = KDTree(colors_vec)
-
-        color_names = list(colors.keys())
-
-        player_colors = []
-        for hue in hue_values:
-            rgb = colorsys.hsv_to_rgb(hue, 1, 1)
-            query_color = np.array([int(c * 255) for c in rgb])
-            _, index = tree.query(query_color, k=1)
-            player_colors.append(color_names[index])
-
-        return player_colors
-
-    def send_action(self, action: Action):
-        """Sends an action to the game environment.
-
-        Args:
-            action: The action to be sent. Contains the player, action type and move direction if action is a movement.
-        """
-        self.simulator.enter_action(action)
-
-    def handle_keys(self):
-        """Handles keyboard inputs. Sends action for the respective players. When a key is held down, every frame
-        an action is sent in this function.
-        """
-        keys = pygame.key.get_pressed()
-        for player_idx, key_set in enumerate(self.player_key_sets):
-            relevant_keys = [keys[k] for k in key_set.player_keys]
-            if any(relevant_keys[:-2]):
-                move_vec = np.zeros(2)
-                for idx, pressed in enumerate(relevant_keys[:-2]):
-                    if pressed:
-                        move_vec += key_set.move_vectors[idx]
-                if np.linalg.norm(move_vec) != 0:
-                    move_vec = move_vec / np.linalg.norm(move_vec)
-
-                action = Action(key_set.name, "movement", move_vec)
-                self.send_action(action)
-
-    def handle_key_event(self, event):
-        """Handles key events for the pickup and interaction keys. Pickup is a single action,
-        for interaction keydown and keyup is necessary, because the player has to be able to hold
-        the key down.
-
-        Args:
-            event: Pygame event for extracting the key action.
-        """
-        for key_set in self.player_key_sets:
-            if event.key == key_set.pickup_key and event.type == pygame.KEYDOWN:
-                action = Action(key_set.name, "pickup", "pickup")
-                self.send_action(action)
-
-            if event.key == key_set.interact_key:
-                if event.type == pygame.KEYDOWN:
-                    action = Action(key_set.name, "interact", "keydown")
-                    self.send_action(action)
-                elif event.type == pygame.KEYUP:
-                    action = Action(key_set.name, "interact", "keyup")
-                    self.send_action(action)
-
-    def draw_background(self):
-        """Visualizes a game background."""
-        block_size = self.counter_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)
-                pygame.draw.rect(
-                    self.screen,
-                    self.visualization_config["Kitchen"]["background_lines"],
-                    rect,
-                    1,
-                )
-
-    def draw_image(self, img_path, size, pos, rot_angle=0):
-        cache_entry = f"{img_path}"
-        if cache_entry in self.image_cache_dict.keys():
-            image = self.image_cache_dict[cache_entry]
-        else:
-            image = pygame.image.load(
-                ROOT_DIR / "pygame_gui" / img_path
-            ).convert_alpha()
-            self.image_cache_dict[cache_entry] = image
-
-        image = pygame.transform.scale(image, (size, size))
-        if rot_angle != 0:
-            image = pygame.transform.rotate(image, rot_angle)
-        rect = image.get_rect()
-        rect.center = pos
-        self.screen.blit(image, rect)
-
-    def draw_players(self, state):
-        """Visualizes the players as circles with a triangle for the facing direction.
-        If the player holds something in their hands, it is displayed
-
-        Args:
-            state: The game state returned by the environment.
-        """
-        for p_idx, player in enumerate(state["players"].values()):
-            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.draw_image(img_path, size, player.pos, angle)
-
-            else:
-                pos = player.pos
-                size = player.radius * self.counter_size
-                color1 = self.player_colors[p_idx]
-                color2 = colors["white"]
-
-                pygame.draw.circle(self.screen, color2, pos, size)
-                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.counter_size),
-                            pos[1] + (facing[0] * 0.1 * self.counter_size),
-                        ),
-                        player.pos + (facing * 0.5 * self.counter_size),
-                    ),
-                )
-
-            if SHOW_INTERACTION_RANGE:
-                pygame.draw.circle(
-                    self.screen,
-                    BLUE,
-                    player.facing_point,
-                    player.interaction_range * self.counter_size,
-                    width=1,
-                )
-                pygame.draw.circle(self.screen, colors["red1"], player.facing_point, 4)
-
-            if player.holding is not None:
-                holding_item_pos = player.pos + (20 * player.facing_direction)
-                self.draw_item(holding_item_pos, player.holding)
-
-            if player.current_nearest_counter:
-                counter: Counter = player.current_nearest_counter
-                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,
-                    ),
-                    width=2,
-                )
-
-    def draw_thing(
-        self, part_pos: npt.NDArray[float], parts: list[dict[str]], scale: float = 1.0
-    ):
-        """Draws an item, based on its visual parts specified in the visualization config.
-
-        Args:
-            pos: Where to draw the item parts.
-            parts: The visual parts to draw.
-            scale: Rescale the item by this factor.
-        """
-        for part in parts:
-            pos = part_pos.copy()
-
-            part_type = part["type"]
-            if part_type == "image":
-                if "center_offset" in part:
-                    pos += np.array(part["center_offset"]) * self.counter_size
-                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,
-                    )
-                else:
-                    pygame.draw.circle(self.screen, color, pos, radius)
-
-    def draw_item(
-        self, pos: npt.NDArray[float], item: Item, scale: float = 1.0, plate=False
-    ):
-        """Visualization 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:
-            pos: The position of the item to draw.
-            item: The item do be drawn in the game.
-            scale: Rescale the item by this factor.
-            plate: Conditional drawing if the item is on a plate, relevant for soup.
-        """
-
-        if not isinstance(item, Meal):
-            if item.name in self.visualization_config:
-                self.draw_thing(
-                    pos, self.visualization_config[item.name]["parts"], scale=scale
-                )
-
-        if isinstance(item, (ProgressibleItem, Plate)) and not item.finished:
-            self.draw_progress_bar(pos, item.progressed_steps, item.steps_needed)
-
-        if isinstance(item, CookingEquipment) and item.content:
-            self.draw_item(pos, item.content, plate=isinstance(item, Plate))
-
-        if isinstance(item, Meal):
-            if item.finished:
-                if item.name in self.visualization_config:
-                    if "Soup" in item.name and plate:
-                        self.draw_thing(
-                            pos, self.visualization_config[item.name + "Plate"]["parts"]
-                        )
-                    else:
-                        self.draw_thing(
-                            pos, self.visualization_config[item.name]["parts"]
-                        )
-            else:
-                for idx, o in enumerate(item.parts):
-                    triangle_offsets = create_polygon(len(item.parts), length=10)
-                    self.draw_item(pos + triangle_offsets[idx], o, scale=0.6)
-
-    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
-            progress_bar = pygame.Rect(
-                pos[0] - (self.counter_size / 2),
-                pos[1] - (self.counter_size / 2) + self.counter_size - bar_height,
-                progress_width,
-                bar_height,
-            )
-            pygame.draw.rect(self.screen, colors["green1"], progress_bar)
-
-    def draw_counter(self, counter):
-        """Visualization 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.
-        """
-
-        self.draw_thing(counter.pos, self.visualization_config["Counter"]["parts"])
-        if str(counter) in self.visualization_config:
-            self.draw_thing(
-                counter.pos, self.visualization_config[str(counter)]["parts"]
-            )
-        else:
-            self.draw_thing(
-                counter.pos,
-                self.visualization_config[counter.__class__.__name__]["parts"],
-            )
-
-        if counter.occupied_by is not None:
-            # Multiple plates on plate return:
-            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
-                        )
-            # All other items:
-            else:
-                self.draw_item(counter.pos, counter.occupied_by)
-
-    def draw_counters(self, state):
-        """Visualizes the counters in the environment.
-
-        Args:
-            state: The game state returned by the environment.
-        """
-        for counter in state["counters"]:
-            self.draw_counter(counter)
-            if SHOW_COUNTER_CENTERS:
-                pygame.draw.circle(self.screen, colors["green1"], counter.pos, 3)
-
-    def draw(self, state):
-        """Main visualization function.
-
-        Args:
-            state: The game state returned by the environment.
-        """
-        self.screen.fill(
-            colors[self.visualization_config["Kitchen"]["ground_tiles_color"]]
-        )
-        self.draw_background()
-
-        self.draw_counters(state)
-        self.draw_players(state)
-
-        pygame.display.flip()
-
-    def start_pygame(self):
-        """Starts pygame and the gui loop. Each frame the game state is visualized and keyboard inputs are read."""
-        log.debug(f"Starting pygame gui at {self.FPS} fps")
-        pygame.init()
-        pygame.font.init()
-
-        self.screen = pygame.display.set_mode((self.window_width, self.window_height))
-        pygame.display.set_caption("Simple Overcooked Simulator")
-        self.screen.fill(
-            colors[self.visualization_config["Kitchen"]["ground_tiles_color"]]
-        )
-
-        clock = pygame.time.Clock()
-
-        # Game loop
-        running = True
-        while running:
-            try:
-                for event in pygame.event.get():
-                    if event.type == pygame.QUIT:
-                        running = False
-                    if event.type in [pygame.KEYDOWN, pygame.KEYUP]:
-                        self.handle_key_event(event)
-
-                self.handle_keys()
-                clock.tick(self.FPS)
-                state = self.simulator.get_state()
-                self.draw(state)
-
-            except KeyboardInterrupt:
-                pygame.quit()
-                self.simulator.stop()
-                sys.exit()
-
-        pygame.quit()
diff --git a/overcooked_simulator/simulation_runner.py b/overcooked_simulator/simulation_runner.py
index 795b61e63a2fb35f6f6802de94e6ffdde8ddf913..8ad41e28ae7bb2834297cadeaa2d06f915e1c87a 100644
--- a/overcooked_simulator/simulation_runner.py
+++ b/overcooked_simulator/simulation_runner.py
@@ -1,5 +1,6 @@
 import logging
 import time
+from datetime import timedelta
 from threading import Thread
 
 import numpy as np
@@ -26,7 +27,7 @@ class Simulator(Thread):
 
     def __init__(
         self,
-        env_layout_path,
+        env_config_path,
         layout_path,
         frequency: int,
         item_info_path=ROOT_DIR / "game_content" / "item_info.yaml",
@@ -39,14 +40,14 @@ class Simulator(Thread):
         self.step_frequency: int = frequency
         self.preferred_sleep_time_ns: float = 1e9 / self.step_frequency
         self.env: Environment = Environment(
-            env_layout_path, layout_path, item_info_path
+            env_config_path, layout_path, item_info_path
         )
 
         super().__init__()
 
-    def step(self):
+    def step(self, passed_time: timedelta):
         """One simulation step of the environment."""
-        self.env.step()
+        self.env.step(passed_time)
 
     def enter_action(self, action: Action):
         """Takes an action and executes it in the environment.
@@ -96,10 +97,10 @@ class Simulator(Thread):
         """Starts the simulator thread. Runs in a loop until stopped."""
 
         overslept_in_ns = 0
-
+        self.env.reset_env_time()
         while not self.finished:
             step_start = time.time_ns()
-            self.step()
+            self.step(timedelta(seconds=overslept_in_ns / 1_000_000_000))
             step_duration = time.time_ns() - step_start
 
             time_to_sleep_ns = self.preferred_sleep_time_ns - (
diff --git a/overcooked_simulator/utils.py b/overcooked_simulator/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e4ab7adac96f14999878ac6acd442f2bc8e03b5
--- /dev/null
+++ b/overcooked_simulator/utils.py
@@ -0,0 +1,7 @@
+from datetime import datetime
+
+
+def create_init_env_time():
+    return datetime(
+        year=2000, month=1, day=1, hour=0, minute=0, second=0, microsecond=0
+    )
diff --git a/setup.py b/setup.py
index 69f30ff36f7dbc7780cf15b9f4f6971aa54da00d..b3ceeba705d5d329be64f2dc239e4de19dbc5056 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ with open("README.md") as readme_file:
 with open("CHANGELOG.md") as history_file:
     history = history_file.read()
 
-requirements = ["numpy", "pygame", "scipy", "pytest>=3", "pyyaml"]
+requirements = ["numpy", "pygame", "scipy", "pytest>=3", "pyyaml", "pygame-gui"]
 
 test_requirements = [
     "pytest>=3",
diff --git a/tests/test_start.py b/tests/test_start.py
index a8fc103ec0eb8457e6bb2403031ff931dbb49a2b..64fce11daf8fb14381605e96180e55b2db40e827 100644
--- a/tests/test_start.py
+++ b/tests/test_start.py
@@ -1,4 +1,5 @@
 import time
+from datetime import timedelta
 
 import numpy as np
 import pytest
@@ -6,8 +7,9 @@ import pytest
 from overcooked_simulator import ROOT_DIR
 from overcooked_simulator.counters import Counter, CuttingBoard
 from overcooked_simulator.game_items import CuttableItem
-from overcooked_simulator.overcooked_environment import Action
+from overcooked_simulator.overcooked_environment import Action, Environment
 from overcooked_simulator.simulation_runner import Simulator
+from overcooked_simulator.utils import create_init_env_time
 
 layouts_folder = ROOT_DIR / "game_content" / "layouts"
 
@@ -51,9 +53,12 @@ def test_simulator_frequency():
         def __init__(self):
             self.c = 0
 
-        def step(self):
+        def step(self, passed_time):
             self.c += 1
 
+        def reset_env_time(self):
+            pass
+
     frequency = 2000
     running_time_seconds = 2
 
@@ -68,7 +73,6 @@ def test_simulator_frequency():
     time.sleep(running_time_seconds)
     sim.stop()
 
-    print(sim.env.c)
     accepted_tolerance = 0.02
     lower = frequency * running_time_seconds * (1 - accepted_tolerance)
     upper = frequency * running_time_seconds * (1 + accepted_tolerance)
@@ -82,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)
@@ -94,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?"
 
 
@@ -105,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"]
 
@@ -142,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."
 
@@ -163,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]))
@@ -214,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 = [counter]
+    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
 
@@ -243,3 +247,24 @@ def test_processing():
     sim.enter_action(button_up)
 
     sim.stop()
+
+
+def test_time_passed():
+    np.random.seed(42)
+    env = Environment(
+        ROOT_DIR / "game_content" / "environment_config.yaml",
+        layouts_folder / "empty.layout",
+        ROOT_DIR / "game_content" / "item_info.yaml",
+    )
+    env.reset_env_time()
+    passed_time = timedelta(seconds=10)
+    env.step(passed_time)
+    assert (
+        env.env_time == create_init_env_time() + passed_time
+    ), "Env time needs to be updated via the step function"
+
+    passed_time_2 = timedelta(seconds=12)
+    env.step(passed_time_2)
+    assert (
+        env.env_time == create_init_env_time() + passed_time + passed_time_2
+    ), "Env time needs to be updated via the step function"