X-Git-Url: https://git.ctpug.org.za/?a=blobdiff_plain;f=koperkapel%2Floaders%2Flevelloader.py;h=8e47b5c150a31e6a7a8221fe7c2187436deb8325;hb=ed3e525ba11d3383fdf0041e26286c72f342e91a;hp=124161f37d12fe93dd9681471bf140cced3a3ef5;hpb=bc78ad7ce0a69ad00b10cf29a86d7596c1f90139;p=koperkapel.git diff --git a/koperkapel/loaders/levelloader.py b/koperkapel/loaders/levelloader.py index 124161f..8e47b5c 100644 --- a/koperkapel/loaders/levelloader.py +++ b/koperkapel/loaders/levelloader.py @@ -1,9 +1,131 @@ """Loader a level, using the pygame-zero ResourceLoader infrastructure""" +import os import json from pgzero.loaders import images, ResourceLoader +import os +import random +from pygame.transform import rotate +class Tile: + IMG = None + TILESET = None + + @classmethod + def image(cls, neighbors): + if cls.IMG is None or cls.TILESET is None: + raise NotImplementedError() + return images.load(os.path.join(cls.TILESET, cls.IMG)) + +class OrientatedTile: + IMG = None + TILESET = None + ANGLE = None + + @classmethod + def image(cls, neighbors): + if cls.IMG is None or cls.TILESET is None: + raise NotImplementedError() + img = images.load(os.path.join(cls.TILESET, cls.IMG)) + if cls.ANGLE: + img = rotate(img, cls.ANGLE) + return img + + +class RandomizedTile(Tile): + IMGDIR = None + TILESET = None + ROTATE = None + + @classmethod + def image(cls, neighbors): + if cls.IMGDIR is None or cls.TILESET is None: + raise NotImplementedError() + + imgdir = os.path.join(os.path.dirname(__file__), '..', 'images', + cls.TILESET, cls.IMGDIR) + imgpath = os.path.splitext(random.choice(os.listdir(imgdir)))[0] + img = images.load(os.path.join(cls.TILESET, cls.IMGDIR, imgpath)) + + if cls.ROTATE: + img = rotate(img, 90 * random.randint(0, 3)) + + return img + +class Floor(RandomizedTile): + IMGDIR = "floor" + +class Wall(RandomizedTile): + IMGDIR = "wall" + +class Underground(RandomizedTile): + IMGDIR = "underground" + +class Tunnel(OrientatedTile): + + @classmethod + def image(cls, neighbors): + connections = [True if 'walk' in x['behaviour'] else False for x in neighbors] + conn_count = connections.count(True) + # simple cases + cls.ANGLE = 0 + if conn_count == 0: + # return single point tunnel + cls.IMG = os.path.join('tunnel', 'tunnel_none') + elif conn_count == 4: + # crossroads + cls.IMG = os.path.join('tunnel', 'tunnel_crossroads') + elif conn_count == 1: + # 1 point connector, roatated correctly + cls.IMG = os.path.join('tunnel', 'tunnel_1way') + # because of the ordering of neighbors, we use this formulation + for x, angle in zip(connections, (90, 270, 0, 180)): + if x: + cls.ANGLE = angle + break + elif conn_count == 3: + # 3 point connector, rotated correctly + cls.IMG = os.path.join('tunnel', 'tunnel_3way') + # find the missing connection. + for x, angle in zip(connections, (0, 180, 270, 90)): + if not x: + cls.ANGLE = angle + break + elif conn_count == 2: + # Need to distinguish pass-through or corner, and + # rotate correctly + # neighbors is left, right then up, down + if connections[0] == connections[1]: + cls.IMG = os.path.join('tunnel', 'tunnel_passthrough') + if connections[0]: + cls.ANGLE = 90 + else: + cls.IMG = os.path.join('tunnel', 'tunnel_corner') + if connections[0]: + if connections[2]: + # left, up + cls.ANGLE = 90 + else: + # left, down + cls.ANGLE = 180 + else: + if connections[2]: + # right, up + cls.ANGLE = 0 + else: + # right, down + cls.ANGLE = 270 + + return super(Tunnel, cls).image(neighbors) + + +TILES = { + "cwall": Wall, # rename this everywhere + "floor": Floor, + "tunnel": Tunnel, + "underground": Underground, +} class LevelLoader(ResourceLoader): """ Level loader. """ @@ -18,19 +140,34 @@ class LevelLoader(ResourceLoader): self._height = len(level_data['tiles']) self._width = len(level_data['tiles'][0]) self._tiles = level_data['tiles'] + self._tileset = level_data['tileset'] # Consistency check, so we can assume things are correct # in the level renderer for row, row_data in enumerate(self._tiles): if len(row_data) != self._width: raise RuntimeError("Incorrect len for row %d" % row) + for tile in TILES.values(): + tile.TILESET = self._tileset self._load_tile_images() return level_data def _load_tile_images(self): """Load all the tile images""" - for row_data in self._tiles: - for tile in row_data: - tile['image'] = images.load(tile['base']) + height = len(self._tiles) + width = len(self._tiles[0]) + for y, row_data in enumerate(self._tiles): + for x, tile in enumerate(row_data): + # simplist case + # 4 -connected neighbors + neighborhood = [self._tiles[y][x-1] if x > 0 else None, + self._tiles[y][x+1] if x < width - 1 else None, + self._tiles[y-1][x] if y > 0 else None, + self._tiles[y+1][x] if y < height- 1 else None, + ] + for layer in ['floor', 'tunnels']: + neighbors = [x[layer] if x else None for x in neighborhood] + tile['%s image' % layer] = \ + TILES[tile[layer]['base']].image(neighbors) levels = LevelLoader('levels')