def move(self, collider, new_pixel_position, tf_dispatch_events=False): """Teleports the collider to new position, and returns any resulting collisions""" collider.position = copy_vector(new_pixel_position) collider.rect.x, collider.rect.y = collider.position.x, collider.position.y collisions = [] if collider.mask == 0: return collisions # optimization: no sense in wasting loops on something that never collides # check for collisions against world grid, if applicable if (collider.mask & constants.Block) != 0: collisions.extend(self.get_world_collisions(collider)) for other_collider in (c for c in self._colliders if c is not collider): if (collider.mask & other_collider.layer) == 0: continue if collider.rect.colliderect( other_collider.rect) and other_collider not in collisions: collisions.append( Collision(collider, other_collider, copy_vector(collider.position))) if tf_dispatch_events: ColliderManager.dispatch_events(collider, collisions) return collisions
def get_world_collisions(self, collider): tw, th = self.tile_map.tile_width, self.tile_map.tile_height tmw, tmh = self.tile_map.width, self.tile_map.height # determine which grid square(s) the collider is in left, right = int(collider.rect.left / tw), int(collider.rect.right / tw) top, bottom = int(collider.rect.top / th), int(collider.rect.bottom / th) r = Rect(left * tw, top * th, tw, th) collisions = [] # each of these tiles is potentially intersecting the collider for x in range(left, right + 1): if x < 0 or x >= tmw: continue for y in range(top, bottom + 1): if y < 0 or y >= tmh: continue if not self.tile_map.get_passable((x, y)): # a non-passable tile might be within range: now use a pixel-perfect collision test r.x = x * tw r.y = y * th if collider.rect.colliderect(r): collisions.append( Collision(moved_collider=collider, hit_thing=(x, y), moved_collider_position=copy_vector( collider.position))) return collisions
def _handle_vertical_movement(self, dt): self.update_airborne() current_velocity = copy_vector(self.velocity) if not self._airborne: current_velocity.y = 0 else: current_velocity.y += (self.parameters.gravity * dt) # limit downward velocity if current_velocity.y > self.parameters.max_vertical_velocity: current_velocity.y = self.parameters.max_vertical_velocity vel = make_vector(0, current_velocity.y) target_pos = self.entity.position + vel * dt self.airborne_collider.position = self.entity.position self.velocity = current_velocity # very important to be accurate with vertical movement because of the single pixel downward we use # for airborne detection. if any(self.airborne_collider.try_move(target_pos, True)): self.airborne_collider.approach(target_pos) self._airborne = False if self.on_hit: self.on_hit() self.entity.position = self.airborne_collider.position
def __init__(self, assets, level, scoring_labels: Labels, mario_stats): super().__init__() self.assets = assets self.scoring_labels = scoring_labels self.mario_stats = mario_stats self.level = level def make_centered(surface): return make_vector(*sr.center) - make_vector(surface.get_width() // 2, surface.get_height() // 2) sr = config.screen_rect tc = pygame.Color('white') self.elapsed = 0 self.world_title = Labels.font_large.render(level.title, True, tc).convert_alpha() self.world_title_pos = make_centered(self.world_title) - make_vector(0, 100) self.x = Labels.font_large.render("x", True, tc) self.x_pos = make_centered(self.x) + make_vector(0, 40) little_mario = assets.character_atlas.load_static("mario_stand_right").image # scale it up self.mario_icon = pygame.transform.scale2x(little_mario).convert() self.mario_pos = copy_vector(self.x_pos) - \ make_vector(self.mario_icon.get_width() * 2, self.mario_icon.get_height() // 4) self.lives = Labels.font_large.render(str(mario_stats.lives), True, tc).convert_alpha() self.lives_pos = self.x_pos + make_vector(self.mario_icon.get_width(), 0)
def __init__(self, position, initial_rect=None, anchor=Anchor.CENTER): # note to self: some elements won't have an initial rect (their content needs to be created), so # a None value is permissible here and will be changed when a layout event occurs super().__init__(initial_rect or pygame.Rect(position[0], position[1], 0, 0)) self.anchor = anchor self.parent = None self.children = [] self.relative_position = copy_vector(position) self.position = self.relative_position self.enabled = True
def __init__(self, entity, manager, mask, position, rect, layer, on_collision_callback=None): assert entity is not None assert manager is not None assert isinstance(mask, int) self.entity = entity self.manager = manager self.mask = mask or 0 self._position = copy_vector(position) self.rect = rect.copy() self.layer = layer self.on_collision = on_collision_callback
def __init__(self, window_position, size, background, anchor=Anchor.TOP_LEFT, draggable=True, background_mouseover=None): super().__init__(window_position, size, anchor) assert background is not None assert isinstance(background, pygame.Surface) or isinstance(background, pygame.Color) \ or isinstance(background, tuple) or isinstance(background, SlicedImage) or isinstance(background, Animation) self.element_position = copy_vector(window_position) self.background = background self.background_mouseover = background_mouseover or background self.draggable = draggable self.hidden_rect = None # event-related state self._is_dragging = False self._start_drag = pygame.Vector2() self._mouseover = False
def offset(self): return copy_vector(self._offset)
def position(self): return copy_vector(self._scroll_position)
def velocity(self, val): self.entity.velocity = copy_vector(val)
def get_velocity(self): return copy_vector(self._velocity)
def position(self): return copy_vector(self.mario_entity.position)
def get_scroll(self): return copy_vector(self.scroll_pos)
def position(self, pos): self._position = copy_vector(pos) self._rect.x, self._rect.y = pos
def deserialize(self, values): super().deserialize(values) self.movement.center_position = copy_vector(self.position)
def __init__(self, position, size, background, font, text, selected_image, unselected_image, is_selected=True, anchor=Anchor.TOP_LEFT, text_color=config.default_text_color, mouseover_image=None, on_selected_callback=None, on_deselected_callback=None): if background is not None: size = size or background.get_rect().size assert hasattr(selected_image, "get_rect") assert hasattr(unselected_image, "get_rect") super().__init__(position=position, size=size, background=background, text="", font=font, anchor=anchor, mouseover_image=mouseover_image) assert selected_image and unselected_image self.on_selected = on_selected_callback self.on_deselected = on_deselected_callback # create textures # position them on left side, in center relative = make_vector(0, size[1] // 2) self._texture_on = Texture(selected_image, relative) self._texture_off = Texture(unselected_image, relative) relative.y -= max(self._texture_off.height, self._texture_on.height) // 2 self._texture_on.relative_position = copy_vector(relative) self._texture_off.relative_position = copy_vector(relative) self.add_child(self._texture_on) self.add_child(self._texture_off) self.selected = is_selected # create text # position to right side of textures relative.x = max(self._texture_on.get_absolute_rect().right + 10, self._texture_off.get_absolute_rect().right + 10) relative.y = size[1] // 2 - font.get_height() // 2 self.text = Text(relative, text, font, text_color=text_color) self.add_child(self.text) self.layout()