Ejemplo n.º 1
0
 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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
 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