def GetSegment(self, sideName): """ Gets a L{LineSegment<Utilities.vector.LineSegment>} that represents one of the sides of this GameTile in world space. @type sideName: C{str} @param sideName: Which side of the GameTile to get. Valid side names are: - C{'top'} - C{'bottom'} - C{'left'} - C{'right'} @rtype: L{LineSegment<Utilities.vector.LineSegment>} @return: One side of the tile as a line segment. """ topLeft = self.Position topRight = (topLeft[0] + self.Width, topLeft[1]) bottomLeft = (topLeft[0], topLeft[1] + self.Height) bottomRight = (topRight[0], bottomLeft[1]) segment = None if (sideName == Constants.TileConstants.SIDE_TOP): segment = LineSegment.from_points(topLeft, topRight) elif (sideName == Constants.TileConstants.SIDE_BOTTOM): segment = LineSegment.from_points(bottomLeft, bottomRight) elif (sideName == Constants.TileConstants.SIDE_LEFT): segment = LineSegment.from_points(topLeft, bottomLeft) elif (sideName == Constants.TileConstants.SIDE_RIGHT): segment = LineSegment.from_points(topRight, bottomRight) else: raise NameError(sideName + ' is not a proper side name') return segment
def __calc_x_collision_adjustment__(self, tiles, previousBB): """ Suggests a new X coordinate for the Actor's bounding box outside of the given colliding tiles. Checks tiles to the left and right of the Actor and finds the closest X coordinate that clears the bounding tiles. Coordinates are always adjusted in the direction of the Actor's previous position. @type tiles: C{list} @param tiles: L{GameTile<Map.GameTile.GameTile>}s colliding with either the left or right side of the Actor's bounding box. @type previousBB: C{U{pygame.Rect<http://www.pygame.org/docs/ref/rect.html>}} @param previousBB: Bounding box at the previous position. @rtype: C{(int, int)} @return: Suggested new X position and how close the intersection was to the previous position (-1 means no collision occurred). """ moveTo = self.Position[0] minDistance = -1 if not tiles: return moveTo, minDistance xVel = self.Velocity.x # a tile tile = tiles[0] # amount to move the boundary to avoid a false negative intersection bumpAmount = 0.0001 # get the tiles to the left or right if (xVel > 0): # going right tileSeg = tile.GetSegment(Constants.TileConstants.SIDE_LEFT) # prepare to create segments from our side at the old position to the side at the new position prevSide = LineSegment.from_points(previousBB.topright, previousBB.bottomright) if self.boundingBox.right == tileSeg.start.x: curSide = curSide = LineSegment.from_points((self.boundingBox.right + bumpAmount, self.boundingBox.top), (self.boundingBox.right + bumpAmount, self.boundingBox.bottom)) else: curSide = LineSegment.from_points(self.boundingBox.topright, self.boundingBox.bottomright) elif (xVel < 0): # going left tileSeg = tile.GetSegment(Constants.TileConstants.SIDE_RIGHT) # prepare to create segments from our side at the old position to the side at the new position prevSide = LineSegment.from_points(previousBB.topleft, previousBB.bottomleft) if self.boundingBox.left == tileSeg.start.x: curSide = LineSegment.from_points((self.boundingBox.left - bumpAmount, self.boundingBox.top), (self.boundingBox.left - bumpAmount, self.boundingBox.bottom)) else: curSide = LineSegment.from_points(self.boundingBox.topleft, self.boundingBox.bottomleft) else: # suggest no movement if we aren't going anywhere return moveTo, minDistance tileSegStart = (tileSeg.start.x, min(self.boundingBox.top, previousBB.top)) tileSegEnd = (tileSeg.end.x, max(self.boundingBox.bottom, previousBB.bottom)) tileSeg = LineSegment.from_points(tileSegStart, tileSegEnd) bbSeg = LineSegment.from_points(prevSide.mid, curSide.mid) intersect, point = bbSeg.intersects(tileSeg) if (intersect): if (bbSeg.start == point): distance = 0 moveTo = point[0] else: distance = LineSegment.from_points(bbSeg.start, point).length if distance == 0: for t in tiles: # if the point is inside the borders of the segment, set up the move # this is < to prioritize horizontal checks slightly below vertical checks to prevent "catching" on some corners if (t.boundingBox.top > previousBB.top and t.boundingBox.top < t.boundingBox.bottom) or (t.boundingBox.bottom > previousBB.top and t.boundingBox.bottom < previousBB.bottom): minDistance = distance moveTo = point[0] break #otherwise we don't move minDistance = -1 moveTo = self.Position[0] else: minDistance = distance moveTo = point[0] if (moveTo != self.Position[0]): if(xVel > 0): # going right, add our width moveTo -= self.Width + 1 elif (xVel < 0): # going left, a little bump over moveTo += 1 return moveTo, minDistance
def __calc_y_collision_adjustment__(self, tiles, previousBB): """ Suggests a new Y coordinate for the Actor's bounding box outside of the given colliding tiles. Checks tiles above and below the Actor and finds the closest Y coordinate that clears the bounding tiles. Coordinates are always adjusted in the direction of the Actor's previous position. @type tiles: C{list} @param tiles: L{GameTile<Map.GameTile.GameTile>}s colliding with either the top or bottom side of the Actor's bounding box. @type previousBB: C{U{pygame.Rect<http://www.pygame.org/docs/ref/rect.html>}} @param previousBB: Bounding box at the previous position. @rtype: C{(int, int)} @return: Suggested new Y position and how close the intersection was to the previous position (-1 means no intersection occurred). """ moveTo = self.Position[1] minDistance = -1 if not tiles: return moveTo, minDistance yVel = self.Velocity.y # a tile tile = tiles[0] # amount to move the boundary to avoid a false negative intersection bumpAmount = 0.0001 # get the tile segment above or below if (yVel > 0): # going down tileSeg = tile.GetSegment(Constants.TileConstants.SIDE_TOP) # prepare to create segments from our side at the old position to the side at the new position prevSide = LineSegment.from_points(previousBB.bottomleft, previousBB.bottomright) if self.boundingBox.bottom == tileSeg.start.y: curSide = LineSegment.from_points((self.boundingBox.left, self.boundingBox.bottom + bumpAmount), (self.boundingBox.right, self.boundingBox.bottom + bumpAmount)) else: curSide = LineSegment.from_points(self.boundingBox.bottomleft, self.boundingBox.bottomright) elif (yVel < 0): # going up tileSeg = tile.GetSegment(Constants.TileConstants.SIDE_BOTTOM) # prepare to create segments from our side at the old position to the side at the new position prevSide = LineSegment.from_points(previousBB.topleft, previousBB.topright) if self.boundingBox.top == tileSeg.start.y: curSide = LineSegment.from_points((self.boundingBox.left, self.boundingBox.top - bumpAmount), (self.boundingBox.right, self.boundingBox.top - bumpAmount)) else: curSide = LineSegment.from_points(self.boundingBox.topleft, self.boundingBox.topright) else: # suggest no movement if we aren't going anywhere return moveTo, minDistance tileSegStart = (min(self.boundingBox.left, previousBB.left), tileSeg.start.y) tileSegEnd = (max(self.boundingBox.right, previousBB.right), tileSeg.end.y) tileSeg = LineSegment.from_points(tileSegStart, tileSegEnd) bbSeg = LineSegment.from_points(prevSide.mid, curSide.mid) intersect, point = bbSeg.intersects(tileSeg) if (intersect): if (bbSeg.start == point): distance = 0 moveTo = point[1] else: distance = LineSegment.from_points(bbSeg.start, point).length if distance == 0: for t in tiles: # if the point is inside the borders of the segment, set up the move # this is <= to prioritize vertical checks slightly over horizontal checks to prevent "catching" on some corners if (t.boundingBox.left >= previousBB.left and t.boundingBox.left <= t.boundingBox.right) or (t.boundingBox.right >= previousBB.left and t.boundingBox.right <= previousBB.right): minDistance = distance moveTo = point[1] break # otherwise it's -1 and we don't move minDistance = -1 moveTo = self.Position[1] else: minDistance = distance moveTo = point[1] if (moveTo != self.Position[1] and self.Velocity.y > 0): # going down, add our height moveTo -= self.Height + 1 return moveTo, minDistance