Ejemplo n.º 1
0
    def startUp(self):
        assert len(self.names) == len(self.spawns) and len(self.spawns) == len(self.goals), "All player related arrays should be of equal size."
        # Initialise the goal colliders.
        self.goal_colliders = []
        self.team_scores = []
        self.locateBots()
        self.BOTS_PER_TEAM = math.ceil(len(self.robots) / len(self.names))

        self.ball_centre = objectFactory(**{
            'collider': 'inherit',
            'visual': {
                'name': 'Circle',
                'radius': 0.1
            },
            'physics': True,
            'key': 'IR-BALL',
        })
        self.ball_centre.shape.sensor = True
        self.ball_centre.shape.collision_type = self.BALL_COLLISION_TYPE
        World.instance.registerObject(self.ball_centre)

        handler = World.instance.space.add_collision_handler(self.BALL_COLLISION_TYPE, self.GOAL_COLLISION_TYPE)
        def handle_collide(arbiter, space, data):
            a, b = arbiter.shapes
            if hasattr(a, 'goal_index'):
                self.goalScoredIn(a.goal_index)
            elif hasattr(b, 'goal_index'):
                self.goalScoredIn(b.goal_index)
            else:
                raise ValueError("Two objects with collision types used by soccer don't have a goal index.")
            return False
        handler.begin = handle_collide

        for x in range(len(self.names)):
            # Set up goal collider.
            pos = self.goals[x]['position']
            del self.goals[x]['position']
            obj = {
                'collider': 'inherit',
                'visual': self.goals[x],
                'position': pos,
                'physics': True,
                'static': True,
                'key':  f'Goal-{x}',
            }
            self.goal_colliders.append(objectFactory(**obj))
            self.goal_colliders[-1].shape.sensor = True
            self.goal_colliders[-1].shape.collision_type = self.GOAL_COLLISION_TYPE
            self.goal_colliders[-1].shape.goal_index = x
            World.instance.registerObject(self.goal_colliders[-1])
            if self.show_goal_colliders:
                ScreenObjectManager.instance.registerVisual(self.goal_colliders[-1].visual, f'Soccer_DEBUG_collider-{len(self.goal_colliders)}')
            # Set up team scores
            self.team_scores.append(0)
            # Set up team name
            ScriptLoader.instance.object_map[f'name{x+1}Text'].text = self.names[x]
        self.updateScoreText()
        self.resetPositions()
        for robot in self.robots:
            robot.robot_class.onSpawn()
Ejemplo n.º 2
0
    def generateGameColliders(self):
        self.ball_centre = objectFactory(
            **{
                "collider": "inherit",
                "visual": {
                    "name": "Circle",
                    "radius": 0.1
                },
                "physics": True,
                "key": "IR-BALL",
            })
        self.field_ball = ScriptLoader.instance.object_map[
            "centreFieldBallDetector"]
        self.field = ScriptLoader.instance.object_map["centreField"]
        for x in range(len(self.spawns)):
            # Set up goal collider.
            self.goals[x]["zPos"] = 6
            pos = self.goals[x]["position"]
            del self.goals[x]["position"]
            obj = {
                "collider": "inherit",
                "visual": self.goals[x],
                "position": pos,
                "physics": True,
                "static": True,
                "key": f"Goal-{x}",
            }
            self.goal_colliders.append(objectFactory(**obj))
        if SoccerUIInteractor.instance.SHOW_GOAL_COLLIDERS:
            from ev3sim.visual.manager import ScreenObjectManager

            for i, collider in enumerate(self.goal_colliders):
                ScreenObjectManager.instance.registerVisual(
                    collider.visual, f"Soccer_DEBUG_collider-{i}")
Ejemplo n.º 3
0
    def loadElements(self, items):
        # Handle any programmatic color references.
        elements = []
        from ev3sim.devices.base import initialise_device

        for item in items:
            assert "key" in item and "type" in item, f"Each item requires a key and type. {item}"
            if item["type"] == "visual":
                vis = visualFactory(**item)
                vis.key = item["key"]
                ScreenObjectManager.instance.registerVisual(vis, vis.key)
                self.object_map[item["key"]] = vis
                elements.append(vis)
            elif item["type"] == "object":
                devices = []
                to_remove = []
                for x in range(len(item.get("children", []))):
                    if item["children"][x]["type"] == "device":
                        devices.append(item["children"][x])
                        to_remove.append(x)
                for x in to_remove[::-1]:
                    del item["children"][x]
                obj = objectFactory(**item)
                obj.key = item["key"]
                for index, device in enumerate(devices):
                    # Instantiate the devices.
                    initialise_device(device, obj, index)
                if item.get("physics", False):
                    World.instance.registerObject(obj)
                ScreenObjectManager.instance.registerObject(obj, obj.key)
                self.object_map[obj.key] = obj
                elements.append(obj)
        return elements
    def setUpBall(self):
        self.ball_centre = objectFactory(
            **{
                "visual": {"name": "Image", "image_path": "custom/Square Dance/ui/flag.png", "scale": 1.3, "zPos": 3},
                "physics": True,
                "key": "target",
            }
        )
        self.ball_centre.shape.sensor = True
        self.ball_centre.shape.collision_type = self.BALL_COLLISION_TYPE
        self.ball_centre.shape.parent = self.ball_centre
        World.instance.registerObject(self.ball_centre)
        ScreenObjectManager.instance.registerObject(self.ball_centre, "target")

        handler = World.instance.space.add_collision_handler(self.BALL_COLLISION_TYPE, self.BOT_COLLISION_TYPE)
        saved_world_no = World.instance.spawn_no

        def handle_collide(arbiter, space, data):
            if World.instance.spawn_no != saved_world_no:
                return
            a, b = arbiter.shapes
            self.current_index += 1
            if self.current_index < len(self.positions):
                if b.collision_type == self.BALL_COLLISION_TYPE:
                    a, b = b, a
                a.parent.body.position = self.positions[self.current_index]
                a.parent.position = a.parent.body.position
            else:
                a.parent.body.position = [1000, 1000]
                a.parent.position = a.parent.body.position
            ScriptLoader.instance.object_map["positionText"].text = f"{self.current_index}/{len(self.positions)} Targets{'!' if self.current_index == len(self.positions) else '...'}"
            return False

        handler.begin = handle_collide
Ejemplo n.º 5
0
 def spawnRobotFollows(self):
     self.bot_follows = []
     for i in range(len(self.robots)):
         # Spawn the robot follow point collider.
         obj = objectFactory(
             **{
                 "collider": "inherit",
                 "visual": {
                     "name": "Circle",
                     "radius": self.ROBOT_CENTRE_RADIUS,
                     "fill": "#00ff00" if self.SHOW_ROBOT_COLLIDER else None,
                     "stroke_width": 0,
                     "sensorVisible": False,
                     "zPos": 100,
                 },
                 "physics": True,
                 "key": f"Robot-{id}-follow",
             }
         )
         obj.shape.filter = pymunk.ShapeFilter(categories=self.FOLLOW_POINT_CATEGORY)
         obj.shape.sensor = True
         obj.shape.collision_type = self.ROBOT_CENTRE_COLLISION_TYPE
         obj.shape._robot_index = i
         World.instance.registerObject(obj)
         if self.SHOW_ROBOT_COLLIDER:
             ScreenObjectManager.instance.registerObject(obj, obj.key)
         self.bot_follows.append(obj)
Ejemplo n.º 6
0
 def _spawnFollowAtLocationWithIndicies(self, position, indicies):
     key = "Tile-follow-" + "-".join(list(map(str, indicies)))
     obj = objectFactory(
         **{
             "collider": "inherit",
             "visual": {
                 "name": "Circle",
                 "radius": self.FOLLOW_POINT_RADIUS,
                 "fill": self.follow_point_colour(indicies) if self.SHOW_FOLLOW_POINTS else None,
                 "stroke_width": 0,
                 "sensorVisible": False,
                 "zPos": self.maxZpos + 0.2,
             },
             "position": position,
             "physics": True,
             "static": True,
             "key": key,
         }
     )
     obj.shape.filter = pymunk.ShapeFilter(categories=self.FOLLOW_POINT_CATEGORY)
     obj.shape.sensor = True
     obj.shape._follow_indexes = indicies
     obj.shape.collision_type = self.FOLLOW_POINT_COLLISION_TYPE
     World.instance.registerObject(obj)
     if self.SHOW_FOLLOW_POINTS:
         ScreenObjectManager.instance.registerObject(obj, obj.key)
     return obj
Ejemplo n.º 7
0
 def onSpawn(self):
     super().onSpawn()
     # This is a rectangle which will contain the completion rects.
     bounding = self.rescue.tiles[self.index]["ui_spawned"].children[1]
     self.original_fill = bounding.visual.fill
     completion_rect_args = [
         {
             "type": "object",
             "physics": False,
             "visual": {
                 "name": "Rectangle",
                 "width": bounding.visual.width,
                 "height": bounding.visual.height / len(self.shortcuts),
                 "fill": self.original_fill,
                 "stroke": "#000000",
                 "stroke_width": 0,
                 "zPos": 5.5,
             },
             "position": [0, ((len(self.shortcuts) - 1) / 2 - x) * bounding.visual.height / len(self.shortcuts)],
         }
         for x in range(len(self.shortcuts))
     ]
     cur_length = len(bounding.children)
     self.completion_rects = []
     for i, child in enumerate(completion_rect_args):
         child["key"] = bounding.key + f"-child-{i+cur_length}"
         bounding.children.append(objectFactory(**child))
         self.completion_rects.append(bounding.children[-1])
         ScreenObjectManager.instance.registerObject(bounding.children[-1], bounding.children[-1].key)
         bounding.children[-1].parent = bounding
     bounding.updateVisualProperties()
 def loadMap(self, map_path):
     # load map
     custom_dir = find_abs_directory("workspace/custom/")
     full_path = join(custom_dir, "Arrow Maze", map_path)
     with open(full_path, "r") as f:
         conf = yaml.safe_load(f)
     # Despawn old stuff
     for arrow in self.arrows:
         ScreenObjectManager.instance.unregisterVisual(arrow.key)
         for child in arrow.children:
             ScreenObjectManager.instance.unregisterVisual(child.key)
     self.arrows = []
     self.dimensions = conf["dimensions"]
     self.spawn = conf["spawn"]
     self.grid = conf["grid"]
     self.rotation = conf.get("rotation", 0) * math.pi / 180
     # Spawn colours
     for x in range(self.dimensions[0]):
         for y in range(self.dimensions[1]):
             arrow_obj = {
                 "name": "Image",
                 "image_path": 'custom/Arrow Maze/ui/arrow.png',
                 "hAlignment": "m",
                 "vAlignment": "m",
                 "scale": (self.width - self.margin) / 200,
                 "zPos": 1,
             }
             children = [
                 {
                     "visual": arrow_obj,
                 }
             ]
             if self.grid[y][x] == "L":
                 children[0]["rotation"] = math.pi
             elif self.grid[y][x] == "R":
                 children[0]["rotation"] = 0
             elif self.grid[y][x] == "U":
                 children[0]["rotation"] = math.pi / 2
             elif self.grid[y][x] == "D":
                 children[0]["rotation"] = - math.pi / 2
             else:
                 children = []
             c_obj = objectFactory(
                 visual={
                     "name": "Rectangle",
                     "width": self.width - self.margin,
                     "height": self.width - self.margin,
                     "fill": "#ffffff",
                     "stroke_width": 0,
                     "zPos": 0.5
                 },
                 children=children,
                 key=f"sq-{x}-{y}",
                 position=[
                     self.width * (x-self.offset[0]), -self.width * (y-self.offset[1]),
                 ],
             )
             
             ScreenObjectManager.instance.registerObject(c_obj, c_obj.key)
             self.arrows.append(c_obj)
    def setUpBall(self):
        self.ball_centre = objectFactory(
            **{
                "visual": {
                    "name": "Image",
                    "image_path": "custom/Search and Destroy/ui/flag.png",
                    "scale": 1.3,
                    "zPos": 3
                },
                "physics": True,
                "key": "target",
            })
        self.ball_centre.shape.sensor = True
        self.ball_centre.shape.collision_type = self.BALL_COLLISION_TYPE
        World.instance.registerObject(self.ball_centre)
        ScreenObjectManager.instance.registerObject(self.ball_centre, "target")

        handler = World.instance.space.add_collision_handler(
            self.BALL_COLLISION_TYPE, self.BOT_COLLISION_TYPE)
        saved_world_no = World.instance.spawn_no

        def handle_collide(arbiter, space, data):
            if World.instance.spawn_no != saved_world_no:
                return
            a, b = arbiter.shapes
            self.accepted()
            return False

        handler.begin = handle_collide
 def setUpGoal(self):
     self.goal = objectFactory(
         **{
             "visual": {
                 "name": "Rectangle",
                 "width": 5,
                 "height": 20,
                 "fill": "#00ff00",
                 "stroke_width": 0.1,
                 "zPos": 3
             },
             "physics": True,
             "key": "target",
             "position": [57.5, -35]
         })
     self.goal.shape.sensor = True
     self.goal.shape.collision_type = self.GOAL_COLLISION_TYPE
     World.instance.registerObject(self.goal)
     ScreenObjectManager.instance.registerObject(self.goal, "target")
Ejemplo n.º 11
0
    def setUpGoal(self):
        self.alien = objectFactory(
            **{
                "visual": {"name": "Image", "image_path": "custom/Social Distancing/ui/ship.png", "scale": 1, "zPos": 3},
                "physics": True,
                "key": "target",
            }
        )
        World.instance.registerObject(self.alien)
        ScreenObjectManager.instance.registerObject(self.alien, "target")

        self.distance_rect = visualFactory(
            **{
                "name": "Rectangle",
                "width": 5,
                "height": 90,
                "fill": "#00ff00",
                "zPos": 3
            }
        )
        ScreenObjectManager.instance.registerVisual(self.distance_rect, "rect")
Ejemplo n.º 12
0
    def startUp(self):
        assert len(self.names) == len(self.spawns) and len(self.spawns) == len(
            self.goals), "All player related arrays should be of equal size."
        # Initialise the goal colliders.
        self.goal_colliders = []
        self.team_scores = []
        self.locateBots()
        self.BOTS_PER_TEAM = math.ceil(len(self.robots) / len(self.names))

        self.ball_centre = objectFactory(
            **{
                "collider": "inherit",
                "visual": {
                    "name": "Circle",
                    "radius": 0.1
                },
                "physics": True,
                "key": "IR-BALL",
            })
        self.ball_centre.shape.sensor = True
        self.ball_centre.shape.collision_type = self.BALL_COLLISION_TYPE
        World.instance.registerObject(self.ball_centre)

        handler = World.instance.space.add_collision_handler(
            self.BALL_COLLISION_TYPE, self.GOAL_COLLISION_TYPE)

        def handle_collide(arbiter, space, data):
            a, b = arbiter.shapes
            if hasattr(a, "goal_index"):
                self.goalScoredIn(a.goal_index)
            elif hasattr(b, "goal_index"):
                self.goalScoredIn(b.goal_index)
            else:
                raise ValueError(
                    "Two objects with collision types used by soccer don't have a goal index."
                )
            return False

        handler.begin = handle_collide

        # Initialise field collider for ball reset on white
        self.field_ball = ScriptLoader.instance.object_map[
            "centreFieldBallDetector"]
        self.field_ball.shape.sensor = True
        self.field_ball.shape.collision_type = self.FIELD_BALL_COLLISION_TYPE
        if self.BALL_RESET_ON_WHITE:
            handler = World.instance.space.add_collision_handler(
                self.FIELD_BALL_COLLISION_TYPE, self.BALL_COLLISION_TYPE)

            def handle_separate_ball(arbiter, space, data):
                self.out_on_white_tick = self.BALL_RESET_WHITE_DELAY_SECONDS * ScriptLoader.instance.GAME_TICK_RATE
                return False

            def handle_collide_ball(arbiter, space, data):
                self.out_on_white_tick = 0
                return False

            handler.separate = handle_separate_ball
            handler.begin = handle_collide_ball

        # Initialise field collider for out on white
        self.field = ScriptLoader.instance.object_map["centreField"]
        self.field.shape.sensor = True
        self.field.shape.collision_type = self.FIELD_COLLISION_TYPE
        if self.ENFORCE_OUT_ON_WHITE:
            handler = World.instance.space.add_collision_handler(
                self.FIELD_COLLISION_TYPE, self.BOT_COLLISION_TYPE)

            def handle_separate(arbiter, space, data):
                a, b = arbiter.shapes
                if hasattr(a, "bot_index"):
                    self.penaliseBot(a.bot_index)
                elif hasattr(b, "bot_index"):
                    self.penaliseBot(b.bot_index)
                else:
                    raise ValueError(
                        "Two objects with collision types used by soccer don't have a bot index."
                    )
                return False

            handler.separate = handle_separate

        for x in range(len(self.names)):
            # Set up goal collider.
            pos = self.goals[x]["position"]
            del self.goals[x]["position"]
            obj = {
                "collider": "inherit",
                "visual": self.goals[x],
                "position": pos,
                "physics": True,
                "static": True,
                "key": f"Goal-{x}",
            }
            self.goal_colliders.append(objectFactory(**obj))
            self.goal_colliders[-1].shape.sensor = True
            self.goal_colliders[
                -1].shape.collision_type = self.GOAL_COLLISION_TYPE
            self.goal_colliders[-1].shape.goal_index = x
            World.instance.registerObject(self.goal_colliders[-1])
            if self.SHOW_GOAL_COLLIDERS:
                ScreenObjectManager.instance.registerVisual(
                    self.goal_colliders[-1].visual,
                    f"Soccer_DEBUG_collider-{len(self.goal_colliders)}")
            # Set up team scores
            self.team_scores.append(0)
            # Set up team name
            ScriptLoader.instance.object_map[
                f"name{x+1}Text"].text = self.names[x]
        self.updateScoreText()
        self.resetPositions()
        for robot in self.robots:
            robot.robot_class.onSpawn()
    def spawnPosition(self):
        self.setBotPos()

        for but in self.buttons:
            World.instance.unregisterObject(but)
        self.buttons = []

        self.states = [random.randint(0, 2) for _ in range(3)]
        for x in range(3):
            c_key = f"movement_bot_colour-{x}"
            o_key = f"movement_bot-button-{x}"
            if c_key in ScreenObjectManager.instance.objects:
                ScreenObjectManager.instance.unregisterVisual(c_key)
            if o_key in ScreenObjectManager.instance.objects:
                ScreenObjectManager.instance.unregisterVisual(o_key)
            for y in range(3):
                if o_key + f"-{y}" in ScreenObjectManager.instance.objects:
                    ScreenObjectManager.instance.unregisterVisual(o_key +
                                                                  f"-{y}")
            c_obj = visualFactory(
                name="Rectangle",
                width=5,
                height=5,
                position=[
                    self.INDICATOR_POSITIONS[x],
                    -35,
                ],
                fill=self.COLOURS[self.states[x]],
                sensorVisible=True,
                stroke_width=0,
                zPos=0.5,
            )
            ScreenObjectManager.instance.registerVisual(c_obj, c_key)
            buttonLight = visualFactory(
                name="Circle",
                radius=0.5,
                fill=self.COLOURS[self.states[x]],
                position=[
                    self.X_POSITIONS[x],
                    self.Y_POSITIONS[self.states[x]],
                ],
                stroke_width=0,
                zPos=0.6,
            )
            ScreenObjectManager.instance.registerVisual(buttonLight, o_key)
            for y in range(3):
                button = objectFactory(visual={
                    "name": "Rectangle",
                    "width": 5,
                    "height": 5,
                    "fill": "#666666",
                    "stroke_width": 0.1,
                    "stroke": "#ffffff",
                    "zPos": 0.5,
                },
                                       position=[
                                           self.X_POSITIONS[x],
                                           self.Y_POSITIONS[y],
                                       ],
                                       physics=True,
                                       key=o_key + f"-{y}")
                button.shape.sensor = True
                button.shape.collision_type = self.BALL_COLLISION_TYPE
                button.shape.movement_index = (x, y)
                self.buttons.append(button)
                World.instance.registerObject(button)
                ScreenObjectManager.instance.registerObject(
                    button, o_key + f"-{y}")

        self.restartBots()
 def loadMap(self, map_path):
     # load map
     custom_dir = find_abs_directory("workspace/custom/")
     full_path = join(custom_dir, "Memory Maze", map_path)
     with open(full_path, "r") as f:
         conf = yaml.safe_load(f)
     # Despawn old stuff
     for col in self.colours:
         ScreenObjectManager.instance.unregisterVisual(col.key)
     self.colours = []
     for wall in self.walls:
         ScreenObjectManager.instance.unregisterVisual(wall.key)
         World.instance.unregisterObject(wall)
     self.walls = []
     self.dimensions = conf["dimensions"]
     self.spawn = conf["spawn"]
     self.passcode = conf["passcode"]
     self.colour_map = conf["colours"]
     self.wall_map = conf["walls"]
     self.rotation = conf.get("rotation", 0) * math.pi / 180
     # Spawn colours
     for x in range(self.dimensions[0]):
         for y in range(self.dimensions[1]):
             index = self.colour_map[y * self.dimensions[0] + x]
             if index == "_": continue
             c_key = f"movement_bot_colour-{x}-{y}"
             c_obj = visualFactory(
                 name="Rectangle",
                 width=self.width - self.margin,
                 height=self.width - self.margin,
                 position=[
                     self.width * (x - self.offset[0]),
                     -self.width * (y - self.offset[1]),
                 ],
                 fill=self.COLOURS[index],
                 sensorVisible=True,
                 stroke_width=0,
                 zPos=0.5,
             )
             c_obj.key = c_key
             ScreenObjectManager.instance.registerVisual(c_obj, c_key)
             self.colours.append(c_obj)
     # Spawn walls
     # First, vertical
     for x in range(self.dimensions[0] + 1):
         for y in range(self.dimensions[1]):
             if self.wall_map[(y + 1) * self.dimensions[0] + y *
                              (self.dimensions[0] + 1) + x] == "*":
                 wall_key = f"movement_bot_wall-vert-{x}-{y}"
                 wall_obj = objectFactory(
                     visual={
                         "name": "Rectangle",
                         "height": self.width,
                         "width": 2,
                         "stroke_width": 0,
                         "fill": "#000000",
                         "zPos": 0.7,
                     },
                     position=[
                         (x - 0.5 - self.offset[0]) * self.width,
                         -self.width * (y - self.offset[1]),
                     ],
                     rotation=0,
                     physics=True,
                     static=True,
                     key=wall_key)
                 self.walls.append(wall_obj)
                 World.instance.registerObject(wall_obj)
                 ScreenObjectManager.instance.registerObject(
                     wall_obj, wall_key)
     # Next, horizontal
     for x in range(self.dimensions[0]):
         for y in range(self.dimensions[1] + 1):
             if self.wall_map[y * (2 * self.dimensions[0] + 1) + x] == "*":
                 wall_key = f"movement_bot_wall-horizontal-{x}-{y}"
                 wall_obj = objectFactory(
                     visual={
                         "name": "Rectangle",
                         "height": 2,
                         "width": self.width,
                         "stroke_width": 0,
                         "fill": "#000000",
                         "zPos": 0.7,
                     },
                     position=[
                         (x - self.offset[0]) * self.width,
                         -self.width * (y - self.offset[1] - 0.5),
                     ],
                     rotation=0,
                     physics=True,
                     static=True,
                     key=wall_key)
                 self.walls.append(wall_obj)
                 World.instance.registerObject(wall_obj)
                 ScreenObjectManager.instance.registerObject(
                     wall_obj, wall_key)
Ejemplo n.º 15
0
    def handleEvents(self):
        from ev3sim.simulation.loader import StateHandler, ScriptLoader

        events = list(pygame.event.get()) + self.unhandled_events
        self.unhandled_events = []
        for event in events:
            if not StateHandler.instance.is_running:
                break
            self.screens[self.screen_stack[-1]].process_events(event)
            self.screens[self.screen_stack[-1]].handleEvent(event)
            if event.type == pygame.VIDEORESIZE:
                self.SCREEN_WIDTH, self.SCREEN_HEIGHT = event.size
                self._SCREEN_WIDTH_ACTUAL, self._SCREEN_HEIGHT_ACTUAL = self.SCREEN_WIDTH, self.SCREEN_HEIGHT
                # Preserve a 4:3 ratio.
                if self.SCREEN_WIDTH / self.SCREEN_HEIGHT < 4 / 3:
                    self.SCREEN_HEIGHT = int(self.SCREEN_WIDTH * 3 / 4)
                else:
                    self.SCREEN_WIDTH = int(self.SCREEN_HEIGHT * 4 / 3)
                self.screen = pygame.display.set_mode(
                    (self._SCREEN_WIDTH_ACTUAL, self._SCREEN_HEIGHT_ACTUAL), pygame.RESIZABLE
                )
                for key, menu in self.screens.items():
                    menu.setSize((self._SCREEN_WIDTH_ACTUAL, self._SCREEN_HEIGHT_ACTUAL))
                for interactor in ScriptLoader.instance.active_scripts:
                    if hasattr(interactor, "setSize"):
                        interactor.setSize((self._SCREEN_WIDTH_ACTUAL, self._SCREEN_HEIGHT_ACTUAL))
                for screen in self.screen_stack:
                    if screen == self.SCREEN_SIM:
                        for key in self.sorting_order:
                            self.objects[key].calculatePoints()
                    self.screens[screen].regenerateObjects()

            if event.type == pygame.QUIT:
                StateHandler.instance.is_running = False
            if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                if len(self.screen_stack) == 1:
                    StateHandler.instance.is_running = False
                else:
                    self.popScreen()
            if event.type == EV3SIM_BOT_COMMAND and event.command_type == CommandSystem.TYPE_DRAW:
                try:
                    possible_keys = []
                    for key in ScriptLoader.instance.object_map.keys():
                        if key.startswith(event.robot_id):
                            possible_keys.append(key)
                    if len(possible_keys) == 0:
                        break
                    possible_keys.sort(key=len)
                    parent_bot = ScriptLoader.instance.object_map[possible_keys[0]]

                    key = event.robot_id + "-" + event.payload["key"]
                    to_remove = []
                    for x, child in enumerate(parent_bot.children):
                        if child.key == key:
                            to_remove.append(x)
                    for x in to_remove[::-1]:
                        del parent_bot.children[x]

                    from ev3sim.objects.base import objectFactory

                    obj = objectFactory(
                        physics=False,
                        visual=event.payload["obj"],
                        position=event.payload["obj"].get("position", [0, 0]),
                        rotation=event.payload["obj"].get("rotation", 0),
                        key=key,
                    )
                    if event.payload.get("on_bot", False):
                        parent_bot.children.append(obj)
                        obj.parent = parent_bot
                        parent_bot.updateVisualProperties()
                    life = event.payload.get("life", 3)
                    self.registerVisual(obj.visual, key, kill_time=life, overwrite_key=True)
                except:
                    pass
        return events
    def startUp(self):
        super().startUp()
        self.posted = False
        self.ball = objectFactory(
            **{
                "visual": {"name": "Circle", "radius": 2, "fill": "#000000", "zPos": 10},
                "physics": True,
                "key": "falling_ball",
                "position": [0, 130],
                "friction": 0.75
            }
        )
        self.ball.shape.collision_type = self.BALL_COLLISION_TYPE
        World.instance.registerObject(self.ball)
        ScreenObjectManager.instance.registerObject(self.ball, self.ball.key)

        ended_cutoffs = [0] + self.CUTOFFS + [self.N_POINTS]
        sq_width = 200 / self.N_POINTS * 0.8
        barricade_width = (200 - (sq_width * self.N_POINTS)) / self.N_POINTS
        for x in range(1, len(ended_cutoffs)):
            for y in range(ended_cutoffs[x-1], ended_cutoffs[x]):
                key = f"square_{y}"
                square = objectFactory(
                    **{
                        "visual": {"name": "Rectangle", "width": sq_width, "height": 10, "fill": f"area_{x}_color", "zPos": 3},
                        "physics": True,
                        "key": key,
                        "position": [
                            200 * (y + 0.5) / self.N_POINTS - 100,
                            -70,
                        ]
                    }
                )
                square.shape.sensor = True
                square.shape.collision_type = self.SQUARE_COLLISION_TYPE
                square.shape.sq_index = (x+1, y+1)
                World.instance.registerObject(square)
                ScreenObjectManager.instance.registerObject(square, key)
                num = visualFactory(
                    **{
                        "name": "Text",
                        "text": str(y+1),
                        "font_style": "fonts/Poppins-Regular.ttf",
                        "fill": "#000000",
                        "font_size": 24,
                        "position": [
                            200 * (y + 0.5) / self.N_POINTS - 100,
                            -70,
                        ],
                        "hAlignment": "m",
                        "vAlignment": "m",
                        "zPos": 5,
                        "key": f"text_{y}",
                    }
                )
                ScreenObjectManager.instance.registerVisual(num, f"text_{y}")
        for y in range(self.N_POINTS + 1):
            key = f"barricade_{y}"
            barricade = objectFactory(
                **{
                    "visual": {"name": "Rectangle", "width": barricade_width, "height": 15, "fill": "#000000", "zPos": 3},
                    "physics": True,
                    "static": True,
                    "key": key,
                    "position": [
                        y * 200 / self.N_POINTS - 100,
                        -67.5,
                    ]
                }
            )
            World.instance.registerObject(barricade)
            ScreenObjectManager.instance.registerObject(barricade, key)
        for x in range(self.bumper_lines):
            more = x % 2 == 0
            for y in range(self.double_spots // 2 + more):
                key = f"bumper_{x}_{y}"
                position = [
                    200 / (self.double_spots + 1) * ((2*y+1) if more else (2*y+2)) - 100,
                    -55 + (x+1) * self.bumper_y_distance,
                ]
                bumper = objectFactory(
                    **{
                        "visual": {"name": "Circle", "radius": self.bumper_radius, "fill": "#000000", "zPos": 3},
                        "physics": True,
                        "static": True,
                        "key": key,
                        "position": position,
                    }
                )
                World.instance.registerObject(bumper)
                ScreenObjectManager.instance.registerObject(bumper, key)
        ScriptLoader.instance.object_map["drop"].shape.sensor = True

        handler = World.instance.space.add_collision_handler(self.BALL_COLLISION_TYPE, self.SQUARE_COLLISION_TYPE)
        saved_world_no = World.instance.spawn_no

        def handle_collide(arbiter, space, data):
            if World.instance.spawn_no != saved_world_no:
                return
            a, b = arbiter.shapes
            if not hasattr(a, "sq_index"):
                a, b = b, a
            self.onFallen(a.sq_index)
            return False

        handler.begin = handle_collide