def test_contains(self): r = Rect(1, 2, 3, 4) self.failUnless(r.contains(Rect(2, 3, 1, 1)), "r does not contain Rect(2,3,1,1)") self.failUnless(r.contains(Rect(r)), "r does not contain the same rect as itself") self.failUnless(r.contains(Rect(2, 3, 0, 0)), "r does not contain an empty rect within its bounds") self.failIf(r.contains(Rect(0, 0, 1, 2)), "r contains Rect(0,0,1,2)") self.failIf(r.contains(Rect(4, 6, 1, 1)), "r contains Rect(4,6,1,1)") self.failIf(r.contains(Rect(4, 6, 0, 0)), "r contains Rect(4,6,0,0)")
def _get_group_bounding(tag_store, sizeRect): if not isinstance(sizeRect, pygame.Rect): sizeRect = Rect(0, 0, sizeRect[0], sizeRect[1]) if tag_store: rects = [tag.rect for tag in tag_store] union = rects[0].unionall(rects[1:]) if sizeRect.contains(union): return union return sizeRect
def test_within_bounds(pack): """Rects packed by the packers lie within the texture bounds.""" by_bin = packs[pack] bounds = Rect(0, 0, 512, 512) for bin_id, rects in by_bin.items(): for r in rects: if not bounds.contains(r): raise AssertionError(f"{r} is not within bounds {bounds}")
def test_fit(self): # __doc__ (as of 2008-08-02) for pygame.rect.Rect.fit: # Rect.fit(Rect): return Rect # resize and move a rectangle with aspect ratio # # Returns a new rectangle that is moved and resized to fit another. # The aspect ratio of the original Rect is preserved, so the new # rectangle may be smaller than the target in either width or height. r = Rect(10, 10, 30, 30) r2 = Rect(30, 30, 15, 10) f = r.fit(r2) self.assertTrue(r2.contains(f)) f2 = r2.fit(r) self.assertTrue(r.contains(f2))
def query(self, rect: Rect): if not self.rect.colliderect(rect): return if self.items: yield from (i for i in self.items if rect.contains(i.rect)) elif hasattr(self, 'ne'): yield from self.ne.query(rect) yield from self.nw.query(rect) yield from self.se.query(rect) yield from self.sw.query(rect)
class Unit(object): def __init__(self, player, coord, ai, hp, speed): """ Arguments: - `player`: The player that this unit fights for. - `coord`: The coordinates of the unit. - `ai`: An AI object to control the unit. """ self.player = player self.rect = Rect(coord[0] - 5, coord[1] - 5, 10, 10) self.coord = coord self.ai = ai self.hp = hp self.speed = speed def move(self, world, dest): "Move along the shortest path to the destination" if dist(self.rect.center, dest) <= self.speed: self.coord = dest self.rect.center = dest else: if dest == self.rect.center: return a = dest[0] - self.coord[0] b = dest[1] - self.coord[1] d = math.sqrt(a ** 2 + b ** 2) / self.speed self.coord = (self.coord[0] + a / d, self.coord[1] + b / d) self.rect.center = self.coord def act(self, world): raise NotImplemented("%s has not implemented act()" % type(self)) def blit(self, screen): raise NotImplemented("%s has not implemented blit()" % type(self)) def contains(self, p): if type(p) == pygame.Rect: return self.rect.contains(p) else: return self.rect.contains(pygame.Rect(p[0], p[1], 1, 1))
class Canvas(object): def __init__(self, size, slot_size): self.area_rect = Rect((0,0), size) self.slot_size = slot_size self._rects_of_slot = {} self._slots_of_entry = {} def _slot_keys_of_rect(self, rect): slot_width, slot_height = self.slot_size for x in xrange(rect.left//slot_width, 1+rect.right//slot_width): for y in xrange(rect.top//slot_height, 1+rect.bottom//slot_height): yield x, y def _add(self, rect, entry): if entry in self._slots_of_entry: raise EntryAlreadyExists("Entry already in Canvas") assert entry not in self._slots_of_entry assert self.area_rect.contains(rect) self._slots_of_entry[entry] = slots = [] for slot_key in self._slot_keys_of_rect(rect): self._rects_of_slot.setdefault(slot_key, {})[entry] = rect slots.append(slot_key) def add(self, entry): self._add(entry.bounding_rect(), entry) def remove(self, entry): for slot_key in self._slots_of_entry[entry]: del self._rects_of_slot[slot_key][entry] del self._slots_of_entry[entry] def clear(self): self._rects_of_slot.clear() self._slots_of_entry.clear() def _rect_collisions(self, rect): for slot_key in self._slot_keys_of_rect(rect): for entry, cur_rect in self._rects_of_slot.get(slot_key, {}).iteritems(): if rect.colliderect(cur_rect): yield entry def collisions(self, entry): for other_entry in self._rect_collisions(entry.bounding_rect()): if entry.collides_with(other_entry): yield other_entry def items(self): return self._slots_of_entry.iterkeys()
class Unit(object): def __init__(self, player, coord, ai, hp, speed): """ Arguments: - `player`: The player that this unit fights for. - `coord`: The coordinates of the unit. - `ai`: An AI object to control the unit. """ self.player = player self.rect = Rect(coord[0] - 5, coord[1] - 5, 10, 10) self.coord = coord self.ai = ai self.hp = hp self.speed = speed def move(self, world, dest): "Move along the shortest path to the destination" if dist(self.rect.center, dest) <= self.speed: self.coord = dest self.rect.center = dest else: if dest == self.rect.center: return a = dest[0] - self.coord[0] b = dest[1] - self.coord[1] d = math.sqrt(a**2 + b**2) / self.speed self.coord = (self.coord[0] + a / d, self.coord[1] + b / d) self.rect.center = self.coord def act(self, world): raise NotImplemented("%s has not implemented act()" % type(self)) def blit(self, screen): raise NotImplemented("%s has not implemented blit()" % type(self)) def contains(self, p): if type(p) == pygame.Rect: return self.rect.contains(p) else: return self.rect.contains(pygame.Rect(p[0], p[1], 1, 1))
def for_rect(cls, tex, rect: Rect): """Create a TextureRegion for the given texture and rect.""" if isinstance(tex, TextureRegion): assert rect.width and rect.height, "Invalid rect dimensions" myrect = Rect(0, 0, tex.width, tex.height) assert myrect.contains(rect), "Subrect is not in bounds." coords = tex.texcoords.astype(np.int32) lb = coords[3] r = np.sign(coords[2] - lb) u = np.sign(coords[0] - lb) lb += r * rect.left + u * rect.top across = r * rect.width up = u * rect.height texcoords = np.array([ lb + up, lb + up + across, lb + across, lb, ], dtype=np.uint16) rot = tex.rot tex = tex.tex else: rot = 0 l = rect.left b = rect.top r = rect.right t = rect.bottom texcoords = np.array([ (l, t), (r, t), (r, b), (l, b), ], dtype=np.uint16) return cls( tex, rect.width, rect.height, texcoords, rot )
def paint(self, hierarchy: Graph, shapes: List[Shape], viewing_window: Rect, action_dict): """ Paints an image based on a relationship graph provided :param action_dict: dict of kind -> texture function each texture function gets (hierarchy, shapes and shape) :param hierarchy: interpreted shape hierarchy :param shapes: list of shapes read by the Loader :param viewing_window: viewing window of the hierarchy shapes :return: png """ img = np.zeros( (int(viewing_window.width), int(viewing_window.height), 3)) # Fun mode # img = np.empty((viewing_window.height, viewing_window.width, 3)) drawn_shapes = [ shape for shape in shapes if viewing_window.contains(shape.shape) or viewing_window.colliderect(shape.shape) ] hs = list(zip(hierarchy.nodes, drawn_shapes)) for i in range(len(hs)): node = hs[i][0] shape = hs[i][1] logging.info( f"Generating texture for shape {shape.id} with kind {shape.kind}" ) texture = action_dict[shape.kind].paint(hierarchy, shapes, shape) # Get indices logging.info( f"Getting indices for shape {shape} and viewing window {viewing_window}" ) x1, x2, y1, y2 = get_splices(viewing_window, shape.shape) # Reshape the texture to fit (hopefully) logging.info(f"Indices are {x1}, {x2}, {y1}, {y2}") resize = np.resize(texture, (x2 - x1, y2 - y1, 3)) img[x1:x2, y1:y2] = resize # for i in range(len(hs)): # shape = hs[i][1] # node = hs[i][0] # anchor = camera.world_to_cam([shape.left, shape.up]) # draw.text((anchor[0], anchor[1]), f"{hash(shape)}", fill=(255, 255, 255)) return cv2.flip(cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE), 1)
def collision_check(self): ''' Method for checking if the entity has run into a tree or something and move it back a pixel if it has ''' if self.wall_collides: # Move the entity inside of the window (border collision) entity_rect = Rect(self.x, self.y, self.width,self.height) window_rect = Rect(0, 0, g.width * c.TILE_SIZE, g.height * c.TILE_SIZE) if not window_rect.contains(entity_rect): entity_rect.clamp_ip(window_rect) self.x = entity_rect.left self.y = entity_rect.top if self.collides: # Make sure collision rectangles are up to date self.update_collision_rects() # Get the tile the entity is standing on tile_pos = self.get_tile() checked_tiles = [] # Loop through a 3x3 tile square around the entity, to not check the entire map for i in range(tile_pos[0] - 1, tile_pos[0] + 2): for j in range(tile_pos[1] - 1, tile_pos[1] + 2): try: if c.IMAGES[g.map[i][j].type].collides: checked_tiles.append(g.map[i][j].rect()) except IndexError: # That index was apparently outside of the map pass except: raise # Check if each of the zones collides with any of the tiles if self.col_left.collidelist(checked_tiles) != -1: self.x += 1 if self.col_right.collidelist(checked_tiles) != -1: self.x -= 1 if self.col_bottom.collidelist(checked_tiles) != -1: self.y -= 1 if self.col_top.collidelist(checked_tiles) != -1: self.y += 1
def collision_check(self): """ Method for checking if the entity has run into a tree or something and move it back a pixel if it has """ if self.wall_collides: # Move the entity inside of the window (border collision) entity_rect = Rect(self.x, self.y, self.width,self.height) window_rect = Rect(0, 0, g.width * c.TILE_SIZE, g.height * c.TILE_SIZE) if not window_rect.contains(entity_rect): entity_rect.clamp_ip(window_rect) self.x = entity_rect.left self.y = entity_rect.top collided = False if self.collides: # Make sure collision rectangles are up to date self.update_collision_rects() # Get the tile the entity is standing on tile_pos = self.get_tile() checked_tiles = [] # Loop through a 3x3 tile square around the entity, to not check the entire map for i in range(tile_pos[0] - 1, tile_pos[0] + 2): for j in range(tile_pos[1] - 1, tile_pos[1] + 2): try: if c.IMAGES[g.map[i][j].type].collides: checked_tiles.append(g.map[i][j].rect()) except IndexError: # That index was apparently outside of the map pass # Check if each of the zones collides with any of the tiles # If so, move it in the appropriate direction, specified in update_collision_rects() as the keys for rect in self.rects: if self.rects[rect].collidelist(checked_tiles) != -1: self.x += rect[0] self.y += rect[1] collided = True self.collided = collided
class GameButton: rect = None unselected_img = None selected_img = None def __init__(self, image, y, width, height): self.rect = Rect((603 - width) / 2, y, width, height / 2) self.unselected_img = image.subsurface((0, 0, width, height)) self.selected_img = image.subsurface((0, height, width, height)) self.unselected_img = transform.scale(self.unselected_img, (width, int(height / 2))) self.selected_img = transform.scale(self.selected_img, (width, int(height / 2))) self.is_selected = False def contains_mouse(self, mouse_pos): return self.rect.contains((mouse_pos.x, mouse_pos.y, 0, 0)) def render(self, mouse_pos): Constant.screen.blit( self.selected_img if self.contains_mouse(mouse_pos) else self.unselected_img, self.rect)
def test_contains(self): r = Rect(1, 2, 3, 4) self.assertTrue(r.contains(Rect(2, 3, 1, 1)), "r does not contain Rect(2, 3, 1, 1)") self.assertTrue(r.contains(Rect(r)), "r does not contain the same rect as itself") self.assertTrue( r.contains(Rect(2, 3, 0, 0)), "r does not contain an empty rect within its bounds", ) self.assertFalse(r.contains(Rect(0, 0, 1, 2)), "r contains Rect(0, 0, 1, 2)") self.assertFalse(r.contains(Rect(4, 6, 1, 1)), "r contains Rect(4, 6, 1, 1)") self.assertFalse(r.contains(Rect(4, 6, 0, 0)), "r contains Rect(4, 6, 0, 0)")
class MapBase(Window): def __init__(self, width, height, default_tile_name='floor'): Window.__init__(self,None,10) self.save_data = SaveObject() self.tile_manager = TileManager() default_tile = self.tile_manager.get_tile(default_tile_name) self.tiles = [] for x in range(width): col = [] self.tiles.append(col) for y in range(height): location = MapLocation(self, (x,y), default_tile) col.append(location) self.width = width self.height = height tiles_x = core.screen.get_width() / 32 tiles_y = core.screen.get_height() / 32 self.dimentions = Rect(0,0,width,height) self.character = None self.entities = RenderEntity() self.non_passable_entities = RenderEntity() self.viewport = Rect(0,0,tiles_x,tiles_y) self.offset = Rect(0,0,0,0) self.map_tile_coverage = Rect(0,0,tiles_x+5,tiles_y+5) if self.map_tile_coverage.width > width: self.map_tile_coverage.width = width if self.map_tile_coverage.height > height: self.map_tile_coverage.height = height self.map_non_scroll_region = \ self.viewport.inflate(SCROLL_EDGE*-2,SCROLL_EDGE*-2) self.action_listeners = {} self.entry_listeners = {} self.movement_listeners = [] self.scrolling = False self.frame = 0 self.map_frames_dirty = [True,True,True,True] self.map_frames = [] self.heal_points = 0 self.regen_rate = 2000000000 self.sound = core.mixer.Sound('%s/sounds/beep.wav' % DATA_DIR) for f in range(4): #TODO Add non hardcoded values for buffer #TODO Make sure we don't make a larger surface than we need #TODO Ex: 5x5 map self.map_frames.append(Surface(((1+width) * TILE_SIZE, \ (1+height) * TILE_SIZE))) def __getstate__(self): dict = {} dict['width'] = self.width dict['height'] = self.height dict['offset.width'] = self.offset.width dict['offset.height'] = self.offset.height dict['save_data'] = self.save_data return dict def __setstate__(self, dict): if self.__class__.__name__ == 'MapBase': self.__init__(dict['width'],dict['height']) else: self.__init__() self.save_data = dict['save_data'] self.offset.width = dict['offset.width'] self.offset.height = dict['offset.height'] self.blur_events() def dispose(self): self.destroy() del self.tiles self.tile_manager.clear() del self.action_listeners del self.entry_listeners del self.movement_listeners self.entities.empty() self.non_passable_entities.empty() self.character.map = None def set_regen_rate(self, rate): self.regen_rate = rate def get(self, x, y): if x<0 or y<0: return None try: return self.tiles[x][y] except: return None def calculate_tile_coverage(self, viewable): if self.character is None: return coverage = self.map_tile_coverage coverage.center = self.character.pos view_scroll = viewable.inflate(8,8) coverage.clamp_ip(view_scroll) coverage.clamp_ip(self.dimentions) self.offset.left = (viewable.left - coverage.left) * TILE_SIZE self.offset.top = (viewable.top - coverage.top ) * TILE_SIZE if not self.map_non_scroll_region.collidepoint(self.character.pos): self.map_non_scroll_region = \ self.viewport.inflate(SCROLL_EDGE*-2,SCROLL_EDGE*-2) def set_location(self, loc, tile_name, walkable=True, tile_pos=None): x, y = loc location = self.get(x, y) tile = self.tile_manager.get_tile(tile_name, None, tile_pos) location.set_tile(tile) location.set_walkable(walkable) def place_character(self, character, pos, passable=False, direction=NORTH): self.character = character character.map = self character.can_trigger_actions = 1 if not self.viewport.collidepoint(pos): self.viewport.center = pos self.viewport.clamp_ip(self.dimentions) self.place_entity(character, pos, passable, direction) self.calculate_tile_coverage(self.viewport) def place_entity(self, entity, entity_pos, passable=False, direction=NORTH): entity.face(direction) entity.map = self entity.move_to(entity_pos) self.entities.add(entity) if not passable: self.non_passable_entities.add(entity) def add_entry_listener(self, x, y, listener): self.entry_listeners[ (x,y) ] = listener def add_movement_listener(self, listener): self.movement_listeners.append(listener) def update(self): """Invoked once per cycle of the event loop, to allow animation to update""" if self.character.entered_tile: self.character.entered_tile = False self.check_heal() if self.entry_listeners.has_key( self.character.pos ): self.entry_listeners[self.character.pos]() for listener in self.movement_listeners: listener() if self.scrolling: axis = self.scroll_axis diff = [0,0] diff[axis] = self.scroll_anchor - self.character.rect[axis] self.entities.scroll(diff) diff[axis] = diff[axis] * -1 self.offset[axis] = self.offset[axis] + diff[axis] if not self.character.moving: self.scrolling = False if self.is_left(): self.move_character(WEST) if self.is_right(): self.move_character(EAST) if self.is_up(): self.move_character(NORTH) if self.is_down(): self.move_character(SOUTH) if self.map_frames_dirty[self.frame]: self.build_current_frame() self.map_frames_dirty[self.frame] = False self.entities.update() def draw(self, blit): blit(self.map_frames[self.frame], (0,0), self.offset) self.entities.draw(blit) def build_current_frame(self): #TODO Decide if map_tile_coverage is the right name for this blit = self.map_frames[self.frame].blit rect = (self.frame * TILE_SIZE, 0, TILE_SIZE, TILE_SIZE) x = 0 y = 0 for col in range(self.map_tile_coverage.left, \ self.map_tile_coverage.right): column = self.tiles[col] for row in range(self.map_tile_coverage.top, \ self.map_tile_coverage.bottom): blit(column[row].tile, (x,y), rect) y = y + TILE_SIZE x = x + TILE_SIZE y = 0 def init(self): self.offset.width = core.screen.get_rect().width self.offset.height = core.screen.get_rect().height self.entities.run_command('enter_map') def handle_event(self,event): if event.type == PUSH_ACTION_EVENT: self.character_activate() if event.type == PUSH_ACTION2_EVENT: menu.run_main_menu() if event.type == QUIT_EVENT: core.wm.running = False def check_heal(self): self.heal_points = self.heal_points + 1 if self.heal_points >= self.regen_rate: core.game.save_data.hero.regenerate() self.heal_points = 0 def character_activate(self): if not self.character.moving: target = add(self.character.pos,MOVE_VECTORS[self.character.facing]) entities = self.non_passable_entities.entity_collisions(target) for e in entities: e.activate() def move_character(self, dir): self.character.move(dir) if not self.scrolling: if self.character.moving: nsr = self.map_non_scroll_region x,y = self.character.pos if dir % 2 == 0: # North or south if y < nsr.bottom and \ y >= nsr.top: return if y < SCROLL_EDGE or \ y >= self.height - SCROLL_EDGE: return self.scroll_axis = 1 else: # East or west if x < nsr.right and \ x >= nsr.left: return if x < SCROLL_EDGE or \ x >= self.width - SCROLL_EDGE: return self.scroll_axis = 0 self.scrolling = True vector = MOVE_VECTORS[dir] self.map_non_scroll_region.move_ip(vector) old_viewport = self.viewport self.viewport = old_viewport.move(vector) self.scroll_anchor = self.character.rect[self.scroll_axis] if not self.map_tile_coverage.contains(self.viewport): self.calculate_tile_coverage(old_viewport) self.dirty() def dirty(self): for f in range(4): self.map_frames_dirty[f] = True def move_ok(self, target_pos, character): x, y = target_pos target = self.get(x,y) if target is not None and target.is_walkable(): entities = self.non_passable_entities.entity_collisions(target_pos) if len(entities) > 0: if character.can_trigger_actions: for e in entities: e.touch() else: for e in entities: if e.can_trigger_actions: character.touch() return 0 else: self.sound.play() return 1 else: return 0 def get_tiles_from_ascii(self,ascii,tile_map): for y in range(self.height): line = ascii[y] for x in range(self.width): c = line[x] args = tile_map[c] pos = None if len(args) > 1: pos = args[1] self.set_location( (x,y), args[0], tile_map['walkable'].find(c)!=-1, pos )
class OrbitPanel(BaseWidget): current = None # ahora será la estrella o sistema seleccionado. curr_idx = None # ahora será el layer de self.Buttons. selected_marker = None last_idx = 0 _loaded_orbits = None offset = 0 curr_x, curr_y = 3, 442 curr_digit = 0 visible_markers = True orbits = None markers = None buttons = None skippable = False no_star_error = False def __init__(self, parent): super().__init__(parent) self.name = 'Orbit' self.image = Surface((ANCHO, ALTO - 32)) self.image.fill(COLOR_BOX) self.rect = self.image.get_rect() self.properties = WidgetGroup() self.area_buttons = self.image.fill(COLOR_AREA, [0, 420, self.rect.w, 200]) self.area_markers = Rect(3, 58, 380, 20 * 16) self.area_scroll = Rect(3, 32, 387, 388) self.area_modify = ModifyArea(self, ANCHO - 201, 374) self.f = self.crear_fuente(16, underline=True) self.order_f = self.crear_fuente(14) self.write(self.name + ' Panel', self.f, centerx=(ANCHO // 4) * 1.5, y=0) self.planet_area = AvailablePlanets(self, ANCHO - 200, 32, 200, 340) self.recomendation = Recomendation(self, 80, ALTO // 2 - 130) self._loaded_orbits = [] self.indexes = [] self._orbits = {} self._buttons = {} self._markers = {} self.orbit_descriptions = WidgetGroup() self.show_markers_button = ToggleableButton(self, 'Stellar Orbits', self.toggle_stellar_orbits, 3, 421) self.show_markers_button.disable() self.add_orbits_button = AddOrbitButton(self, ANCHO - 94, 394) self.resonances_button = AddResonanceButton(self, ANCHO - 140, 416) self.digit_x = RatioDigit(self, 'x', self.resonances_button.rect.left - 60, self.resonances_button.rect.y) self.write(':', self.crear_fuente(16), topleft=[ self.digit_x.rect.right + 1, self.resonances_button.rect.y - 1 ]) self.digit_y = RatioDigit(self, 'y', self.digit_x.rect.right + 9, self.resonances_button.rect.y) self.ratios = [self.digit_x, self.digit_y] self.cycler = cycle(self.ratios) next(self.cycler) self.properties.add([ self.area_modify, self.planet_area, self.show_markers_button, self.add_orbits_button, self.resonances_button, self.digit_x, self.digit_y ], layer=2) EventHandler.register(self.clear, 'ClearData') EventHandler.register(self.save_orbits, 'Save') EventHandler.register(self.load_orbits, 'LoadData') def set_current(self): self.toggle_current_markers_and_buttons(False) star = Systems.get_current_star() self.current = star self.curr_idx = self.indexes.index(star) self.orbits = self._orbits[star] self.markers = self._markers[star] self.buttons = self._buttons[star] if not len(self.markers) or not self.markers[0].locked: self.populate() self.toggle_current_markers_and_buttons(True) self.sort_buttons() self.add_orbits_button.enable() self.visible_markers = False self.toggle_stellar_orbits() def populate(self): star = self.current markers = { 'Inner Boundary': star.inner_boundry, 'Habitable Inner': star.habitable_inner, 'Habitable Outer': star.habitable_outer, 'Frost Line': star.frost_line, 'Outer Boundary': star.outer_boundry } for marker in markers: x = OrbitMarker(self, marker, star, markers[marker]) x.locked = True self._markers[star].append(x) self.properties.add(x, layer=4) if hasattr(star, 'habitable_orbit'): markers = { 'Inner Forbbiden Zone': star.inner_forbbiden_zone, 'Outer Forbbiden Zone': star.outer_forbbiden_zone } for marker in markers: x = OrbitMarker(self, marker, star, markers[marker]) x.locked = True self._markers[star].append(x) self.properties.add(x, layer=4) self.add_orbit_marker(star.habitable_orbit) self.sort_markers() def toggle_current_markers_and_buttons(self, toggle: bool): if self.markers is not None: for marker in self.markers: marker.toggle(toggle) if self.buttons is not None: for button in self.buttons: button.toggle(toggle) def add_orbit_marker(self, position, resonance=False): star = self.current if not hasattr(position, 'star') else position.star inner = star.inner_boundry outer = star.outer_boundry bc = False if resonance is False else True if type(position) is q: ba = True bb = False if not resonance: test = inner < position < outer color = COLOR_TEXTO else: test = inner < position # TNOs orbit well outside of 40AUs. color = (255, 0, 0) # color provisorio else: # type(position) is PlanetOrbit ba = False bb = True test = True # saved orbits are valid by definition color = COLOR_STARORBIT if test is True: new = OrbitMarker(self, 'Orbit', star, position, is_orbit=ba, is_complete_orbit=bb, is_resonance=bc) self._markers[star].append(new) self._orbits[star].append(new) self.sort_markers() self.add_button_and_type(star, new, color) self.properties.add(new, layer=4) def add_button_and_type(self, star, marker, color): orbit_type = OrbitType(self) button = OrbitButton(self, color) self._buttons[star].append(button) # Buttons, OrbitTypes and Markers are all Intertwined. orbit_type.intertwine(m=marker, b=button) button.intertwine(m=marker, o=orbit_type) marker.intertwine(o=orbit_type, b=button) self.orbit_descriptions.add(orbit_type) if len(self.buttons): self.sort_buttons() self.properties.add(button, layer=4) self.properties.add(orbit_type, layer=4) button.enable() def sort_markers(self): self.markers.sort(key=lambda m: m.value) for i, marker in enumerate(self.markers, start=1): marker.rect.y = i * 2 * 10 + 38 + self.offset if not self.area_markers.contains(marker.rect): marker.hide() else: marker.show() def sort_buttons(self): x, y = self.curr_x, self.curr_y for bt in sorted(self.buttons, key=lambda b: b.get_value().m): bt.move(x, y) if not self.area_buttons.contains(bt.rect): bt.hide() else: bt.show() if x + bt.rect.w + 15 < self.rect.w - bt.rect.w + 15: x += bt.rect.w + 15 else: x = 3 y += 32 def delete_marker(self, marker): """ :type marker: OrbitMarker """ if not marker.locked: marker.kill() marker.linked_type.kill() marker.linked_button.kill() if marker is self.area_modify.marker: self.area_modify.unlink() idx = self.markers.index(marker) del self.markers[idx] self.buttons.remove(marker.linked_button) self.sort_markers() self.sort_buttons() def on_mousebuttondown(self, event): if self.area_scroll.collidepoint(event.pos): last_is_hidden = not self.markers[-1].is_visible if len(self.markers) > 16 and event.button in (4, 5): if event.button == 4 and self.offset < 0: self.offset += 20 elif event.button == 5 and last_is_hidden: self.offset -= 20 self.sort_markers() elif self.area_buttons.collidepoint( event.pos) and self.buttons is not None and len(self.buttons): self.buttons.sort(key=lambda b: b.get_value().m) last_is_hidden = not self.buttons[-1].is_visible first_is_hidden = not self.buttons[0].is_visible if event.button == 4 and first_is_hidden: self.curr_y += 32 elif event.button == 5 and last_is_hidden: self.curr_y -= 32 self.sort_buttons() elif event.button == 1 and self.markers is not None: for marker in self.markers: marker.deselect() marker.enable() def check_orbits(self): self.orbits.sort(key=lambda o: o.value.m) for x, p in enumerate(self.orbits[1:], start=1): a = self.orbits[x - 1].value.m if x > 0 and len( self.orbits) else self.orbits[0].value.m # el anterior assert a + 0.15 < p.value.m, 'Orbit @' + str( p.value.m) + ' is too close to Orbit @' + str(a) if x + 1 < len(self.orbits): b = self.orbits[x + 1].value.m # el posterior assert p.value.m < b - 0.15, 'Orbit @' + str( p.value.m) + ' is too close to Orbit @' + str(b) def anchor_maker(self, marker): self.area_modify.link(marker) self.selected_marker = marker def clear(self, event): if event.data['panel'] is self: for marker in self.markers: marker.kill() for orbit in self.buttons: orbit.kill() self.markers.clear() self.clear_ratios() def save_orbits(self, event): orbits = self._loaded_orbits for system in Systems.get_systems(): if system.star_system.letter == 'S': for star in system: for marker in self._orbits.get(star, []): d = self.create_save_data(marker.orbit) orbits.append(d) else: star = system.star_system for marker in self._orbits.get(star, []): d = self.create_save_data(marker.orbit) orbits.append(d) EventHandler.trigger(event.tipo + 'Data', 'Orbit', {'Stellar Orbits': orbits}) @staticmethod def create_save_data(orb): d = {} if hasattr(orb, 'semi_major_axis'): d['a'] = round(orb.semi_major_axis.m, 2) if hasattr(orb, 'inclination'): d['i'] = orb.inclination.m if hasattr(orb, 'eccentricity'): d['e'] = orb.eccentricity.m if hasattr(orb, 'astrobody'): d['astrobody'] = orb.astrobody.id d['star_id'] = orb.astrobody.orbit.star.id return d def load_orbits(self, event): for position in event.data.get('Stellar Orbits', []): if position not in self._loaded_orbits: self._loaded_orbits.append(position) def set_loaded_orbits(self): for orbit_data in self._loaded_orbits: a = q(orbit_data['a'], 'au') if 'e' not in orbit_data: self.add_orbit_marker(a) else: e = q(orbit_data['e']) i = q(orbit_data['i'], 'degree') system = Systems.get_system_by_id(orbit_data['star_id']) planet = system.get_astrobody_by(orbit_data['astrobody'], tag_type='id') star = system.star_system planet.set_orbit(star, [a, e, i]) self.add_orbit_marker(planet.orbit) self.planet_area.delete_objects(planet) # borrar las órbitas cargadas para evitar que se dupliquen. self.sort_markers() self._loaded_orbits.clear() def fill_indexes(self): assert len(Systems.get_systems()) for system in Systems.get_systems(): star = system.star_system if star not in self._markers: self._markers[star] = [] self._orbits[star] = [] self._buttons[star] = [] self.indexes.append(star) def show(self): try: self.fill_indexes() self.set_current() self.no_star_error = False except AssertionError: self.no_star_error = True for prop in self.properties.get_widgets_from_layer(2): prop.show() self.visible_markers = True if len(self._loaded_orbits): self.set_loaded_orbits() self.show_markers_button.show() super().show() def hide(self): super().hide() for item in self.properties.widgets(): item.hide() def toggle_stellar_orbits(self): if self.visible_markers: self.area_modify.color_alert() self.add_orbits_button.disable() for marker in self.markers: marker.hide() else: for marker in self.markers: marker.show() self.hide_orbit_types() self.show_markers_button.disable() self.add_orbits_button.enable() self.area_modify.color_standby() self.visible_markers = not self.visible_markers self.area_modify.visible_markers = self.visible_markers def hide_orbit_types(self): for orbit_type in self.orbit_descriptions.widgets(): orbit_type.hide() for orbit_button in self.buttons: orbit_button.unlock() def deselect_markers(self, m): for marker in self.markers: marker.deselect() marker.enable() m.select() def link_astrobody_to_stellar_orbit(self, astrobody): locked = [i for i in self.buttons if i.locked] if len(locked): orbit = PseudoOrbit(locked[0].linked_marker.orbit) locked[0].linked_marker.orbit = orbit locked[0].linked_type.show() locked[0].linked_type.link_astrobody(astrobody) self.add_orbits_button.disable() if astrobody.celestial_type == 'planet': self.recomendation.suggest(astrobody, orbit, Systems.get_current_star()) self.recomendation.show_suggestion(astrobody, orbit.temperature) def update(self): super().update() idx = Systems.get_current_idx() if idx != self.last_idx: self.set_current() self.last_idx = idx if not self.no_star_error: self.image.fill(COLOR_BOX, self.area_markers) else: f = self.crear_fuente(16) text = 'There is no star system set. Go back to the Star Panel and set a star first.' rect = Rect(50, 100, 200, 100) render = render_textrect(text, f, rect.w, (0, 0, 0), COLOR_BOX) self.image.blit(render, rect) def __repr__(self): return 'Orbit Panel' def set_current_digit(self, idx): self.curr_digit = self.ratios.index(idx) def cycle(self): has_values = False for ratio in self.ratios: ratio.deselect() has_values = ratio.value != '' valid = has_values and not self.no_star_error valid = valid and self.selected_marker is not None if valid: self.resonances_button.enable() else: ratio = next(self.cycler) ratio.select() WidgetHandler.set_origin(ratio) def ratios_to_string(self): x = int(self.digit_x.value) y = int(self.digit_y.value) assert x >= y, 'invalid ratio' self.write('{}° Order'.format(x - y), self.order_f, right=self.digit_x.rect.left - 2, y=self.digit_x.rect.y) return '{}:{}'.format(x, y) def clear_ratios(self): self.digit_x.clear() self.digit_y.clear()
def reverse_clamp_ip(larger_rect: Rect, smaller_rect: Rect): if not larger_rect.contains(smaller_rect): larger_rect.left = min(larger_rect.left, smaller_rect.left) larger_rect.right = max(larger_rect.right, smaller_rect.right) larger_rect.top = min(larger_rect.top, smaller_rect.top) larger_rect.bottom = max(larger_rect.bottom, smaller_rect.bottom)
class Dungeons(): def __init__(self, space_size=(400, 600), n_rooms=7): #list of all rooms self.rooms = [] #walls self.walls = [] #list of all coridors self.corridors = [] #list of all shapes on the map (to create full topolical map later) shapes = [] self.space_size = space_size grid_size = WALL_SIZE self.space_Rect = Rect(0, 0, space_size[0], space_size[1]) max_room_size = MAX_ROOM_SIZE / grid_size min_room_size = MIN_ROOM_SIZE / grid_size space_grid = self.space_size[0] / grid_size, space_size[1] / grid_size all_rooms = geo.Polygon() for ii in range(n_rooms): room_width = grid_size * rand.randint(min_room_size, max_room_size) room_height = grid_size * rand.randint(min_room_size, max_room_size) room_center = grid_size * (rand.randint( 1, space_grid[0] - 1)), grid_size * (rand.randint( 1, space_grid[1] - 1)) new_room = Room(room_center, room_width, room_height) dist = new_room.ring.distance(all_rooms) out_of_bounds = not self.space_Rect.contains(new_room) while self.rooms and dist < WALL_SIZE or out_of_bounds: room_width = grid_size * rand.randint(min_room_size, max_room_size) room_height = grid_size * rand.randint(min_room_size, max_room_size) room_center = grid_size * (rand.randint( 1, space_grid[0] - 1)), grid_size * (rand.randint( 1, space_grid[1] - 1)) new_room = Room(room_center, room_width, room_height) #keys = new_room.collidelistall(self.rooms) dist = new_room.ring.distance(all_rooms) out_of_bounds = not self.space_Rect.contains(new_room) #create corridors for room in self.rooms: corridor = Corridor(new_room, room) self.corridors.append(corridor) new_room.corridors.append(self.corridors[-1]) room.corridors.append(self.corridors[-1]) shapes.append(corridor.ring) self.rooms.append(new_room) shapes.append(new_room.ring) all_rooms = all_rooms.union(new_room.ring) # remove the corridors that intersect with rooms # TODO: Attention: the corridors are only being removed from the full list of corridors in self, but not from the lists that are coresponding to each of the rooms # TODO: Clean up, it can be easier! new_corridors = [] for corridor in self.corridors: own_rooms = corridor.room_h.ring.union(corridor.room_v.ring) own_room_walls = corridor.room_h.wall_polygons + corridor.room_v.wall_polygons current_all_rooms = all_rooms.difference(own_rooms) if current_all_rooms.is_empty or ( corridor.ring.distance(current_all_rooms) > 10): walls_own_rooms = geo.Polygon() for wall in own_room_walls: walls_own_rooms = walls_own_rooms.union(wall) if walls_own_rooms.intersection( corridor.ring ).area <= 2 * CORRIDOR_SIZE * CORRIDOR_SIZE: new_corridors.append(corridor) self.corridors = new_corridors self.corridors = [ x for x in self.corridors if not x.ring.intersection(all_rooms).length > Corridor.narrow * 4 ] #create topological map self.topology = self.rooms[0].ring for room in self.rooms: self.topology = self.topology.union(room.ring) for jj in range(len(self.corridors)): self.corridors[jj].ring = self.corridors[jj].ring.difference( self.topology) for jj in range(len(self.corridors)): self.topology = self.topology.union(self.corridors[jj].ring) walls = [] #create walls for jj in range(len(self.rooms)): for ii in range(len(self.rooms[jj].wall_polygons)): self.rooms[jj].wall_polygons[ii] = self.rooms[ jj].wall_polygons[ii].difference(self.topology) #wall = Wall(self.rooms[jj].wall_polygons[ii].boundary) walls.append( (self.rooms[jj].wall_polygons[ii], self.rooms[jj].texture)) for jj in range(len(self.corridors)): for ii in range(len(self.corridors[jj].wall_polygons)): self.corridors[jj].wall_polygons[ii] = self.corridors[ jj].wall_polygons[ii].difference(self.topology) #print(self.corridors[jj].wall_polygons[ii]) if not self.corridors[jj].wall_polygons[ii].is_empty: walls.append((self.corridors[jj].wall_polygons[ii], self.corridors[jj].texture)) #draw_multilinestring(self.corridors[jj].wall_polygons[ii].boundary, screen) print(len(walls)) walls__ = convert_to_list_of_poly(walls) print(len(walls__)) for wall in walls__: print(wall) # print (wall[1]) # wall_ = Wall(wall[0].boundary, texture=wall[1]) self.walls.append(wall) #TODO: check connectivity: this is implemented on the level of the environment, but should be moved here def generate_random_point(self, n_points=1, pymunk_coordinates=True): #fundtion to generate random point inside of the map (eg for the fruits) ll = [] bb = self.topology.bounds for ii in range(n_points): p = (rand.randint(bb[0], bb[2]), rand.randint(bb[1], bb[3])) while not self.topology.contains(geo.Point(p)): p = (rand.randint(bb[0], bb[2]), rand.randint(bb[1], bb[3])) if pymunk_coordinates: ll.append((p[0], self.space_size[1] - p[1])) else: ll.append((p[0], p[1])) return ll def draw(self): #standalone display of the topological elements of the map using pygame engine #this is mainly needed for debugging, hence not removing old code pygame.init() screen = pygame.display.set_mode(self.space_size) #for room in self.rooms: #pygame.draw.rect(screen, (0, 255, 255), room, 2) # for corridor in self.corridors: # pygame.draw.rect(screen, (0, 255, 255), corridor.h, 2) # pygame.draw.rect(screen, (0, 255, 255), corridor.v, 2) # for corridor in self.corridors: # print(corridor.ring.boundary) # array_of_points = np.array(corridor.ring.boundary) # for ii in range(1, array_of_points.shape[0]): # pygame.draw.line(screen, (255, 255, 0), array_of_points[ii-1, :], array_of_points[ii, :], 2) # print(array_of_points[ii-1, :], array_of_points[ii, :]) # pygame.draw.line(screen, (255, 255, 0), array_of_points[-1, :], array_of_points[0, :], 2) # # # for ii in range(1, array_of_points.shape[0]): # # pygame.draw.line(screen, (255, 255, 0), array_of_points[ii-1, :], array_of_points[ii, :], 2) # # print(array_of_points[ii-1, :], array_of_points[ii, :]) # # pygame.draw.line(screen, (255, 255, 0), array_of_points[-1, :], array_of_points[0, :], 2) # # # for x in np.nditer(array_of_points): # # pygame.draw.line(screen, (0, 255, 0), line_[x, :], line_[1, :], 2) # # #pygame.draw.rect(screen, (255, 0, 0), corridor.v, 2) # #pygame.draw.rect(screen, (255, 0, 0), corridor.h, 2) draw_multilinestring(self.topology.boundary, screen) #for room in self.rooms: #draw_linearring(room.outer_line.boundary, screen) # for jj in range(len(self.rooms)): # for ii in range(len(self.rooms[jj].wall_polygons)): # self.rooms[jj].wall_polygons[ii] = self.rooms[jj].wall_polygons[ii].difference(self.topology) # draw_multilinestring(self.rooms[jj].wall_polygons[ii].boundary, screen) # # # for jj in range(len(self.corridors)): # for ii in range(len(self.corridors[jj].wall_polygons)): # # self.corridors[jj].wall_polygons[ii] = self.corridors[jj].wall_polygons[ii].difference(self.topology) # print(self.corridors[jj].wall_polygons[ii]) # if not self.corridors[jj].wall_polygons[ii].is_empty: # draw_multilinestring(self.corridors[jj].wall_polygons[ii].boundary, screen) # for wall in self.walls: pygame.draw.rect( screen, (0, 255, 255), Rect(wall.x - 0.5 * wall.width, wall.y - 0.5 * wall.height, wall.width, wall.height), 2) pygame.draw.circle( screen, (255, 0, 0), self.generate_random_point(pymunk_coordinates=False)[-1], 5, 1) # print(self.topology.boundary) # sh = geo.shape(self.topology.boundary) # for line in sh: # array_of_points = np.array(line) # for ii in range(1, array_of_points.shape[0]): # pygame.draw.line(screen, (255, 255, 0), array_of_points[ii - 1, :], array_of_points[ii, :], 2) # print(array_of_points[ii - 1, :], array_of_points[ii, :]) # pygame.draw.line(screen, (255, 255, 0), array_of_points[-1, :], array_of_points[0, :], 2) # for line in sh: # print (np.array(line)) # line_ = np.array(line) # pygame.draw.line(screen, (0, 255, 0), line_[0, :], line_[1, :], 2) pygame.display.update() clock = pygame.time.Clock() # pygame.display.update() pygame.event.clear() while True: event = pygame.event.wait() if event.type == QUIT: pygame.quit() sys.exit() screen.fill((128, 0, 128)) clock.tick(20)
class Camera: def __init__(self, width, height, world, screen=None, top=0, left=0): self.height = height self.width = width self.world = world self.max_height = world.end self.position = Rect(left, top, width, height) self.screen = screen self.bar = gui.NarratorBar(Rect(0, 350, self.width, 350)) self.event_num = 0 self.bar.set_text("""Hello """ + game.player_name + """! Welcome to the world of cubes. This world is filled with loneliness. A lot of cubes feel lonely and you are no exception. How do you overcome this? You can move around by using the arrow keys.""") def move(self, player_centery): if not self.world.player.trying_to_communicate: self.position.centery = player_centery if self.event_num < len(event_positions): if event_positions[self.event_num] >= self.position.top >= event_positions[self.event_num] - 5: self.bar.set_text(event_text[self.event_num]) self.bar.pop_up() self.event_num += 1 def adjust_agent(self, agent): return self.adjust_rect(agent.rect) def adjust_rect(self, rect): new_left = rect.left - self.position.left new_top = rect.top - self.position.top return Rect(new_left, new_top, rect.width, rect.height) def check_visibility(self, rect): return self.position.contains(rect) def draw(self): self.world.background.draw(self.screen, self.position) self.draw_overlay(100 - self.world.player.happiness) for cluster in self.world.clusters: if self.position.top <= cluster.start_position: for agent in cluster.members: if self.check_visibility(agent.rect): new_rect = self.adjust_agent(agent) self.screen.blit(agent.s, new_rect.topleft) else: #print "not visible ", self.position.bottom, agent.rect.top, cluster.start_position, cluster.name #print "num members ", len(cluster.members) if agent.rect.top > self.position.bottom: #print "dlkshj" cluster.members.remove(agent) if not cluster.members: self.world.clusters.remove(cluster) #new_rect = self.adjust_agent(self.world.player) #self.screen.blit(self.world.player.s, new_rect.topleft) for agent in self.world.player_cluster.members: new_rect = self.adjust_agent(agent) self.screen.blit(agent.s, new_rect.topleft) self.bar.draw(self.screen) def draw_overlay(self, alpha=0): s = pygame.Surface((640, 480)) # the size of your rect s.set_alpha(alpha) # alpha level s.fill((0, 0, 0)) # this fills the entire surface self.screen.blit(s, (0, 0)) # (0,0) are the top-left coordinates
class PlanetaryOrbitPanel(BaseWidget): skippable = True skip = False current = None markers = None satellites = None curr_digit = 0 selected_marker = None curr_x = 0 curr_y = 0 added = None visible_markers = True def __init__(self, parent): super().__init__(parent) self.name = 'Planetary Orbit' self.image = Surface((ANCHO, ALTO - 32)) self.image.fill(COLOR_BOX) self.rect = self.image.get_rect() self.properties = WidgetGroup() self.buttons = WidgetGroup() self.orbit_descriptions = WidgetGroup() self._markers = {} self.markers = [] self.added = [] self.objects = [] self.satellites = {} self._loaded_orbits = [] self.area_buttons = self.image.fill(COLOR_AREA, [0, 420, self.rect.w, 200]) self.area_markers = Rect(3, 58, 380, 20 * 16) self.curr_x = self.area_buttons.x + 3 self.curr_y = self.area_buttons.y + 21 self.planet_area = AvailablePlanets(self, ANCHO - 200, 32, 200, 340) self.add_orbits_button = SetOrbitButton(self, ANCHO - 94, 394) self.area_modify = ModifyArea(self, ANCHO - 201, 374) self.show_markers_button = ToggleableButton(self, 'Satellites', self.toggle_stellar_orbits, 3, 421) self.show_markers_button.disable() self.resonances_button = AddResonanceButton(self, ANCHO - 140, 416) self.order_f = self.crear_fuente(14) self.write(self.name + ' Panel', self.crear_fuente(16, underline=True), centerx=(ANCHO // 4) * 1.5, y=0) self.digit_x = RatioDigit(self, 'x', self.resonances_button.rect.left - 60, self.resonances_button.rect.y) self.write(':', self.crear_fuente(16), topleft=[ self.digit_x.rect.right + 1, self.resonances_button.rect.y - 1 ]) self.digit_y = RatioDigit(self, 'y', self.digit_x.rect.right + 9, self.resonances_button.rect.y) self.ratios = [self.digit_x, self.digit_y] self.cycler = cycle(self.ratios) next(self.cycler) self.properties.add(self.area_modify, self.show_markers_button, self.digit_x, self.digit_y, self.planet_area, self.add_orbits_button, self.resonances_button, layer=2) EventHandler.register(self.save_orbits, 'Save') EventHandler.register(self.load_orbits, 'LoadData') def load_orbits(self, event): for position in event.data.get('Planetary Orbits', []): if position not in self._loaded_orbits: self._loaded_orbits.append(position) def set_loaded_orbits(self): for orbit_data in self._loaded_orbits: a = q(orbit_data['a'], 'earth_radius') e = q(orbit_data['e']) i = q(orbit_data['i'], 'degree') system = Systems.get_system_by_id(orbit_data['star_id']) planet = system.get_astrobody_by(orbit_data['planet_id'], tag_type='id') if planet.id not in self.satellites: self.satellites[planet.id] = [] if planet.id not in self._markers: self._markers[planet.id] = [] satellite = system.get_astrobody_by(orbit_data['astrobody'], tag_type='id') self.satellites[planet.id].append(satellite) satellite.set_orbit(planet, [a, e, i]) self.add_existing(satellite, planet.id) # borrar las órbitas cargadas para evitar que se dupliquen. self._loaded_orbits.clear() def save_orbits(self, event): orbits = self._loaded_orbits for planet_obj in self.planet_area.listed_objects.widgets(): planet = planet_obj.object_data for marker in self._markers.get(planet.id, []): if marker.orbit is not None: d = self.create_save_data(marker.orbit) orbits.append(d) EventHandler.trigger(event.tipo + 'Data', 'Orbit', {'Planetary Orbits': orbits}) @staticmethod def create_save_data(orb): d = {} if hasattr(orb, 'semi_major_axis'): d['a'] = round(orb.semi_major_axis.m, 2) if hasattr(orb, 'inclination'): d['i'] = orb.inclination.m if hasattr(orb, 'eccentricity'): d['e'] = orb.eccentricity.m if hasattr(orb, 'astrobody'): d['astrobody'] = orb.astrobody.id d['planet_id'] = orb.astrobody.parent.id d['star_id'] = orb.astrobody.parent.parent.id return d def toggle_stellar_orbits(self): if self.visible_markers: self.area_modify.color_alert() self.add_orbits_button.disable() for marker in self.markers: marker.hide() else: for button in self.buttons.widgets(): button.deselect() self.hide_orbit_types() if self.current is not None: for marker in self.markers: marker.show() self.show_markers_button.disable() self.area_modify.color_standby() self.visible_markers = not self.visible_markers self.area_modify.visible_markers = self.visible_markers def hide_orbit_types(self): for orbit_type in self.orbit_descriptions.widgets(): orbit_type.hide() for orbit_button in self.buttons.widgets(): orbit_button.enable() def populate(self): planet = self.current if planet.id not in self._markers: self._markers[planet.id] = [] self.markers = self._markers[planet.id] for marker in self.markers: if marker not in self.properties: self.properties.add(marker, layer=3) marker.show() self.create_hill_marker(planet) self.sort_markers() def add_objects(self): system = Systems.get_current() if system is not None: for obj in system.satellites + system.asteroids: if obj not in self.objects: self.objects.append(obj) btn = ObjectButton(self, obj, self.curr_x, self.curr_y) if obj.orbit is not None: btn.update_text(obj.orbit.a) markers = self._markers[obj.orbit.star.id] marker_idx = [ i for i in range(len(markers)) if markers[i].obj == obj ][0] marker = markers[marker_idx] btn.link_marker(marker) self.buttons.add(btn, layer=Systems.get_current_idx()) self.properties.add(btn) self.sort_buttons() def show(self): super().show() for prop in self.properties.get_widgets_from_layer(2): prop.show() self.set_loaded_orbits() self.add_objects() def hide(self): super().hide() for prop in self.properties.widgets(): prop.hide() def select_planet(self, planet): if planet is not self.current: self.hide_everything() self.current = planet self.populate() if planet.id not in self.satellites: self.satellites[planet.id] = [] for button in self.buttons.widgets(): button.enable() button.deselect() self.visible_markers = True sats = self.satellites[planet.id] densest = sorted(sats, key=lambda i: i.density.to('earth_density').m, reverse=True) if len(densest): self.create_roches_marker(densest[0]) self.sort_markers() def select_one(self, button): for bttn in self.buttons.widgets(): bttn.deselect() button.select() def anchor_maker(self, marker): self.area_modify.link(marker) self.area_modify.visible_markers = True self.add_orbits_button.link(marker) self.add_orbits_button.enable() self.selected_marker = marker def deselect_markers(self, m): for marker in self.markers: marker.deselect() marker.enable() m.select() def sort_markers(self): self.markers.sort(key=lambda m: m.value.m) for i, marker in enumerate(self.markers, start=1): marker.rect.y = i * 2 * 10 + 38 if not self.area_markers.contains(marker.rect): marker.hide() else: marker.show() def sort_buttons(self): x, y = self.curr_x, self.curr_y for bt in self.buttons.get_widgets_from_layer( Systems.get_current_idx()): bt.move(x, y) if not self.area_buttons.contains(bt.rect): bt.hide() else: bt.show() if x + bt.rect.w + 10 < self.rect.w - bt.rect.w + 10: x += bt.rect.w + 10 else: x = 3 y += 32 def create_roches_marker(self, obj): obj_density = obj.density.to('earth_density').m roches = self.current.set_roche(obj_density) roches_marker = Marker(self, "Roche's Limit", roches, lock=True) first = self.markers[0] if first.name == "Roche's Limit": self.properties.remove(first) self.markers[0] = roches_marker else: self.markers.append(roches_marker) self.properties.add(roches_marker, layer=3) return roches def create_hill_marker(self, planet): x = Marker(self, 'Hill Sphere', planet.hill_sphere) x.locked = True last = None if not len(self.markers) else self.markers[-1] if last is not None and last.name == 'Hill Sphere': self.properties.remove(last) self.markers[-1] = x else: self.markers.append(x) self.properties.add(x, layer=3) def add_new(self, obj): if obj not in self.added: self.added.append(obj) obj_name = obj.cls pln_habitable = Systems.get_current().is_habitable(self.current) pln_hill = self.current.hill_sphere.m obj_type = obj.celestial_type roches = self.create_roches_marker(obj) text = "A satellite's mass must be less than or equal to the\nmass of the planet." text += '\n\nConsider using a less massive satellite for this planet.' assert self.current.mass.to('earth_mass').m >= obj.mass.to( 'earth_mass').m, text pos = q( round( roll(self.current.roches_limit.m, self.current.hill_sphere.m / 2), 3), 'earth_radius') orbit = RawOrbit(Systems.get_current_star(), pos) obj_marker = Marker(self, obj_name, pos, color=COLOR_SELECTED, lock=False) max_value = pln_hill if pln_habitable and obj_type != 'asteroid': max_value /= 2 obj_marker.set_max_value(max_value) obj_marker.set_min_value(roches.m) obj_marker.links(orbit, obj) self.markers.append(obj_marker) self.properties.add(obj_marker, layer=3) self.sort_markers() return orbit, obj_marker def add_existing(self, obj, pln_id): if obj not in self.added: self.added.append(obj) obj_name = obj.cls orbit = obj.orbit pos = orbit.a obj_marker = Marker(self, obj_name, pos, color=COLOR_SELECTED, lock=False) obj_marker.links(orbit, obj) self._markers[pln_id].append(obj_marker) def hide_markers(self): for marker in self.markers: marker.hide() self.show_markers_button.enable() def hide_everything(self): for marker in self.markers: if marker.linked_button is not None: marker.linked_button.hide_info() marker.hide() self.visible_markers = False self.show_markers_button.disable() def is_added(self, obj): return obj in self.added def get_raw_orbit_markers(self): raws = [ m for m in self.markers if ((not m.locked) and (type(m.orbit) == RawOrbit)) ] return raws def link_satellite_to_planet(self, marker): marker._orbit = PseudoOrbit(marker.orbit) button = marker.linked_button self.hide_everything() button.update_text(marker.orbit.a) button.info.link_marker(marker) button.info.locked = False button.info.show() def notify(self): if not self.visible_markers: self.show_markers_button.enable() for button in self.buttons.widgets(): button.disable() def get_sorted_satellites(self): self.sort_markers() markers = [ marker.obj for marker in self.markers if marker.obj is not None ] return markers def set_current_digit(self, idx): self.curr_digit = self.ratios.index(idx) def cycle(self): has_values = False for ratio in self.ratios: ratio.deselect() has_values = ratio.value != '' valid = has_values and self.selected_marker is not None if valid: self.resonances_button.enable() else: ratio = next(self.cycler) ratio.select() WidgetHandler.set_origin(ratio) def ratios_to_string(self): x = int(self.digit_x.value) y = int(self.digit_y.value) diff = y - x if y > x else x - y self.write('{}° Order'.format(diff), self.order_f, right=self.digit_x.rect.left - 2, y=self.digit_x.rect.y) return '{}:{}'.format(x, y) def get_difference(self): x = int(self.digit_x.value) y = int(self.digit_y.value) return x - y def clear_ratios(self): self.digit_x.clear() self.digit_y.clear()
def query(self, rect: Rect): if not self.rect.colliderect(rect): return yield from (r for r in self.points if rect.contains(r)) yield from (r for tree in self.children for r in tree.query(rect))