def blit_sprite(self, sprite: 'sprites.AbstractSprite'): if sprite is None: return elif isinstance(sprite, sprites.MultiSprite): for spr in sprite.all_sprites(): self.blit_sprite(spr) else: mult = self._get_render_mult() offs = (self.camera_xy[0] * mult, self.camera_xy[1] * mult) if isinstance(sprite, sprites.ImageSprite): if sprite.model() is not None: src_rect_on_atlas = sprite.model().rect() dest_rect_in_world = sprite.rect() surf = self._get_drawing_surface() dest_rect = [dest_rect_in_world[0] * mult * self.camera_scale[0] - offs[0], dest_rect_in_world[1] * mult * self.camera_scale[1] - offs[1], dest_rect_in_world[2] * mult * self.camera_scale[0], dest_rect_in_world[3] * mult * self.camera_scale[1]] if (src_rect_on_atlas[2] == dest_rect[2] and src_rect_on_atlas[3] == dest_rect[3] and sprite.rotation() == 0 and sprite.xflip() is False and sprite.color() == (1, 1, 1)): # already the correct size, just blit it surf.blit(self.cached_texture_atlas, (dest_rect[0], dest_rect[1]), src_rect_on_atlas) else: subsurf = self.cached_texture_atlas.subsurface(src_rect_on_atlas) orig_subsurf = subsurf if sprite.xflip(): subsurf = pygame.transform.flip(subsurf, True, False) if sprite.rotation() == 0: subsurf = subsurf.copy() elif sprite.rotation() == 1: subsurf = pygame.transform.rotate(subsurf, -90) elif sprite.rotation() == 2: subsurf = pygame.transform.rotate(subsurf, -180) else: subsurf = pygame.transform.rotate(subsurf, -270) if sprite.color() != (1, 1, 1): if subsurf == orig_subsurf: subsurf = subsurf.copy() color255 = tuple(util.bound(int(c * 256), 0, 255) for c in sprite.color()) subsurf.fill(color255, [0, 0, subsurf.get_width(), subsurf.get_height()], pygame.BLEND_MULT) xformed = pygame.transform.scale(subsurf, (int(dest_rect[2]), int(dest_rect[3]))) surf.blit(xformed, (dest_rect[0], dest_rect[1])) elif isinstance(sprite, sprites.TriangleSprite): surf = self._get_drawing_surface() color255 = list(util.bound(int(c * 256), 0, 255) for c in sprite.color()) xformed_pts = [(p[0] * mult - offs[0], p[1] * mult - offs[1]) for p in sprite.points()] pygame.draw.polygon(surf, color255, xformed_pts)
def _get_temp_zoom_prog(self): if self._temp_zoom_idx is None: return 0 elif self._use_temp_zoom: return util.bound( self._temp_zoom_tick_count / self._temp_zoom_delay, 0, 1) else: return util.bound( 1 - self._temp_zoom_tick_count / self._temp_zoom_delay, 0, 1)
def draw_with_transparency(src_sheet, src_rect, dest_sheet, dest_pos, alpha): """ :param alpha: a value from [0.0, 1.0] where 0.0 is fully transparent """ draw_wtih_color_xform( src_sheet, src_rect, dest_sheet, dest_pos, lambda color: (color[0], color[1], color[2], util.bound(color[3] * alpha, 0, 1)))
def adjust_base_zoom(self, dz: int): old_center = self.get_camera_center_in_world(ignore_temp_zoom=True) new_zoom_idx = util.bound(int(self._base_zoom_idx + dz), 0, len(_ZOOM_LEVELS) - 1) self._base_zoom_idx = new_zoom_idx self.set_camera_center_in_world(old_center)
def _handle_inputs(self): edits = inputs.get_instance().all_pressed_ascii_keys() text = self.text cursor_pos = self.cursor_pos jump_cursor = inputs.get_instance().was_pressed_two_way( pygame.K_HOME, pygame.K_END) if jump_cursor < 0: cursor_pos = 0 elif jump_cursor > 0: cursor_pos = len(text) move_cursor = 0 if inputs.get_instance().was_pressed_or_held_and_repeated( pygame.K_LEFT) and not inputs.get_instance().is_held( pygame.K_RIGHT): move_cursor = -1 if inputs.get_instance().was_pressed_or_held_and_repeated( pygame.K_RIGHT) and not inputs.get_instance().is_held( pygame.K_LEFT): move_cursor = 1 if move_cursor != 0: cursor_pos = util.bound(cursor_pos + move_cursor, 0, len(text)) if inputs.get_instance().was_pressed_or_held_and_repeated( pygame.K_DELETE): text, cursor_pos = util.apply_ascii_edits_to_text( text, ["~delete~"], cursor_pos=cursor_pos) if not inputs.get_instance().was_pressed( pygame.K_BACKSPACE) and inputs.get_instance( ).was_pressed_or_held_and_repeated(pygame.K_BACKSPACE): # backspace is an ascii character, so if it was pressed this frame it'll be in edits text, cursor_pos = util.apply_ascii_edits_to_text( text, ["\b"], cursor_pos=cursor_pos) # TODO can't hold regular keys to make them repeat if len(edits) > 0: text, cursor_pos = util.apply_ascii_edits_to_text( text, edits, cursor_pos=cursor_pos, max_len=self.char_limit, allowlist=self.allowed_chars) self.text = text self.cursor_pos = cursor_pos
def resolve_explicit_song_id_from_level(explicit_song_id): if explicit_song_id in _SONG_MAPPINGS_FOR_LEVELS: return _SONG_MAPPINGS_FOR_LEVELS[explicit_song_id][0] else: try: # it should look like "sector_ab_2", in which case we need to extract "sector_ab" and 2. underscore_idx = explicit_song_id.rindex("_") key = explicit_song_id[0:underscore_idx] idx = int(explicit_song_id[underscore_idx + 1:]) - 1 if key in _SONG_MAPPINGS_FOR_LEVELS: n_songs = len(_SONG_MAPPINGS_FOR_LEVELS[key]) return _SONG_MAPPINGS_FOR_LEVELS[key][util.bound( idx, -1, n_songs - 1)] else: print( "WARN: unrecognized song id: {}".format(explicit_song_id)) except Exception: print("WARN: song id couldn't be parsed: {}".format( explicit_song_id)) # if we failed to resolve the explicit ID, just bail. return SILENCE
def get_prog(self): if self.duration < 0: return 0 else: return util.bound(self.ticks_active / self.duration, 0, 1)
def set_clear_color(self, color): self.clear_color = tuple(util.bound(int(c * 256), 0, 255) for c in color)
def set_master_volume(val): global _MASTER_VOLUME, CURRENT_SONG if val != _MASTER_VOLUME: print("INFO: setting master music volume to {}".format(val)) _MASTER_VOLUME = util.bound(val, 0.0, 1.0) pygame.mixer.music.set_volume(_MASTER_VOLUME * CURRENT_SONG.volume)
def set_volume(volume): global _MASTER_VOLUME _MASTER_VOLUME = util.bound(volume, 0.0, 1.0)