Advertisement
xgeovanni

Grid Library for Pygame.

Dec 8th, 2012
375
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.32 KB | None | 0 0
  1. # Grid library for Pygame by Bobby Clarke
  2. # GNU General Public License 3.0
  3.  
  4. # Version 1.1
  5.  
  6. import pygame
  7. import math
  8. from fractions import gcd
  9. from functools import reduce
  10.  
  11. def _isEven(i):
  12.     return i % 2 == 0
  13.  
  14. def product(_list):
  15.     return reduce(lambda x, y: x * y, _list, 1)
  16.  
  17. def _range(start, stop, step=1):
  18.     """Range function which can handle floats."""
  19.     while start < stop:
  20.         yield start
  21.         start += step
  22.        
  23. def _simplify(a, b):
  24.     hcf = gcd(a, b)
  25.     return (a / hcf, b / hcf)
  26.  
  27. class Tile(pygame.Rect):
  28.     def __init__(self, point, size, colour = None, imgs = [], tags = []):
  29.         self.size = [int(i) for i in size]
  30.         self.point = point
  31.         self.colour = colour
  32.  
  33.         for img in imgs:
  34.             if isinstance(img, tuple):
  35.                 imgs[imgs.index(img)] = pygame.image.fromstring(img[0],
  36.                                                                 img[1],
  37.                                                                 img[2])
  38.         self.imgs = imgs[:]
  39.         self.tags = tags[:]
  40.  
  41.         pygame.Rect.__init__(self, self.point, self.size)
  42.  
  43.     def __lt__(self, other):
  44.         return (self.point[0] < other.point[0] or
  45.                 self.point[1] < other.point[1])
  46.     def __gt__(self, other):
  47.         return (self.point[0] > other.point[0] or
  48.                 self.point[1] > other.point[1])
  49.     def __le__(self, other):
  50.         return (self.point[0] <= other.point[0] or
  51.                 self.point[1] <= other.point[1])
  52.     def __ge__(self, other):
  53.         return (self.point[0] >= other.point[0] or
  54.                 self.point[1] >= other.point[1])
  55.  
  56.     def toData(self, imgFormat = "RGBA"):
  57.         return (self.point, self.size, self.colour,
  58.                [(pygame.image.tostring(img, imgFormat),
  59.                  img.get_size(), imgFormat) for img in self.imgs], self.tags)
  60.  
  61.     def fromData(data, baseTile = None):
  62.         tile = Tile(*data)
  63.  
  64.         if baseTile and isinstance(baseTile, Tile):
  65.             baseTile = tile
  66.         else:
  67.             return tile
  68.  
  69.     def getRect(self):
  70.         return self
  71.     def getColour(self):
  72.         return self.colour
  73.     def setColour(self, colour):
  74.         self.colour = colour
  75.     def getPoint(self):
  76.         return self.point
  77.     def addTag(self, *tags):
  78.         if isinstance(tags[0], list):
  79.             self.tags.extend(tags[0])
  80.         else:
  81.             self.tags.extend(tags)
  82.     def hasTag(self, tag):
  83.         return (tag in self.tags)
  84.     def delTag(self, tag):
  85.         self.tags.remove(tag)
  86.     def clearTags(self):
  87.         self.tags = []
  88.     def addImg(self, img, resize = False):
  89.         if isinstance(img, pygame.Surface):
  90.             if img.get_rect() != self and resize:
  91.                 img = pygame.transform.scale(img, (self.size))
  92.             self.imgs.append(img)
  93.         elif img is not None:
  94.             raise TypeError("Images must be pygame.Surface object")
  95.     def delImg(self, img):
  96.         self.imgs.remove(img)
  97.     def clearImgs(self):
  98.         self.imgs = []
  99.  
  100.     def isClicked(self):
  101.         return self.collidepoint(pygame.mouse.get_pos())
  102.        
  103.     def draw(self, surface):
  104.         if self.colour is not None:
  105.             surface.fill(self.colour, self)
  106.         for img in self.imgs:
  107.             surface.blit(img, self)
  108.  
  109. class Grid():
  110.     def __init__(self, surface, num, colour = None, tiles = None,
  111.                  force_square = False):
  112.         self.WIDTH = surface.get_width()
  113.         self.HEIGHT = surface.get_height()
  114.         self.surface = surface
  115.  
  116.         aspect_ratio = _simplify(self.WIDTH, self.HEIGHT)
  117.  
  118.         if isinstance(num, int):
  119.             if aspect_ratio == (1, 1) or force_square:
  120.                 self.x = math.sqrt(num)
  121.                 self.y = math.sqrt(num)
  122.            
  123.             else:            
  124.                 self.x = aspect_ratio[0] * (num / product(aspect_ratio))
  125.                 self.y = aspect_ratio[1] * (num / product(aspect_ratio))
  126.         else:
  127.             try:
  128.                 self.x = num[0]
  129.                 self.y = num[1]
  130.             except TypeError:
  131.                 raise TypeError("2nd argument must be int or subscriptable")
  132.        
  133.         self.tilesize = (self.WIDTH / self.x,
  134.                          self.HEIGHT / self.y)
  135.         self.num = num
  136.         self.colour = colour
  137.  
  138.         if tiles:
  139.             if hasattr(tiles, "__getitem__") and isinstance(tiles[0], Tile):
  140.                 self.tiles = tiles
  141.             else:
  142.                 self.tiles = [[Tile.fromData(tile) for tile in column]
  143.                               for column in tiles]
  144.         else:
  145.             self.tiles = self.maketiles(colour)
  146.  
  147.     def __getitem__(self, index):
  148.         return self.tiles[index]
  149.  
  150.     def __setitem__(self, index, new):
  151.         self.tiles[index] = new
  152.  
  153.     def __len__(self):
  154.         return len(self.tiles)
  155.    
  156.     def index(self, tile):
  157.         for column in self.tiles:
  158.             if tile in column:
  159.                 return self.tiles.index(column), column.index(tile)
  160.  
  161.     def getTiles(self):
  162.         """Get all tiles. Returns a generator"""
  163.         for column in self.tiles:
  164.             for tile in column:
  165.                 yield tile
  166.  
  167.     def tagSearch(self, tag):
  168.         """Search for tiles by tag. Returns a generator"""
  169.        
  170.         for tile in self.getTiles():
  171.             if tile.hasTag(tag):
  172.                 yield tile
  173.  
  174.     def pointSearch(self, point):
  175.         """Search for tiles by point. Returns a tile"""
  176.        
  177.         for tile in self.getTiles():
  178.             if tile.collidepoint(point):
  179.                 return tile
  180.            
  181.     def rectSearch(self, rect):
  182.         """Search for tiles by rect. Returns a generator"""
  183.        
  184.         for tile in self.getTiles():
  185.             if tile.colliderect(rect):
  186.                 yield tile
  187.                
  188.     def getColumn(self, i):
  189.         return self.tiles[i]
  190.     def getRow(self, i):
  191.         return [column[i] for column in self.tiles]
  192.            
  193.     def checker(self, colour1, colour2 = None):
  194.         for column in self.tiles:
  195.             for tile in column:
  196.                 if _isEven(self.tiles.index(column) + column.index(tile)):
  197.                     tile.setColour(colour1)
  198.                 else:
  199.                     if colour2:
  200.                         tile.setColour(colour2)
  201.                        
  202.     def getDiagonal(self, tile, direction = 1):
  203.         index = self.index(tile)
  204.         diagonal = []
  205.        
  206.         currentIndex = [i - index[0] for i in index]
  207.        
  208.         while currentIndex[1] != self.y:
  209.             diagonal.append(self[currentIndex[0]][currentIndex[1]])
  210.            
  211.             currentIndex = [i + 1 for i in currentIndex]
  212.            
  213.         return diagonal
  214.                        
  215.     def getBetweenTiles(self, tile1, tile2):
  216.         """Inefficient and badly implemented"""
  217.        
  218.         index1 = self.index(tile1)
  219.         index2 = self.index(tile2)
  220.        
  221.         if index1[0] != index2[0] and index1[1] != index2[1]:
  222.             raise ValueError("Tiles must be in same row or column")
  223.        
  224.         for column in self.tiles:
  225.             if tile1 in column and tile2 in column:
  226.                 return column[column.index(tile1) : column.index(tile2)]
  227.            
  228.         for i in range(self.y):
  229.             row = self.getRow(i)
  230.             if tile1 in row and tile2 in row:
  231.                     return row[row.index(tile1) : row.index(tile2)]
  232.  
  233.     def getSurroundingTiles(self, tile,  adjacent = True, diagonal = True):    
  234.         di = (0, 1, 0, -1, 1, 1, -1, -1)
  235.         dj = (1, 0, -1, 0, 1, -1, 1, -1)
  236.         # indices 0 - 3 are for horizontal, 4 - 7 are for vertical
  237.        
  238.         index = list(self.getTiles()).index(tile)
  239.         max_x = self.x - 1 # Offset for 0 indexing
  240.         max_y = self.y - 1
  241.  
  242.         i = int(math.floor(index / self.x))
  243.         j = int(index % self.y)
  244.  
  245.         surroundingTiles = []
  246.  
  247.         startat = 0 if adjacent else 4
  248.         stopat = 8 if diagonal else 4
  249.  
  250.         for k in range(startat, stopat):
  251.             ni = i + di[k]
  252.             nj = j + dj[k]
  253.             if ni >= 0 and nj >= 0 and ni <= max_x and nj <= max_y:
  254.                 surroundingTiles.append(self[ni][nj])
  255.  
  256.         surroundingTiles.reverse()
  257.  
  258.         return sorted(surroundingTiles)
  259.  
  260.     def draw(self, drawGrid = False, gridColour = (0, 0, 0), gridSize = 1):
  261.         for tile in self.getTiles():
  262.             tile.draw(self.surface)
  263.            
  264.             if drawGrid:
  265.                 pygame.draw.rect(self.surface, gridColour, tile, gridSize)
  266.                
  267.     def maketiles(self, colour):
  268.         """Make the tiles for the grid"""
  269.        
  270.         tiles = []
  271.        
  272.         width = self.WIDTH / self.x
  273.         height = self.HEIGHT / self.y
  274.        
  275.         for i in _range(0, self.WIDTH, width):
  276.             column = []
  277.            
  278.             for j in _range(0, self.HEIGHT, height):
  279.                 sq = Tile((i, j), (width, height), colour)
  280.                
  281.                 column.append(sq)
  282.                              
  283.             tiles.append(column)
  284.            
  285.         return tiles
  286.  
  287.     def toData(self):
  288.         return (self.num, self.colour,
  289.                 [[tile.toData() for tile in column] for column in self.tiles])
  290.  
  291.     def fromData(data, surface):
  292.         return Grid(*([surface] + list(data)))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement