def afterPhysics(self): for i, obj in enumerate(self.generated): obj.position = local_space_to_world_space( self.relative_location + local_space_to_world_space(self.relative_positions[i], self.relative_rotation, np.array([0, 0])), self.physical_object.rotation, self.physical_object.position, ) obj.rotation = self.physical_object.rotation + self.relative_rotation
def afterPhysics(self): for i, obj in enumerate(self.generated): obj.position = local_space_to_world_space( self.relative_location + local_space_to_world_space(self.relative_positions[i], self.relative_rotation, np.array([0, 0])), self.physical_object.rotation, self.physical_object.position, ) if obj.key == (self.getPrefix() + "relative_north"): obj.rotation = self.device_class.global_rotation - self.do_rotation else: obj.rotation = self.physical_object.rotation + self.relative_rotation
def afterPhysics(self): from ev3sim.objects.base import PhysicsObject for i, obj in enumerate(self.generated): obj.position = local_space_to_world_space( self.relative_location + local_space_to_world_space( self.relative_positions[i], self.relative_rotation, np.array([0, 0])), self.physical_object.rotation, self.physical_object.position, ) obj.rotation = self.physical_object.rotation + self.relative_rotation if isinstance(obj, PhysicsObject): obj.body.position = obj.position obj.body.angle = obj.rotation
def calculatePoints(self): try: tmp = self.rotation, self.position except: return for i, v in enumerate(self.verts): self.points[i] = utils.worldspace_to_screenspace(local_space_to_world_space(v, self.rotation, self.position))
def spawnAt(self, tileIndex): self.can_scored_this_spawn = False self.resetFollows() spawn_point = ( self.tiles[tileIndex]["follows"][0][0][0] if isinstance(self.tiles[tileIndex]["follows"][0], (list, tuple)) else self.tiles[tileIndex]["follows"][0] ) for i in range(len(self.robots)): self.robots[i].body.angle = self.tiles[tileIndex]["rotation"] if self.tiles[tileIndex]["flip"]: self.robots[i].body.angle = self.robots[i].body.angle + np.pi self.bot_follows[i].body.position = [ float(v) for v in local_space_to_world_space( ScriptLoader.instance.robots[f"Robot-{i}"]._follow_collider_offset, self.robots[i].body.angle, (self.robots[i].body.position.x, self.robots[i].body.position.y), ) ] self.robots[i].body.position = [ a + b - c for a, b, c in zip(self.robots[i].body.position, spawn_point, self.bot_follows[i].body.position) ] self.robots[i].body.velocity = (0, 0) self.robots[i].body.angular_velocity = 0 self.touchBot()
def startUp(self): super().startUp() self.START_TIME = datetime.timedelta(minutes=self.GAME_LENGTH_MINUTES) self.spawnTiles() self.spawnFollowPointPhysics() self.spawnTileUI() self.spawnRobotFollows() assert len(self.robots) <= len(self.BOT_SPAWN_POSITION), "Not enough spawning locations specified." self.spawnCan() self.reset() for i in range(len(self.robots)): # This is bad, I should get the robot key somehow else (Generally speaking the robot class, interactor and object should be more tightly coupled.) self.bot_follows[i].body.position = [ float(v) for v in local_space_to_world_space( ScriptLoader.instance.robots[f"Robot-{i}"]._follow_collider_offset, self.robots[i].body.angle, (self.robots[i].body.position.x, self.robots[i].body.position.y), ) ] self.addCollisionHandler() for robot in self.robots: robot.robot_class.onSpawn()
def onReset(self): super().onReset() self.tunnelTop.body.position = [ float(v) for v in local_space_to_world_space( [0, 9], self.rescue.tiles[self.index]["rotation"], self.rescue.tiles[self.index]["all_elems"][0].position, ) ] self.tunnelBot.body.position = [ float(v) for v in local_space_to_world_space( [0, -9], self.rescue.tiles[self.index]["rotation"], self.rescue.tiles[self.index]["all_elems"][0].position, ) ]
def changeForce(self, force): # Reduce the force by a factor # args[0]: slow factor if self.force_type == "slow": return force * self.force_args[0] # Reduce the force by a factor in a certain direction. # args[0]: normalised vector to slow by # args[1]: slow factor if self.force_type == "slow_dir": parallel = np.dot( force, local_space_to_world_space( self.force_args[0], self.rotation, [0, 0])) * local_space_to_world_space( self.force_args[0], self.rotation, [0, 0]) perpendicular = force - parallel parallel *= self.force_args[1] return perpendicular + parallel raise ValueError(f"Unknown Force Effect Type {self.force_type}")
def _applyMotors(self, object, position, rotation): # Look at motor global position for any force modification fields. pos = local_space_to_world_space(object.body.position, rotation, position) new_force = self.applied_force * np.array( [np.cos(rotation), np.sin(rotation)]) shapes = World.instance.space.point_query( [float(v) for v in pos], 0.0, pymunk.ShapeFilter(mask=STATIC_CATEGORY)) if shapes: max_z = max(pq.shape.obj.clickZ for pq in shapes) shapes = [pq for pq in shapes if pq.shape.obj.clickZ == max_z] for pq in shapes: if pq.shape.obj.affectsForce: new_force = pq.shape.obj.changeForce(new_force) object.apply_force(new_force, pos=position)
def spawnTiles(self): self.tiles = [] for i, tile in enumerate(self.TILE_DEFINITIONS): self.tiles.append({}) import yaml path = find_abs(tile["path"], allowed_areas=preset_locations()) with open(path, "r") as f: t = yaml.safe_load(f) self.maxZpos = 0 base_pos = np.array(tile.get("position", [0, 0])) # Transfer to rescue space. base_pos = [base_pos[0] * self.TILE_LENGTH, base_pos[1] * self.TILE_LENGTH] base_rotation = tile.get("rotation", 0) * np.pi / 180 flip = tile.get("flip", False) for obj in t["elements"]: rel_pos = np.array(obj.get("position", [0, 0])) if flip: rel_pos[0] = -rel_pos[0] if obj.get("name", "") == "Image": obj["flip"] = [True, False] if obj.get("name", "") == "Arc": obj["rotation"] = 180 - obj.get("rotation", 0) obj["angle"] = -obj["angle"] obj["rotation"] = (obj.get("rotation", 0)) * np.pi / 180 + base_rotation obj["position"] = local_space_to_world_space(rel_pos, base_rotation, base_pos) obj["sensorVisible"] = True k = obj["key"] obj["key"] = f"Tile-{i}-{k}" self.maxZpos = max(self.maxZpos, obj.get("zPos", 0)) t["elements"].append( { "position": local_space_to_world_space(np.array([0, 0]), base_rotation, base_pos), "rotation": base_rotation, "type": "visual", "name": "Rectangle", "width": self.TILE_LENGTH, "height": self.TILE_LENGTH, "fill": None, "stroke_width": 0.1, "stroke": "rescue_outline_color", "zPos": self.maxZpos + 0.1, "key": f"Tile-{i}-outline", "sensorVisible": False, } ) self.tiles[-1]["type"] = t.get("type", "follow") self.tiles[-1]["follows"] = [] self.tiles[-1]["roam_status"] = [] self.tiles[-1]["world_pos"] = base_pos self.tiles[-1]["rotation"] = base_rotation self.tiles[-1]["flip"] = flip if self.tiles[-1]["type"] == "follow": self.tiles[-1]["entries"] = t["entries"] self.tiles[-1]["exits"] = t["exits"] mname, cname = t.get("checker").rsplit(".", 1) import importlib klass = getattr(importlib.import_module(mname), cname) with open(find_abs(t["ui"], allowed_areas=preset_locations()), "r") as f: self.tiles[-1]["ui_elem"] = yaml.safe_load(f) for j, point in enumerate(t["follow_points"]): if isinstance(point[0], (list, tuple)): self.tiles[-1]["follows"].append([]) self.tiles[-1]["roam_status"].append([]) for path in point: self.tiles[-1]["follows"][-1].append([]) self.tiles[-1]["roam_status"][-1].append([]) for point2 in path: if isinstance(point2, str): self.tiles[-1]["roam_status"][-1][-1][-1] = point2 else: if flip: point2[0] = -point2[0] self.tiles[-1]["follows"][-1][-1].append( local_space_to_world_space( np.array(point2), tile.get("rotation", 0) * np.pi / 180, base_pos ) ) self.tiles[-1]["roam_status"][-1][-1].append(None) else: if isinstance(point, str): self.tiles[-1]["roam_status"][-1] = point else: if flip: point[0] = -point[0] self.tiles[-1]["follows"].append( local_space_to_world_space( np.array(point), tile.get("rotation", 0) * np.pi / 180, base_pos ) ) self.tiles[-1]["roam_status"].append(None) self.tiles[-1]["checker"] = klass(self.tiles[-1]["follows"], i, self, **t.get("checker_kwargs", {})) else: self.tiles[-1]["green_conns"] = t.get("green_conns", []) self.tiles[-1]["all_elems"] = ScriptLoader.instance.loadElements(t["elements"]) connecting_objs = [] for tile in self.tiles: # We need to add connections between green tiles if they exist. if tile["type"] == "follow": continue under, right, under_right = self._checkConnectingRescueTiles(tile["world_pos"]) if under_right and under and right: # Draw a big square connecting all 4 tiles. key = "c1-" + str(tile["world_pos"][0]) + "-" + str(tile["world_pos"][1]) connecting_objs.append( { "type": "visual", "name": "Rectangle", "width": 50, "height": 50, "fill": "grass_color", "zPos": 0.3, "key": key, "position": [ tile["world_pos"][0] + self.TILE_LENGTH / 2, tile["world_pos"][1] + self.TILE_LENGTH / 2, ], "sensorVisible": True, } ) else: if under: key = "c2-" + str(tile["world_pos"][0]) + "-" + str(tile["world_pos"][1]) connecting_objs.append( { "type": "visual", "name": "Rectangle", "width": 20, "height": 50, "fill": "grass_color", "zPos": 0.3, "key": key, "position": [tile["world_pos"][0], tile["world_pos"][1] + self.TILE_LENGTH / 2], "sensorVisible": True, } ) if right: key = "c3-" + str(tile["world_pos"][0]) + "-" + str(tile["world_pos"][1]) connecting_objs.append( { "type": "visual", "name": "Rectangle", "width": 50, "height": 20, "fill": "grass_color", "zPos": 0.3, "key": key, "position": [tile["world_pos"][0] + self.TILE_LENGTH / 2, tile["world_pos"][1]], "sensorVisible": True, } ) self.connecting_objs = ScriptLoader.instance.loadElements(connecting_objs)
def tick(self, tick): super().tick(tick) self.cur_tick = tick for i in range(len(self.robots)): self.bot_follows[i].body.position = [ float(v) for v in local_space_to_world_space( ScriptLoader.instance.robots[f"Robot-{i}"]._follow_collider_offset, self.robots[i].body.angle, (self.robots[i].body.position.x, self.robots[i].body.position.y), ) ] # Ensure visual is not 1 frame behind. self.bot_follows[i].position = np.array(self.bot_follows[i].body.position) if self.current_follow is not None and not World.instance.paused: distance = magnitude_sq( self.bot_follows[i].position - self._recurseObj(self.tiles[self.current_follow[0]]["follows"], self.current_follow[1:]) ) if distance > self.MAX_FOLLOW_DIST * self.MAX_FOLLOW_DIST and not self.roaming[i]: self.lackOfProgress(i) if self.roaming[i] and not World.instance.paused: # Check we are still in the tile. Kinda bad. if ( abs(self.bot_follows[i].position[0] - self.tiles[self.roam_tile[i]]["world_pos"][0]) > self.TILE_LENGTH / 2 or abs(self.bot_follows[i].position[1] - self.tiles[self.roam_tile[i]]["world_pos"][1]) > self.TILE_LENGTH / 2 ) and magnitude_sq( self.bot_follows[i].position - self._recurseObj(self.tiles[self.roam_tile[i]]["follows"], self.roaming[i][1]) ) > ( self.ROBOT_CENTRE_RADIUS + self.FOLLOW_POINT_RADIUS + 0.05 ) * ( self.ROBOT_CENTRE_RADIUS + self.FOLLOW_POINT_RADIUS + 0.05 ): self.lackOfProgress(i) if not World.instance.paused: x = (self.bot_follows[i].position[0] + self.TILE_LENGTH / 2) // self.TILE_LENGTH y = (self.bot_follows[i].position[1] + self.TILE_LENGTH / 2) // self.TILE_LENGTH for tile in self.tiles: tx = (tile["world_pos"][0] + self.TILE_LENGTH / 2) // self.TILE_LENGTH ty = (tile["world_pos"][1] + self.TILE_LENGTH / 2) // self.TILE_LENGTH if tx == x and ty == y: if tile["type"] == "rescue" and self.modes[i] == self.MODE_FOLLOW: self.modes[i] = self.MODE_RESCUE # For reentry. self.resetFollows() self.current_follow = None elif tile["type"] == "follow" and self.modes[i] == self.MODE_RESCUE: self.modes[i] = self.MODE_FOLLOW if self.can_scored_this_spawn: self.scoreReEntry() break else: self.lackOfProgress(i) if not self.can_scored_this_spawn: cx = (self.can_obj.position[0] + self.TILE_LENGTH / 2) // self.TILE_LENGTH cy = (self.can_obj.position[1] + self.TILE_LENGTH / 2) // self.TILE_LENGTH for tile in self.tiles: tx = (tile["world_pos"][0] + self.TILE_LENGTH / 2) // self.TILE_LENGTH ty = (tile["world_pos"][1] + self.TILE_LENGTH / 2) // self.TILE_LENGTH if tx == cx and ty == cy: if tile["type"] != "rescue": self.scoreCan() rel_pos_x = self.can_obj.position[0] - tile["world_pos"][0] rel_pos_y = self.can_obj.position[1] - tile["world_pos"][1] sx = 1 sy = 1 if rel_pos_x < 0: rel_pos_x = -rel_pos_x sx = -1 if rel_pos_y < 0: rel_pos_y = -rel_pos_y sy = -1 if rel_pos_y < self.TILE_LENGTH / 3 and rel_pos_x < self.TILE_LENGTH / 3: break under, right, under_right = self._checkConnectingRescueTiles(tile["world_pos"], sx, sy) if under_right and under and right: # We can't be outside of the area. break if under: if rel_pos_x < self.TILE_LENGTH / 3: break if right: if rel_pos_y < self.TILE_LENGTH / 3: break self.scoreCan() break else: self.scoreCan() for i in range(len(self.tiles)): if self.tiles[i]["type"] == "follow": self.tiles[i]["checker"].tick(tick) # UI Tick if self._pressed: ScriptLoader.instance.object_map["controlsReset"].visual.image_path = "ui/controls_reset_pressed.png" else: ScriptLoader.instance.object_map["controlsReset"].visual.image_path = "ui/controls_reset_released.png" self.update_time()