def debug_world(world: esper.World, *with_components: Type[Any]) -> None: data = [] for ent, _ in world.get_components(*with_components): components = world.components_for_entity(ent) data.append(dict({"ent": ent}, **{str(type(c)): c for c in components})) print(tabulate.tabulate(data))
def _get_target_point(self, world: World, entity: int) -> Optional[Tuple[int, int]]: if entity is self.__target: return None # Prepare data try: self_position = world.component_for_entity(entity, Position) target_position = world.component_for_entity(self.__target, Position) target_velocity = world.component_for_entity(self.__target, Velocity) except KeyError: return None v_self_position = np.array([self_position.x, self_position.y]) v_target_position = np.array([target_position.x, target_position.y]) v_target_velocity = np.array([target_velocity.x, target_velocity.y]) # Calculate navigation target v_navigation_target = v_target_position if self.__distance > 0: # Adjust for follow distance and go there target_velocity_size = np.linalg.norm(v_target_velocity) if target_velocity_size > 0: v_follow_velocity = v_target_velocity / target_velocity_size else: v_follow_velocity = v_target_position - v_self_position v_follow_velocity = v_follow_velocity / np.linalg.norm(v_follow_velocity) v_follow_velocity *= -1 * self.__distance v_navigation_target = v_target_position + v_follow_velocity else: # Navigate right to where the target will be next tick v_navigation_target = v_target_position + v_target_velocity return (v_navigation_target[0], v_navigation_target[1])
def path_from_mxCell(cell: Element, draw2entity, world: esper.World): """Extracts the points of a path from XML.""" logger = logging.getLogger(__name__) points = [] lastPoint = None geometry = cell[0] # Check if there's a source object - 1st point if 'source' in cell.attrib: source_ent = draw2entity.get(cell.attrib['source'], None) if source_ent is None: raise DependencyNotFound("Path source not found") source_pos = world.component_for_entity(source_ent[0], Position) points.append(source_pos.center) for el in geometry: if el.tag == 'mxPoint': if el.attrib['as'] == 'targetPoint': lastPoint = parse_mxPoint(el) else: points.append(parse_mxPoint(el)) elif el.tag == 'Array' and el.attrib['as'] == 'points': for p in el: points.append(parse_mxPoint(p)) else: logger.error(f'Path object has unknown element {el} in cell geometry') raise Exception('Failed to create Path') if lastPoint: points.append(lastPoint) # Check if there's a target object - Last point if 'target' in cell.attrib: target_ent = draw2entity.get(cell.attrib['target'], None) if target_ent is None: raise DependencyNotFound("Path target not found") target_pos = world.component_for_entity(target_ent[0], Position) points.append(target_pos.center) return points
def __init__(self): self.world = World() self.world.add_processor(DisplayProcessor(), priority=30) self.world.add_processor(InputProcessor(), priority=20) self.world.add_processor(GameStateProcessor(), priority=100) self.world.create_entity(GameState.TITLE_SCREEN)
def color_item_name(world: World, entity: int) -> str: name = "item" for item in world.try_component(entity, Item): name = item.name for display in world.try_component(entity, Display): color = hex(display.color).upper()[2:] return f"[color=#{color}]{name}[/color]" else: return name
def get_blocked_tiles(world: World) -> Set[Tuple[int, int]]: blocked = set() blocked.update( (position.x, position.y) for _, (position, _) in world.get_components(Position, Player) ) blocked.update( (position.x, position.y) for _, (position, _) in world.get_components(Position, Monster) ) return blocked
class Main: def __init__(self): self.world = World() self.world.add_processor(DisplayProcessor(), priority=30) self.world.add_processor(InputProcessor(), priority=20) self.world.add_processor(GameStateProcessor(), priority=100) self.world.create_entity(GameState.TITLE_SCREEN) def core_game_loop(self): while True: self.world.process()
def build_object(cell: Element, world: esper.World, window_options, draw2entity: dict): logger = logging.getLogger(__name__) mxCell = cell[0] points = path_from_mxCell(mxCell, draw2entity, world) obj = mxCell.attrib.get('source', None) (ent, _) = draw2entity.get(obj, (None, None)) if ent is None: raise DependencyNotFound('Path origin not found') else: logger.debug(f"Adding path to entity {ent}") world.add_component(ent, Path(points)) return {}, [], {}
def build_object(cell, world: esper.World, window_options, draw2entity): logger = logging.getLogger(__name__) mxCell = cell[0] points = path_from_mxCell(mxCell, draw2entity, world) if len(points) <= 1: raise Exception(f'Map path has {len(points)} points. Minimum is 2.') # Entity 1 is the simulation entity if world.has_component(1, Map): simulation_map = world.component_for_entity(1, Map) else: simulation_map = Map() world.add_component(1, simulation_map) add_nodes_from_points(simulation_map, points) return {}, [], {}
def build_object(cell, world: World, window_options, draw2entity): (components, style) = mxCellDecoder.parse_object(cell, window_options) ent = world.create_entity() # Custom components for key, val in cell.attrib.items(): if key.startswith('component_'): component_name = key[10:] # removes "component_" from the name init_values = json.loads(val) component = dynamic_importer.init_component( component_name, init_values) components.append(component) print(components) for c in components: world.add_component(ent, c) return {style['id']: [ent, style]}, [(ent, style['id'])], {}
def ParseFile(lines: Iterable[str], world: esper.World): working = world.create_entity() world.add_component(working, Passport(True)) for line in lines: words = line.strip().split() if not words: working = world.create_entity() world.add_component(working, Passport(True)) for word in words: tag, value = word.split(":") world.add_component(working, FIELD_TO_COMPONENT[tag](value))
def asteroid(world: esper.World) -> int: global asteroid_counter asteroid_counter += 1 return world.create_entity( Renderable("#", colors.OBJECT_JUNK), Selectable(), Destructable(20, 100, 0), Velocity(0, 0), Name("Asteroid", f"AST-{asteroid_counter:05d}") )
def build_object(cell, world: World, *args) -> Tuple[dict, list, dict]: area_name = cell.attrib['label'] max_resources = cell.attrib.get('max_resources', 0) geometry = cell[0][0] x = geometry.attrib['x'] y = geometry.attrib['y'] kitchen_area = KitchenArea(area_name, int(max_resources), (float(x), float(y))) kitchen_layout = world.component_for_entity(1, KitchenLayout) kitchen_layout.areas[area_name] = kitchen_area return {}, [], {}
def enemy_fighter(world: esper.World) -> int: return world.create_entity( Position(10, 10), Renderable("V", colors.OBJECT_ENEMY), Velocity(0, 0), Acceleration(0, 0, 0.001), Selectable(), Destructable(10, 20, 20), Damageable(), Behaviour(), Name("Some wanker", "WNK-80085") )
def build_object(object, world: esper.World, window_options, draw2entity): logger = logging.getLogger(__name__) mxCell = object[0] mxGeometry = mxCell[0] # Get X, Y coordinates x = float(mxGeometry.attrib.get('x', 0)) y = float(mxGeometry.attrib.get('y', 0)) width = float(mxGeometry.attrib.get('width', 0)) height = float(mxGeometry.attrib.get('height', 0)) pos = Position(x, y, 0, width, height) x += (width // 2) y += (height // 2) # Get the Map for simulation or create one # Entity 1 is the simulation entity if world.has_component(1, Map): simulation_map = world.component_for_entity(1, Map) else: simulation_map = Map() world.add_component(1, simulation_map) # Get POI tag if 'tag' in object.attrib: tag = object.attrib['tag'] else: tag = 'POI_' + str(len(simulation_map.pois)) logger.warning(f'POI ({x}, {y}) with no TAG. Using {tag}') simulation_map.pois[tag] = (x, y) # Alternatively display the POI if object.attrib.get('display', False): skeleton = Skeleton(object.attrib['id'], mxCell.attrib['style'], tag) world.create_entity(pos, skeleton) return {}, [], {}
def player_ship(world: esper.World) -> int: return world.create_entity( Player(), Position(0, 0), Renderable("@", colors.OBJECT_PLAYER), Velocity(0, 0), Acceleration(0, 0, 0.001), Selectable(), Destructable(1000, 1000, 1000), Damageable(), Behaviour(), Name("Player ship", "PLR-12345") )
def execute(self, world: World, entity: int): # Prepare data try: self_position = world.component_for_entity(entity, Position) self_velocity = world.component_for_entity(entity, Velocity) self_acceleration = world.component_for_entity(entity, Acceleration) self.__valid = True except KeyError: self.__valid = False return target_position = self._get_target_point(world, entity) if target_position is None: self.__valid = False return v_self_position = np.array([self_position.x, self_position.y]) v_self_velocity = np.array([self_velocity.x, self_velocity.y]) v_navigation_target = np.array(target_position) # Calculate stopping distance self_speed = np.linalg.norm(v_self_velocity) stopping_distance = (self_speed**2) / (2 * self_acceleration.max_acceleration) # What has to actually happen to get to the navigation target? v_course_correction = v_navigation_target - (v_self_position + v_self_velocity) #Enfore maximum acceleration v_course_correction = v_course_correction / np.linalg.norm(v_course_correction) v_course_correction *= self_acceleration.max_acceleration if stopping_distance >= np.linalg.norm(v_navigation_target - v_self_position): v_course_correction = v_course_correction * -1 #Accelerate to correct course self_acceleration.x = v_course_correction[0] self_acceleration.y = v_course_correction[1]
def _get_target_point(self, world: World, entity: int) -> Optional[Tuple[int, int]]: self_position = world.component_for_entity(entity, Position) patrol_target = self.__get_patrol_target() v_self_position = np.array([self_position.x, self_position.y]) v_patrol_target = np.array([patrol_target[0], patrol_target[1]]) distance = np.linalg.norm(v_patrol_target - v_self_position) if (distance <= self.distance): self.current_target_b = not self.current_target_b patrol_target = self.__get_patrol_target() v_patrol_target = np.array([patrol_target[0], patrol_target[1]]) return (v_patrol_target[0], v_patrol_target[1])
def assign_positions(world: esper.World, config: List[Point]): logger = logging.getLogger(__name__) components = {} for ent, (hover, pos) in world.get_components(Hover, Position): components[ent] = (hover, pos) for point in config: if len(components) == 0: break distances = [] for ent, (_, pos) in components.items(): center = pos.center distances.append((distance(point, center), ent)) distances.sort() # logger.debug(f'Point {point}: {distances}') for closer in distances: # logger.debug(f'Assigning point {point} to entity {closer[1]}') hover = components[closer[1]][0] hover.target = point change_hover_state(world, closer[1], HoverState.MOVING) components.pop(closer[1]) break
def change_hover_state(world: World, ent: int, new_state: HoverState): hover = world.component_for_entity(ent, Hover) skeleton = world.component_for_entity(ent, Skeleton) hover.status = new_state skeleton.style = re.sub(r'fillColor=#[\d\w]{6}', f'fillColor={new_state.value[0]}', skeleton.style) skeleton.changed = True
def build_simulation_objects(content_root: Element, world: esper.World, window_options: WindowOptions, available_builders: dict): """ Parses the XML Elements into esper entities. Parsing is done by transforming Element's attributes and annotations into components. There are 2 types of objects: 1. Untyped objects -- Do not possess any type annotation. Used for building walls, for example. They have only basic components (e.g. Collision, Position, ...) 2. Typed objects -- Possess a type annotation. Enclosed in <object> tags in the XML file. Parsed by a specific builder according to the type. Not all typed objects are transformed into entities. RETURNS: draw2entity: dict -- Maps ids from drawio to entities in the simulation. objects: list -- List of typed objects that have been transformed into entities. interactive: dict -- Maps what entities can be interacted with (e.g. picked up). Key is the entity name, value is the entity id """ logger = logging.getLogger(__name__) logger.info(f'Available builders: {available_builders}') draw2entity = {} objects: List[Tuple[int, str]] = [] interactive = {} # If any object in the XML has dependencies that appear after it in the XML # The builder can return a DependencyNotFound error, causing the cell to be deferred. # Deferred cells are re-evaluated after the first pass is complete. deferred: List[Element] = [] # 1st pass for cell in content_root: if cell.tag == 'mxCell' and 'style' in cell.attrib: (components, style) = mxCellDecoder.parse_mxCell(cell, window_options) ent = world.create_entity() for c in components: world.add_component(ent, c) draw2entity[style['id']] = [ent, style] if cell.tag == 'object': cell_type = cell.attrib['type'] try: pending_updates = \ available_builders[cell_type].__dict__['build_object'](cell, world, window_options, draw2entity) draw2entity.update(pending_updates[0]) objects += pending_updates[1] interactive.update(pending_updates[2]) except DependencyNotFound as err: deferred.append(cell) logger.debug(f'Cell {cell.tag} deferred - {err}') # 2nd pass for cell in deferred: if cell.tag == 'mxCell' and 'style' in cell.attrib: (components, style) = mxCellDecoder.parse_mxCell(cell, window_options) ent = world.create_entity() for c in components: world.add_component(ent, c) draw2entity[style['id']] = [ent, style] if cell.tag == 'object': cell_type = cell.attrib['type'] try: pending_updates = \ available_builders[cell_type].__dict__['build_object'](cell, world, window_options, draw2entity) draw2entity.update(pending_updates[0]) objects += pending_updates[1] interactive.update(pending_updates[2]) except DependencyNotFound as err: logger.error(f'Cell {cell.tag} failed processing - {err}') return draw2entity, objects, interactive
def build_simulation_objects(content_root, batch: pyglet.graphics.Batch, world: esper.World, window_options): # Create Walls draw2entity = {} interactive = {} objects = [] windowSize = window_options[0] for cell in content_root: if cell.tag == 'mxCell' and 'style' in cell.attrib: (components, style) = mxCellDecoder.parse_mxCell(cell, batch, window_options) ent = world.create_entity() for c in components: world.add_component(ent, c) draw2entity[style['id']] = [ent, style] if cell.tag == 'object': if cell.attrib['type'] == 'robot': (components, style) = mxCellDecoder.parse_object(cell, batch, window_options) ent = world.create_entity() # Custom components for key, val in cell.attrib.items(): if key.startswith('component_'): component_name = key[ 10:] # removes "component_" from the name init_values = json.loads(val) component = dynamic_importer.init_component( component_name, init_values) components.append(component) for c in components: world.add_component(ent, c) draw2entity[style['id']] = [ent, style] objects.append((ent, style['id'])) elif cell.attrib['type'] == 'pickable': skeleton = copy.copy(cell) (components, style) = mxCellDecoder.parse_object(cell, batch, window_options) pick = Pickable(float(cell.attrib['weight']), cell.attrib['name'], skeleton) components.append(pick) ent = world.create_entity() for c in components: world.add_component(ent, c) interactive[style['name']] = ent elif cell.attrib['type'] == 'path': mxCell = cell[0] points = Path.from_mxCell(mxCell, windowSize[1]) obj = mxCell.attrib.get('source', None) (ent, _) = draw2entity.get(obj, (None, None)) if ent is None: print(f"Path origin ({obj}) not found. Trying target.") else: print(f"Adding path to entity {ent}") world.add_component(ent, Path(points)) elif cell.attrib['type'] == 'map-path': mxCell = cell[0] points = Path.from_mxCell(mxCell, windowSize[1]) objId = cell.attrib.get('origin', '') key = cell.attrib.get('key', '') if key == '': print(f"Map entry without key. Using default value") key = 'Default' (ent, _) = draw2entity.get(objId, (None, None)) if ent is None: print(f"Path origin ({obj}) not found. Trying target.") else: if world.has_component(ent, Map): map = world.component_for_entity(ent, Map) if key == 'Default': key += str(len(map)) map.paths[key] = points else: if key == 'Default': key += '0' newMap = Map({key: points}) world.add_component(ent, newMap) else: print("Unrecognized object", cell) return draw2entity, objects, interactive
def WorldSetup(w: esper.World): w.add_processor(BirthYearValidator()) w.add_processor(IssueYearValidator()) w.add_processor(ExpirationYearValidator()) w.add_processor(HeightValidator()) w.add_processor(HairColorValidator()) w.add_processor(EyeColorValidator()) w.add_processor(PassportIDValidator()) w.add_processor(FieldPresenceValidator())