我们从Python开源项目中,提取了以下50个代码示例,用于说明如何使用pygame.rect()。
def _draw_agent(center_point, screen, base_size=30): ''' Args: center_point (tuple): (x,y) screen (pygame.Surface) Returns: (pygame.rect) ''' # taxi_image = pygame.image.load("taxi.png") # image_rect = taxi_image.get_rect() tri_bot_left = center_point[0] - base_size, center_point[1] + base_size tri_bot_right = center_point[0] + base_size, center_point[1] + base_size tri_top = center_point[0], center_point[1] - base_size tri = [tri_bot_left, tri_top, tri_bot_right] tri_color = (98, 140, 190) # screen.blit(taxi_image, image_rect) # return image_rect return pygame.draw.polygon(screen, tri_color, tri)
def added_to_stage(self, stage): """ adjusts our max positions based on the stage's level's dimensions - only if it's a Level (not a simple Screen) :param Stage stage: the Stage we were added to """ # TODO: make this independent on Level or simple Screen (even a Screen should have dimensions) if isinstance(stage.screen, Level): if self.x_min == "auto": self.x_min = 0 if self.x_max == "auto": self.x_max = stage.screen.width - self.rect.width if self.y_min == "auto": self.y_min = 0 if self.y_max == "auto": self.y_max = stage.screen.height - self.rect.height
def collide_simple_with_sprite(self, sprite, collision_detector): """ Collides a Sprite (that only obeys simple physics rules) with a TiledTileLayer and solves all detected collisions. The Sprite needs to have the properties vx and vy, which are interpreted as the Sprite's velocity. Ignores slopes. :param Sprite sprite: the Sprite to test for collisions against a TiledTileLayer :param callable collision_detector: the collision detector method to use (this is set in the Sprite's Stage's options) """ tile_start_x, tile_end_x, tile_start_y, tile_end_y = self.get_overlapping_tiles(sprite) xy, v = Stage.estimate_sprite_direction(sprite) # very simple algo: look through tile list (in no particular order) and return first tile that collides # None if no colliding tile found for tile_x in range(tile_start_x, tile_end_x + 1): for tile_y in range(tile_start_y, tile_end_y + 1): tile_sprite = self.tile_sprites[tile_x, tile_y] if not tile_sprite: continue col = collision_detector(sprite, tile_sprite, collision_objects=None, direction=xy, direction_veloc=v, original_pos=(sprite.rect.x, sprite.rect.y)) if col: return col return None
def __init__(self, layer, pytmx_tiled_map, id_, tile_props, rect): """ :param TiledTileLayer layer: the TiledTileLayer object to which this tile belongs :param pytmx.pytmx.TiledMap pytmx_tiled_map: the tmx tiled-map object to which this tile belongs (useful to have to look up certain map-side properties, e.g. tilewidth/height) :param int id_: tthe ID of the tile in the layer :param dict tile_props: the properties dict of this tile (values already translated into python types) :param Union[pygame.Rect,None] rect: the pygame.Rect representing the position and size of the tile """ super().__init__(rect.x, rect.y, width_height=(rect.width, rect.height)) self.tiled_tile_layer = layer self.pytmx_tiled_map = pytmx_tiled_map self.tile = id_ self.tile_x = self.rect.x // self.pytmx_tiled_map.tilewidth self.tile_y = self.rect.y // self.pytmx_tiled_map.tileheight self.tile_props = tile_props # add the `dockable` type to all tiles self.type |= Sprite.get_type("dockable")
def __init__(self, layer, pytmx_tiled_map, id_, tile_props, rect): """ :param TiledTileLayer layer: the TiledTileLayer object to which this tile belongs :param pytmx.pytmx.TiledMap pytmx_tiled_map: the tmx tiled-map object to which this tile belongs (useful to have to look up certain map-side properties, e.g. tilewidth/height) :param int id_: tthe ID of the tile in the layer :param dict tile_props: the properties dict of this tile (values already translated into python types) :param Union[pygame.Rect,None] rect: the pygame.Rect representing the position and size of the tile """ super().__init__(layer, pytmx_tiled_map, id_, tile_props, rect) # slope properties of the tile self.slope = tile_props.get("slope", None) # the slope property of the tile in the tmx file (inverse steepness (1/m in y=mx+b) of the line that defines the slope) self.offset = tile_props.get("offset", None) # the offset property of the tile in the tmx file (in px (b in y=mx+b)) self.is_full = (self.slope == 0.0 and self.offset == 1.0) # is this a full collision tile? self.max_x = self.pytmx_tiled_map.tilewidth self.max_y = max(self.get_y(0), self.get_y(self.rect.width)) # store our highest y-value (height of this tile)
def tick(self, game_loop): """ Needs to be called by the GameObject at some point during the GameObject's `tick` method. :param GameLoop game_loop: the currently playing GameLoop object """ obj = self.game_object self.reset() if self.game_obj_cmp_anim and self.game_obj_cmp_anim.flags & Animation.get_flag("paralyzes"): return # look for edges ahead -> then change direction if one is detected # - makes sure an enemy character does not fall off a cliff if (not (game_loop.frame % 3) and self.check_cliff_ahead()) or obj.rect.x <= 0 or obj.rect.x >= obj.x_max: self.toggle_direction() self.commands["left" if self.flipped else "right"] = True
def check_cliff_ahead(self): """ Checks whether there is a cliff ahead (returns true if yes). """ obj = self.game_object tile_w = obj.stage.screen.tmx_obj.tilewidth tile_h = obj.stage.screen.tmx_obj.tileheight # check below character (c=character sprite, _=locateObject (a stripe with x=x width=w-6 and height=3)) # ccc -> walking direction # ccc # _ w = max(tile_w * 1.5, obj.rect.width - 6) col = obj.stage.locate((obj.rect.right - tile_w - w) if self.flipped else (obj.rect.left + tile_w), obj.rect.bottom - tile_h * 0.5, w, tile_h * 1.75, Sprite.get_type("default")) if not col or isinstance(col.sprite2, LiquidBody): return True return False # checks whether an enemy is in sight
def move(self, sprite, x, y, absolute=False): """ This will 'overwrite' the normal Sprite's `move` method by Component's extend. :param Sprite sprite: the GameObject that this Component belongs to (the Sprite to move around) :param Union[int,None] x: the amount in pixels to move in x-direction :param Union[int,None] y: the amount in pixels to move in y-direction :param bool absolute: whether x and y are given as absolute coordinates (default: False): in this case x/y=None means do not move in this dimension """ orig_x = sprite.rect.x orig_y = sprite.rect.y # first call the original Sprite's move method sprite._super_move(x, y, absolute) # move all our docked Sprites along with us if not absolute: for docked_sprite in self.docked_sprites: docked_sprite.move(x, y, absolute=False) else: # translate into relative movement: we don't want the docked components to move to the given mothership's absolute values x_move = x - orig_x if x is not None else 0 y_move = y - orig_y if y is not None else 0 for docked_sprite in self.docked_sprites: docked_sprite.move(x_move, y_move)
def tick(self, game_loop): """ Moving elevator up and down OR left and right. """ dt = game_loop.dt self.move(self.vx * dt, self.vy * dt) if self.direction == "x": if self.rect.x < self.min_pos: self.vx = abs(self.vx) self.move(self.min_pos, None, absolute=True) elif self.rect.x > self.max_pos: self.vx = -abs(self.vx) self.move(self.max_pos, None, absolute=True) else: if self.rect.y < self.min_pos: self.vy = abs(self.vy) self.move(None, self.min_pos, absolute=True) elif self.rect.y > self.max_pos: self.vy = -abs(self.vy) self.move(None, self.max_pos, absolute=True)
def lock_ladder(self): """ Locks the GameObject into a ladder. Makes sure that there is nothing in the x-way (to move to the center of the ladder if standing a little bit aside). Otherwise, will not lock. """ obj = self.game_object # test x-direction after corrective x-move to center of ladder (if there is something, don't lock) #obj.stage.locate() self.on_ladder = self.touched_ladder # switch off gravity self.gravity = False # lock obj to center of ladder (touched_ladder is always set to the one we are touching right now) obj.rect.centerx = self.touched_ladder.rect.centerx self.vx = 0 # stop x-movement # undock all objects currently docked to us (if any) self.game_obj_cmp_dockable.undock_all_docked_objects() # store the type before it locked to the ladder and remove the dockable/one-way-platform types (if set) self.type_before_ladder = obj.type obj.type &= ~Sprite.get_type("one_way_platform,dockable")
def collide(sprite1, sprite2, collision_objects=None, original_pos=None): """ solves a simple spatial collision problem for two Sprites (that have a rect property) - defaults to SAT collision between two objects - thanks to doc's at: http://www.sevenson.com.au/actionscript/sat/ - TODO: handle angles on objects - TODO: handle velocities of sprites prior to collision to calculate correct normals :param Sprite sprite1: sprite 1 :param Sprite sprite2: sprite 2 (the other sprite) :param Union[None,Tuple[Collision]] collision_objects: the two always-recycled returnable Collision instances (aside from None); if None, use our default ones :param Union[Tuple[int],None] original_pos: the position of sprite1 before doing the move that lead to this collision-detection call :return: a Collision object with all details of the collision between the two Sprites (None if there is no collision) :rtype: Union[None,Collision] """ pass
def __init__(self,ishape,pos): if not isinstance(ishape, tuple): ishape = ishape,None image,shape = ishape if shape == None: shape = pygame.Rect(0,0,image.get_width(),image.get_height()) if isinstance(shape, tuple): shape = pygame.Rect(shape) self.image = image self._image = self.image self.shape = shape self.rect = pygame.Rect(pos[0],pos[1],shape.w,shape.h) self._rect = pygame.Rect(self.rect) self.irect = pygame.Rect(pos[0]-self.shape.x,pos[1]-self.shape.y, image.get_width(),image.get_height()) self._irect = pygame.Rect(self.irect) self.groups = 0 self.agroups = 0 self.updated = 1
def setimage(self,ishape): """Set the image of the Sprite. Arguments: ishape -- an image, or an image, rectstyle. The rectstyle will describe the shape of the image, used for collision detection. """ if not isinstance(ishape, tuple): ishape = ishape,None image,shape = ishape if shape == None: shape = pygame.Rect(0,0,image.get_width(),image.get_height()) if isinstance(shape, tuple): shape = pygame.Rect(shape) self.image = image self.shape = shape self.rect.w,self.rect.h = shape.w,shape.h self.irect.w,self.irect.h = image.get_width(),image.get_height() self.updated = 1
def run_codes(self,cdata,rect): """Run codes. Arguments: cdata -- a dict of code:(handler function, value) rect -- a tile rect of the parts of the layer that should have their codes run """ tw,th = self.tiles[0].image.get_width(),self.tiles[0].image.get_height() x1,y1,w,h = rect clayer = self.clayer t = Tile() for y in range(y1,y1+h): for x in range(x1,x1+w): n = clayer[y][x] if n in cdata: fnc,value = cdata[n] t.tx,t.ty = x,y t.rect = pygame.Rect(x*tw,y*th,tw,th) fnc(self,t,value)
def get_vector_to_closest_pond(self): x_offset = self.closest_pond.rect.centerx - self.rect.centerx y_offset = self.closest_pond.rect.centery - self.rect.centery vector_length = math.sqrt((x_offset * x_offset) + (y_offset * y_offset)) if x_offset == 0 or vector_length == 0: x_vel = 0 else: x_vel = x_offset / vector_length if y_offset == 0 or vector_length == 0: y_vel = 0 else: y_vel = y_offset / vector_length self.closest_pond_vector = x_vel, y_vel
def get_vector_to_closest_food(self): x_offset = self.closest_food.rect.centerx - self.rect.centerx y_offset = self.closest_food.rect.centery - self.rect.centery vector_length = math.sqrt((x_offset * x_offset) + (y_offset * y_offset)) if x_offset == 0 or vector_length == 0: x_vel = 0 else: x_vel = x_offset / vector_length if y_offset == 0 or vector_length == 0: y_vel = 0 else: y_vel = y_offset / vector_length self.closest_food_vector = x_vel, y_vel
def render(self, color): pygame.draw.rect(Renderer.SCREEN, color, self.rect, 0) # Line to nearest entity #pygame.draw.line(Renderer.SCREEN, (0, 255, 0), (self.rect.centerx, self.rect.centery), (self.closest_entity.rect.centerx, self.closest_entity.rect.centery), 1) # Line to nearest food #pygame.draw.line(Renderer.SCREEN, (255, 0, 0), (self.x + self.size / 2, self.y + self.size / 2), (self.closest_food.x + 3, self.closest_food.y + 3), 1) # Line following movement vector #start_line = self.x + self.size / 2, self.y + self.size / 2 #end_line = self.x + (self.size / 2) + (60 * self.closest_food_vector[0]), self.y + (self.size / 2) + (60 * self.closest_food_vector[1]) #moving_line_start = self.x + (self.size / 2), self.y + (self.size / 2) #moving_line_end = moving_line_start[0] + (20 * self.dx), moving_line_start[1] + (20 * self.dy) #pygame.draw.line(Renderer.SCREEN, (0, 255, 0), moving_line_start, moving_line_end, 1) #pygame.draw.line(Renderer.SCREEN, (0, 255, 0), start_line, end_line, 1)
def _draw_agent(center_point, screen, base_size=30): ''' Args: center_point (tuple): (x,y) screen (pygame.Surface) Returns: (pygame.rect) ''' tri_bot_left = center_point[0] - base_size, center_point[1] + base_size tri_bot_right = center_point[0] + base_size, center_point[1] + base_size tri_top = center_point[0], center_point[1] - base_size tri = [tri_bot_left, tri_top, tri_bot_right] tri_color = (98, 140, 190) return pygame.draw.polygon(screen, tri_color, tri)
def move(self, x, y, absolute=False): """ Moves us by x/y pixels (or to x,y if absolute=True). :param Union[int,None] x: the amount in pixels to move in x-direction :param Union[int,None] y: the amount in pixels to move in y-direction :param bool absolute: whether x and y are given as absolute coordinates (default: False): in this case x/y=None means do not move in this dimension """ # absolute coordinates given if absolute: if x is not None: self.rect.x = x if y is not None: self.rect.y = y # do a minimum of 1 pix (if larger 0.0) else: if 0 < x < 1: x = 1 self.rect.x += x if 0 < y < 1: y = 1 self.rect.y += y # then we do the boundary checking if self.x_max is not None and self.rect.x > self.x_max: self.rect.x = self.x_max elif self.x_min is not None and self.rect.x < self.x_min: self.rect.x = self.x_min if self.y_max is not None and self.rect.y > self.y_max: self.rect.y = self.y_max elif self.y_min is not None and self.rect.y < self.y_min: self.rect.y = self.y_min # @override(GameObject)
def render(self, display): """ Paints the Sprite with its current image onto the given Display object. :param Display display: the Display object to render on (Display has a pygame.Surface, on which we blit our image) """ if self.image: #print("render at x={}".format(self.rect.x + self.image_rect.x - display.offsets[0])) display.surface.blit(self.image, (self.rect.x + self.image_rect.x - display.offsets[0], self.rect.y + self.image_rect.y - display.offsets[1])) if DEBUG_FLAGS & DEBUG_RENDER_SPRITES_RECTS: pygame.draw.rect(display.surface, DEBUG_RENDER_SPRITES_RECTS_COLOR, pygame.Rect((self.rect.x - display.offsets[0], self.rect.y - display.offsets[1]), (self.rect.w, self.rect.h)), 1)
def __init__(self, x, y, image_file, **kwargs): ro = kwargs.pop("render_order", 0) # by default, make this Sprite render first super().__init__(x, y, image_file=image_file, render_order=ro, **kwargs) self.vx = kwargs.get("vx", 1) self.vy = kwargs.get("vy", 1) self.repeat_x = kwargs.get("repeat_x", True) self.repeat_y = kwargs.get("repeat_y", True) self.repeat_w = kwargs.get("repeat_w", self.rect.width) self.repeat_h = kwargs.get("repeat_h", self.rect.height) # don't collide with anything self.type = Sprite.get_type("none") self.collision_mask = 0 # @override(Sprite)
def render(self, display): # debug rendering (no backgrounds) -> early out if DEBUG_FLAGS & DEBUG_DONT_RENDER_TILED_TILE_LAYERS: return self.ignore_after_n_ticks = 100 # replenish counter so that the repeater never goes out of the Viewport's scope view_x = display.offsets[0] view_y = display.offsets[1] offset_x = self.rect.x + view_x * self.vx offset_y = self.rect.y + view_y * self.vy if self.repeat_x: start_x = math.floor(-offset_x % self.repeat_w) if start_x > 0: start_x -= self.repeat_w else: start_x = self.rect.x - view_x if self.repeat_y: start_y = math.floor(-offset_y % self.repeat_h) if start_y > 0: start_y -= self.repeat_h else: start_y = self.rect.y - view_y scale = 1.0 cur_y = start_y while cur_y < display.height / scale: cur_x = start_x while cur_x < display.width / scale: #display.surface.blit(self.image, dest=(math.floor(cur_x + view_x), math.floor(cur_y + view_y))) display.surface.blit(self.image, dest=(math.floor(cur_x), math.floor(cur_y))) cur_x += self.repeat_w if not self.repeat_x: break cur_y += self.repeat_h if not self.repeat_y: break
def add_sprite(self, sprite, group_name): """ Adds a new single Sprite to an existing or a new pygame.sprite.Group. :param Sprite sprite: the Sprite to be added to this Stage (the Sprite's position is defined in its rect.x/y properties) :param str group_name: the name of the group to which the GameObject should be added (group will not be created if it doesn't exist yet) :return: the Sprite that was added :rtype: Sprite """ # if the group doesn't exist yet, create it if group_name not in self.sprite_groups: self.sprite_groups[group_name] = pygame.sprite.Group() sprite.stage = self # set the Stage of this GameObject self.sprite_groups[group_name].add(sprite) self.sprites.append(sprite) sprite.sprite_groups.append(self.sprite_groups[group_name]) # add each single Sprite to the sorted (by render_order) to_render list and to the "all"-sprites list # - note: the to_render list also contains entire TiledTileLayer objects if sprite.do_render: self.to_render.append(sprite) self.to_render.sort(key=lambda x: x.render_order) # trigger two events, one on the Stage with the object as target and one on the object with the Stage as target self.trigger_event("added_to_stage", sprite) sprite.trigger_event("added_to_stage", self) return sprite
def __init__(self, pytmx_layer, pytmx_tiled_map, tile_sprite_handler): """ :param pytmx.pytmx.TiledTileLayer pytmx_layer: the underlying pytmx TiledTileLayer :param pytmx.pytmx.TiledMap pytmx_tiled_map: the underlying pytmx TiledMap object (representing the tmx file) :param callable tile_sprite_handler: the callable that returns an ndarray, populated with TileSprite objects for storage in this layer """ super().__init__(pytmx_layer, pytmx_tiled_map) self.type_str = self.properties.get("type", "none") self.type = 0 # get type mask of this layer from `type` property for t in self.type_str.split(","): self.type |= Sprite.get_type(t) # an ndarray holding all single tiles (by x/y position) from this layer # non-existing tiles are not(!) stored in this ndarray and return None at the respective x/y position self.tile_sprites = tile_sprite_handler(self) # update do_render indicator depending on some debug settings self.do_render = (self.properties["do_render"] == "true" and not (DEBUG_FLAGS & DEBUG_DONT_RENDER_TILED_TILE_LAYERS)) or \ (self.type != Sprite.get_type("none") and (DEBUG_FLAGS & DEBUG_RENDER_COLLISION_TILES)) self.render_order = int(self.properties["render_order"]) # put this layer in one single Sprite that we can then blit on the display (with 'area=[some rect]' to avoid drawing the entire layer each time) self.pygame_sprite = None # we are rendering this layer, need to store entire image in this structure if self.do_render: self.pygame_sprite = self.build_sprite_surface()
def build_sprite_surface(self): """ Builds the image (pygame.Surface) for this tile layer based on all found tiles in the layer. """ surf = pygame.Surface((self.pytmx_layer.width * self.pytmx_tiled_map.tilewidth, self.pytmx_layer.height * self.pytmx_tiled_map.tileheight), flags=pygame.SRCALPHA) # rendered collision layer if self.type != Sprite.get_type("none") and (DEBUG_FLAGS & DEBUG_RENDER_COLLISION_TILES): # red for normal collisions, light-blue for touch collisions color = DEBUG_RENDER_COLLISION_TILES_COLOR_DEFAULT if self.type & Sprite.get_type("default") else DEBUG_RENDER_COLLISION_TILES_COLOR_OTHER for (x, y, image), (_, _, gid) in zip(self.pytmx_layer.tiles(), self.pytmx_layer.iter_data()): surf.blit(image.convert_alpha(), (x * self.pytmx_tiled_map.tilewidth, y * self.pytmx_tiled_map.tileheight)) tile_props = self.pytmx_tiled_map.get_tile_properties_by_gid(gid) or {} # normal collision tiles if not tile_props.get("no_collision"): pygame.draw.rect(surf, color, pygame.Rect((x * self.pytmx_tiled_map.tilewidth, y * self.pytmx_tiled_map.tileheight), (self.pytmx_tiled_map.tilewidth, self.pytmx_tiled_map.tileheight)), 1) # "normal" layer (and no debug rendering) else: for x, y, image in self.pytmx_layer.tiles(): surf.blit(image.convert_alpha(), (x * self.pytmx_tiled_map.tilewidth, y * self.pytmx_tiled_map.tileheight)) pygame_sprite = pygame.sprite.Sprite() pygame_sprite.image = surf pygame_sprite.rect = surf.get_rect() return pygame_sprite
def render(self, display): """ Blits a part of our Sprite's image onto the Display's Surface using the Display's offset attributes. :param Display display: the Display object to render on """ assert self.do_render, "ERROR: TiledTileLayer.render() called but self.do_render is False!" assert not isinstance(self.pygame_sprite, Sprite), "ERROR: TiledTileLayer.render() called but self.pygame_sprite is not a Sprite!" r = pygame.Rect(self.pygame_sprite.rect) # make a clone so we don't change the original Rect # apply the display offsets (camera) r.x += display.offsets[0] r.y += display.offsets[1] r.width = display.width r.height = display.height display.surface.blit(self.pygame_sprite.image, dest=(0, 0), area=r)
def get_y(self, x): """ Calculates the y value (in normal cartesian y-direction (positive values on up axis)) for a given x-value. :param int x: the x-value (x=0 for left edge of tile x=tilewidth for right edge of tile) :return: the calculated y-value :rtype: int """ # y = mx + b if self.slope is None or self.offset is None: return 0 return self.slope * min(x, self.max_x) + self.offset * self.rect.height
def sloped_xy_pull(self, sprite): """ Applies a so-called xy-pull on a Sprite object moving in x-direction in this sloped tile. An xy-pull is a change in the y-coordinate because of the x-movement (sliding up/down a slope while moving left/right). :param Sprite sprite: the Sprite object that's moving on the slope """ if self.slope == 0 or not self.slope: return # the local x value for the Sprite on the tile's internal x-axis (0=left edge of tile) x_local = max(0, (sprite.rect.left if self.slope < 0 else sprite.rect.right) - self.rect.left) # the absolute y-position that we will force the sprite into y = self.rect.bottom - self.get_y(x_local) - sprite.rect.height sprite.move(None, y, True)
def invert(self): """ Inverts this Collision in place to yield the Collision for the case that the two Sprites are switched. """ # flip the sprites tmp = self.sprite1 self.sprite1 = self.sprite2 self.sprite2 = tmp # invert the normal and separate (leave distance negative, leave magnitude positive) self.normal_x = -self.normal_x self.normal_y = -self.normal_y self.separate = [-self.separate[0], -self.separate[1]] # the direction veloc self.direction_veloc = -self.direction_veloc return self ## OBSOLETE CLASS #class PlatformerCollision(Collision): # """ # A collision object that can be used by PlatformerPhysics to handle Collisions. # """ # # def __init__(self): # super().__init__() # self.impact = 0.0 # the impulse of the collision on some mass (used for pushing heavy objects) # # OBSOLETE: these should all be no longer needed # # self.slope = False # whether this is a collision with a sloped TileSprite of a TiledTileLayer # (will also be False if obj1 collides with the Tile's rect, but obj1 is still in air (slope)) # # self.slope_y_pull = 0 # amount of y that Sprite has to move up (negative) or down (positive) because of the collision (with a slope) # #self.slope_up_down = 0 # 0=no slope, -1=down slope, 1 = up slope
def get_highest_tile(tiles, direction, start_abs, end_abs): """ Returns the `highest` tile in a list (row or column) of sloped, full-collision or empty tiles. :param list tiles: the list of tiles to check :param str direction: the direction in which the list of tiles is arranged (x=row of tiles or y=column of tiles) :param int start_abs: the absolute leftmost x-value from where to check :param int end_abs: the absolute rightmost x-value from where to check :return: a tuple consisting of a) the highest SlopedTileSprite found in the list and b) the height value measured on a cartesian y-axis (positive=up) :rtype: Tuple[SlopedTileSprite,int] """ # start with leftmost tile (measure max height for the two x points: sprite's leftmost edge and tile's right edge) best_tile = None # the highest tile in this row (if not height==0.0) tile = tiles[0] if tile: max_y = max(tile.get_y(start_abs - tile.rect.left), tile.get_y(tile.rect.width)) best_tile = tile else: max_y = 0 # then do all center tiles for slot in range(1, len(tiles) - 1): tile = tiles[slot] max_ = tile.max_y if tile else 0 if max_ > max_y: max_y = max_ best_tile = tile # then do the rightmost tile (max between tiles left edge and sprite's right edge) tile = tiles[-1] max_ = max(tile.get_y(end_abs - tile.rect.left), tile.get_y(0)) if tile else 0 if max_ > max_y: max_y = max_ best_tile = tile # TODO: store x-in and y-pull(push) in tile props (as temporary values) return best_tile, max_y
def push_an_object(self, pusher, col): """ Pushes a pushable other GameObject (assuming that this other object also has a PlatformerPhysics Component). :param pusher: the Sprite that's actively pushing against the other GameObject :param col: the Collision object (that caused the push) returned by the collision detector method """ pushee = col.sprite2 # the object being pushed orig_x = pushee.rect.x pushee_phys = pushee.components["physics"] # calculate the amount to move in x-direction based on vx_max and the collision-separation move_x = - col.separate[0] * abs(pushee_phys.vx_max / col.direction_veloc) # adjust x-speed based on vx_max self.vx = math.copysign(pushee_phys.vx_max, col.direction_veloc) # first move rock, then do a x-collision detection of the rock, then fix that collision (if any) -> only then move the pusher pushee.move(move_x, 0) # TODO: be careful not to overwrite the col object that's currently still being used by this method's caller # right now it's being overridden by the below call -> it's not a problem yet because this collision object is only used further via the normal_x # property, which should stay the same self.collide_in_one_direction(pushee, "x", self.vx, (orig_x, pushee.rect.y)) # re-align pusher with edge of pushee if self.vx < 0: x_delta = pushee.rect.right - pusher.rect.left else: x_delta = pushee.rect.left - pusher.rect.right # and we are done pusher.move(x_delta, 0)
def follow(self, game_loop=None, first=False): """ Helper method to follow our self.obj_to_follow (should not be called by the API user). Called when the Stage triggers Event 'post_tick' (passes GameLoop into it which is not used). :param GameLoop game_loop: the GameLoop that's currently playing :param bool first: whether this is the very first call to this function (if so, do a hard center on, otherwise a soft-center-on) """ follow_x = self.directions["x"](self.obj_to_follow) if callable(self.directions["x"]) else self.directions["x"] follow_y = self.directions["y"](self.obj_to_follow) if callable(self.directions["y"]) else self.directions["y"] func = self.center_on if first else self.soft_center_on func(self.obj_to_follow.rect.centerx if follow_x else None, self.obj_to_follow.rect.centery if follow_y else None)
def collide(sprite1, sprite2, collision_objects=None, original_pos=None): # use default CollisionObjects? if not collision_objects: collision_objects = SATCollision.default_collision_objects # do AABB first for a likely early out # TODO: right now, we only have pygame.Rect anyway, so these are AABBs if (sprite1.rect.right < sprite2.rect.left or sprite1.rect.bottom < sprite2.rect.top or sprite2.rect.right < sprite1.rect.left or sprite2.rect.right < sprite1.rect.left): return None test = SATCollision.try_collide(sprite1, sprite2, collision_objects[0], False) if not test: return None test = SATCollision.try_collide(sprite2, sprite1, collision_objects[1], True) if not test: return None # pick the best collision from the two ret = collision_objects[1] if collision_objects[1].magnitude < collision_objects[0].magnitude else collision_objects[0] if not ret.is_collided: return None # fill in some more values in the recycled Collision object before returning it ret.separate[0] = - ret.distance * ret.normal_x ret.separate[1] = - ret.distance * ret.normal_y if not original_pos: original_pos = (sprite1.rect.x, sprite1.rect.y) ret.original_pos = original_pos return ret
def hit(self,x,y,t,s): tiles = self.tiles tw,th = tiles[0].image.get_width(),tiles[0].image.get_height() t.tx = x t.ty = y t.rect = Rect(x*tw,y*th,tw,th) t._rect = t.rect if hasattr(t,'hit'): t.hit(self,t,s)
def loop(self): """Update and hit testing loop. Run this once per frame.""" self.loop_sprites() #sprites may move self.loop_tilehits() #sprites move self.loop_spritehits() #no sprites should move for s in self.sprites: s._rect = pygame.Rect(s.rect)
def __init__(self, ai_settings, screen, ship): """??????????""" #super(Bullet, self).__init__() ???2.7?? ?? 3.0?? ?? super().__init__() self.screen = screen #class Foo(): ????????? # def __init__(self, frob, frotz) # self.frobnicate = frob # self.frotz = frotz #class Bar(Foo): # def __init__(self, frob, frizzle) # super().__init__(frob, 34) # self.frazzle = frizzle # ??0.0???????????????????. self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height) self.rect.centerx = ship.rect.centerx self.rect.top = ship.rect.top # ??????????? self.y = float(self.rect.y) self.color = ai_settings.bullet_color self.speed_factor = ai_settings.bullet_speed_factor #???? ????? ??? pygame.rect() ?????????? #?? ?????????? X Y ?? ?? ?? ????? ????? ?settings ???? #rect.centerx ?????????? #rect.top ????????????
def update(self): """??????.""" # ??????????. ???????? ??????? self.y -= self.speed_factor # ?? rect ??. ???????? self.rect.y = self.y
def draw_bullet(self): """???????.""" pygame.draw.rect(self.screen, self.color, self.rect) #?draw.recct() ???self.color????????rect ???????
def rect(self): return Rect(self.x, self.y, Tile.width, Tile.height)
def render(self): pygame.draw.rect(Renderer.SCREEN, self.color, self.rect, 0)
def rect(self): return Rect(self.x, self.y, self.width, self.height) # Initialises the Tileset and adds columns and rows
def is_at(self, x, y): return self.rect.collidepoint(x, y) # Specifies if the Tileset is at the current mouse position
def render(self): for col in range(self.cols): for row in range(self.rows): self.tiles[col][row].render() if self.show_grid: pygame.draw.rect(Renderer.SCREEN, Renderer.COLOR_BLACK, self.tiles[col][row].rect, 1)
def rect(self): return Rect(self.x, self.y, self.size, self.size)