Пример #1
0
 def computeGridMap(self):
     """Fill the grid_map attribute with a GridMap instance, to be used in pathfinding
     Call this method after init the level the first time and also when something is changed
     """
     tile_size_x, tile_size_y = cblocals.PATHFINDING_GRID_SIZE
     w,h = self.levelSize
     self.grid_map = GridMap(w/tile_size_x, h/tile_size_y)
     collideGroups = (self['physical'],)
     for group in collideGroups:
         for sprite in group.sprites():
             self.grid_map.set_blocked_multi(sprite.collide_grid)
Пример #2
0
class GridMapSupport(object):
    """An object that behave all method for support the usage of a GridMap object and pathfinding features"""

    def __init__(self):
        self.grip_map = None

    def computeGridMap(self):
        """Fill the grid_map attribute with a GridMap instance, to be used in pathfinding
        Call this method after init the level the first time and also when something is changed
        """
        tile_size_x, tile_size_y = cblocals.PATHFINDING_GRID_SIZE
        w,h = self.levelSize
        self.grid_map = GridMap(w/tile_size_x, h/tile_size_y)
        collideGroups = (self['physical'],)
        for group in collideGroups:
            for sprite in group.sprites():
                self.grid_map.set_blocked_multi(sprite.collide_grid)

    def toGridCoord(self, coord):
        """Transforms a level coordinate to a grid point"""
        tile_size_x, tile_size_y = cblocals.PATHFINDING_GRID_SIZE
        x, y = coord
        x/= tile_size_x; y/=tile_size_y
        return int(x),int(y)

    def fromGridCoord(self, coord):
        """Transforms a grid coordinate to a level absolute ones"""
        tile_size_x, tile_size_y = cblocals.PATHFINDING_GRID_SIZE
        x, y = coord
        return int(x*tile_size_x+tile_size_x/2), int(y*tile_size_y+tile_size_y/2)

    def drawGridMapSquares(self, surface):
        """Draw on a surface the gridmap areas, for debug purposes"""
        gw, gh = cblocals.PATHFINDING_GRID_SIZE
        w,h = self.levelSize
        transformToScreenCoordinate = self.transformToScreenCoordinate
        for x in range(0,w,gw):
            pygame.draw.line(surface, (255,255,255), transformToScreenCoordinate((x,0)), transformToScreenCoordinate((x,h)), 1)
        for y in range(0,h,gh):
            pygame.draw.line(surface, (255,255,255), transformToScreenCoordinate((0,y)), transformToScreenCoordinate((w,y)), 1)

    def isPointOnFreeSlot(self, point):
        """Check if a given point is placed on a free slot.
        This can be different from GameLevel.checkPointIsFree, beacuse a point can be free (don't collide with anything) but placed
        on a occupied slot.
        """
        grid_point = self.toGridCoord(point)
        try:
            return not self.grid_map.isBlocked(grid_point)
        except IndexError:
            return False

    def getFreeNearSlot(self, point):
        """This method check for a free slot near the point passed. The free slot can be the point itself (if it's free).
        @return: The free slot coord, or None if no free slot is found.
        """
        grid_map = self.grid_map
        try:
            if not grid_map.isBlocked(point):
                return point
        except IndexError:
            blocked = True
        px, py = point
        for y,x in ( (-1,0), (0,1), (1,0), (0,-1),):
            try:
                blocked = grid_map.isBlocked( (px+x,py+y) )
            except IndexError:
                blocked = True
            if not blocked:
                return (px+x, py+y)
        return None

    # ******* methods needed to init a PathFinder object *******
    def grid_map_successors(self, point):
        """Given a point get all possible successors where you can freely move into from the given point.
        Freepoint are all non blocked point near the point itself.
        Also no diagonal movement is possible if one of the two near non-diagolan point is blocked.
        @return: a list of successors, free points
        """
        successors = []
        grid_map = self.grid_map
        px, py = point
        
        # linear near points
        for y,x in ( (-1,0), (0,1), (1,0), (0,-1),):
            try:
                blocked = grid_map.isBlocked( (px+x,py+y) )
            except IndexError:
                blocked = True
            if not blocked:
                successors.append( (px+x,py+y) )
        # diagonal movements
        for y,x in ( (-1,-1), (-1,1), (1,1), (1,-1),):
            try:
                blocked = grid_map.isBlocked( (px+x,py+y) )
            except IndexError:
                blocked = True
            if not blocked:
                # must check near non-diag points also
                if (0,x) in successors and (y,0) in successors:
                    successors.append( (px+x,py+y) )
        return successors

    def grid_map_move_cost(self, point_a, point_b):
        """Get the numeric cost of moving from the first point to the second.

        Euclidean distance is:
        h(n) = D * sqrt((n.x-goal.x)^2 + (n.y-goal.y)^2)
        
        Diagonal distance (if diagonal movements cost like straight ones) is:
        h(n) = D * max(abs(n.x-goal.x), abs(n.y-goal.y))
        
        Diagonal distance (if diagonal movements cost more than straight ones) is:        
        h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
        h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
        h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
        """
        d = 1
        d2 = 1.25
        ax,ay = point_a
        bx,by = point_b
        h_diagonal = min(abs(ax-bx), abs(ay-by))
        h_straight = (abs(ax-bx) + abs(ay-by))
        return d2 * h_diagonal + d * (h_straight - 2*h_diagonal)

    def grid_map_heuristic_to_goal(self, point, goal):
        """Given a point and a goal point,
        obtains the numeric heuristic estimation of 
        the cost of reaching the goal from the point.
        """
        return self.grid_map_move_cost(point, goal)