From 65537104872241bb4f1732bb19dcb78d5017d03d Mon Sep 17 00:00:00 2001 From: Neil Date: Thu, 3 Mar 2016 23:37:16 +0200 Subject: [PATCH] Move various bits into gamelib --- koperkapel/gamelib/__init__.py | 0 koperkapel/gamelib/level.py | 23 +++++ koperkapel/gamelib/tiles.py | 119 ++++++++++++++++++++++++ koperkapel/loaders/levelloader.py | 144 +++--------------------------- koperkapel/scenes/level.py | 6 +- 5 files changed, 159 insertions(+), 133 deletions(-) create mode 100644 koperkapel/gamelib/__init__.py create mode 100644 koperkapel/gamelib/level.py create mode 100644 koperkapel/gamelib/tiles.py diff --git a/koperkapel/gamelib/__init__.py b/koperkapel/gamelib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/koperkapel/gamelib/level.py b/koperkapel/gamelib/level.py new file mode 100644 index 0000000..dd89f7e --- /dev/null +++ b/koperkapel/gamelib/level.py @@ -0,0 +1,23 @@ +""" Class holding the level info """ + + +class Level(object): + + def __init__(self): + self.width = self.height = 0 + self.tiles = [] + self.tileset = None + + def get_neighbors(self, x, y): + # 4 -connected neighbors + return [self.tiles[y][x-1] if x > 0 else None, + self.tiles[y][x+1] if x < self.width - 1 else None, + self.tiles[y-1][x] if y > 0 else None, + self.tiles[y+1][x] if y < self.height- 1 else None, + ] + + def can_walk(self, x, y, layer): + return 'walk' in self.tiles[y][x][layer]['behaviour'] + + def can_fly(self, x, y, layer): + return 'fly' in self.tiles[y][x][layer]['behaviour'] diff --git a/koperkapel/gamelib/tiles.py b/koperkapel/gamelib/tiles.py new file mode 100644 index 0000000..382a2ea --- /dev/null +++ b/koperkapel/gamelib/tiles.py @@ -0,0 +1,119 @@ +""" Definitions for the various tile types """ + +import os +import random + +from pygame.transform import rotate + +from pgzero.loaders import images + + +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(Tile): + 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 = True + + @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) + diff --git a/koperkapel/loaders/levelloader.py b/koperkapel/loaders/levelloader.py index a4b5b6f..3b22565 100644 --- a/koperkapel/loaders/levelloader.py +++ b/koperkapel/loaders/levelloader.py @@ -1,121 +1,12 @@ """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 +from pgzero.loaders import ResourceLoader -class Tile: - IMG = None - TILESET = None +from ..gamelib.tiles import Wall, Floor, Tunnel, Underground +from ..gamelib.level import Level - @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(Tile): - 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 = True - - @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 = { @@ -135,33 +26,26 @@ class LevelLoader(ResourceLoader): f = open(level_path, 'r') level_data = json.load(f) f.close() - self._height = len(level_data['tiles']) - self._width = len(level_data['tiles'][0]) - self._tiles = level_data['tiles'] - self._tileset = level_data['tileset'] + self._level = Level() + self._level.height = len(level_data['tiles']) + self._level.width = len(level_data['tiles'][0]) + self._level.tiles = level_data['tiles'] + self._level.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: + for row, row_data in enumerate(self._level.tiles): + if len(row_data) != self._level.width: raise RuntimeError("Incorrect len for row %d" % row) for tile in TILES.values(): - tile.TILESET = self._tileset + tile.TILESET = self._level.tileset self._load_tile_images() - return level_data + return self._level def _load_tile_images(self): """Load all the tile images""" - height = len(self._tiles) - width = len(self._tiles[0]) - for y, row_data in enumerate(self._tiles): + for y, row_data in enumerate(self._level.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, - ] + neighborhood = self._level.get_neighbors(x, y) for layer in ['floor', 'tunnels']: neighbors = [x[layer] if x else None for x in neighborhood] tile['%s image' % layer] = \ diff --git a/koperkapel/scenes/level.py b/koperkapel/scenes/level.py index 9a8fdc3..82fff65 100644 --- a/koperkapel/scenes/level.py +++ b/koperkapel/scenes/level.py @@ -12,8 +12,8 @@ class BaseLevelScene(Scene): """ Level scene. """ def enter(self, world): - self._level_data = levels.load(world.level.name) - self._tiles = self._level_data['tiles'] + self._level = levels.load(world.level.name) + self._tiles = self._level.tiles self._level_layer = 'floor' self._surfaces = {} self._overlay = {} @@ -47,7 +47,7 @@ class BaseLevelScene(Scene): if self._level_layer != 'floor': screen.surface.blit(self._overlay, (0, 0), area=(viewport[0], viewport[1], WIDTH, HEIGHT), - special_flags=pgl.BLEND_ADD) + special_flags=pgl.BLEND_MULT) def on_key_down(self, key, mod, unicode): if key == keys.ESCAPE: -- 2.34.1