diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index 1bae98e..a291911 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -3,12 +3,16 @@ config.py Holds all constants used for setting up the game. May later hold functions for loading/saving configuration files. """ + import os +from enum import Enum + BASE_PATH = os.path.dirname(os.path.abspath(__file__)) RESOURCES = os.path.join(BASE_PATH, "resources") IMAGES = os.path.join(RESOURCES, "images") + class Config(object): """ A simple class dedicated to loading, storing and organizing constants. @@ -20,29 +24,50 @@ class Config(object): SCREEN_TITLE = "Triple Dungeon" TILE_WIDTH = 63 IDLE_UPDATES_PER_FRAME = 20 - RUN_UPDATES_PER_FRAME = 10 + RUN_UPDATES_PER_FRAME = 8 # Constants used to scale our sprites from their original size CHARACTER_SCALING = 1 TILE_SCALING = 2 + # The number of pixels across the level + LEVEL_SIZE = 10 * TILE_SCALING * TILE_WIDTH + # Movement speed of player, in pixels per frame PLAYER_MOVEMENT_SPEED = 7 - # How many pixels to keep as a minimum margin between the character and the edge of the screen. + # How many pixels to keep as a minimum margin between the characters and the edge of the screen. LEFT_VIEWPORT_MARGIN = 250 RIGHT_VIEWPORT_MARGIN = 250 BOTTOM_VIEWPORT_MARGIN = 50 TOP_VIEWPORT_MARGIN = 100 -class Sprites(object): +class Enums(Enum): + """ + A simple class used for tracking different simple + """ + + # Play Direction Enums + RIGHT = 0 + LEFT = 1 + UP = 2 + DOWN = 3 + IDLE = 4 + + +class SpritePaths(object): """ Simple class for holding sprite paths. """ + __CHARACTERS = os.path.join(IMAGES, "characters") __MONSTERS = os.path.join(IMAGES, "monsters") + # Single frame sprites SKELETON = os.path.join(__MONSTERS, "skeleton.png") GHOST = os.path.join(__MONSTERS, "ghost", "ghost1.png") FROG = os.path.join(__MONSTERS, "frog", "frog1.png") + + # Animated sprites + KNIGHT = os.path.join(__CHARACTERS, "knight") diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index f25021f..48bc7af 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -3,12 +3,13 @@ main.py The main class used to load the game. Holds the main game window, as well as manages basic functions for organizing the game. """ +import random import arcade +from config import Config from map import Dungeon -from mobs import Player, Enemy -from config import Config, Sprites +from mobs import Player class Game(arcade.Window): @@ -25,53 +26,44 @@ class Game(arcade.Window): self.wall_list = None self.floor_list = None self.enemy_list = None - self.player_list = None - - # Separate variable that holds the player sprite self.player = None + self.dungeon = None + # list to keep track of keypresses - self.prev_keypress = [] + self.prev_keypress = [] # Our physics engine self.physics_engine = None - + # Used to keep track of our scrolling self.view_bottom = 0 self.view_left = 0 - arcade.set_background_color(arcade.csscolor.BLACK) + arcade.set_background_color(arcade.color.BLACK) def setup(self): """ Set up the game here. Call this function to restart the game. """ # Create the Sprite lists - self.player_list = arcade.SpriteList() - self.wall_list = arcade.SpriteList() - self.floor_list = arcade.SpriteList() self.enemy_list = arcade.SpriteList() - # Set up the player, specifically placing it at these coordinates. + # Set up the player, specifically placing it at these coordinates. self.player = Player() self.player.scale = 1 - self.player.center_x = Config.SCREEN_WIDTH / 2 - self.player.center_y = Config.SCREEN_HEIGHT / 2 - self.player_list = self.player - # Create the dungeon - dungeon = Dungeon() - - self.floor_list = dungeon.floor_list - self.wall_list = dungeon.wall_list - + self.dungeon = Dungeon(0, 3) + + self.player.center_x, self.player.center_y = random.choice(self.dungeon.levelList).center() + # Create monsters # This needs to be updated to comply with the new mobs.py code - #self.enemy_list.append(Enemy("resources/images/monsters/ghost/ghost1.png", 200, 200, 4).get_enemy()) - #self.enemy_list.append(Enemy("resources/images/monsters/frog/frog1.png", 200, 1000, 4).get_enemy()) + # self.enemy_list.append(Enemy("resources/images/monsters/ghost/ghost1.png", 200, 200, 4)) + # self.enemy_list.append(Enemy("resources/images/monsters/frog/frog1.png", 200, 1000, 4)) # Create the 'physics engine' - self.physics_engine = arcade.PhysicsEngineSimple(self.player, self.wall_list) + self.physics_engine = arcade.PhysicsEngineSimple(self.player, self.dungeon.getWalls()) def on_draw(self): """ Render the screen. """ @@ -80,43 +72,46 @@ class Game(arcade.Window): arcade.start_render() # Draw our sprites - self.floor_list.draw() - self.player_list.draw() + self.dungeon.render() + self.player.draw() self.enemy_list.draw() self.wall_list.draw() + x, y = self.player.center_x, self.player.center_y + 100 + arcade.draw_text(f"({x}, {y})", x, y, arcade.color.WHITE, 15) + def on_key_press(self, key, modifiers): """Called whenever a key is pressed. """ if key == arcade.key.UP or key == arcade.key.W: - self.player_list.change_y = Config.PLAYER_MOVEMENT_SPEED + self.player.change_y = Config.PLAYER_MOVEMENT_SPEED self.prev_keypress.append(key) elif key == arcade.key.DOWN or key == arcade.key.S: - self.player_list.change_y = -Config.PLAYER_MOVEMENT_SPEED + self.player.change_y = -Config.PLAYER_MOVEMENT_SPEED self.prev_keypress.append(key) elif key == arcade.key.LEFT or key == arcade.key.A: - self.player_list.change_x = -Config.PLAYER_MOVEMENT_SPEED + self.player.change_x = -Config.PLAYER_MOVEMENT_SPEED self.prev_keypress.append(key) elif key == arcade.key.RIGHT or key == arcade.key.D: - self.player_list.change_x = Config.PLAYER_MOVEMENT_SPEED + self.player.change_x = Config.PLAYER_MOVEMENT_SPEED self.prev_keypress.append(key) elif key == 65307: - self.close() + self.close() def on_key_release(self, key, modifiers): """Called when the user releases a key. """ if key == arcade.key.UP or key == arcade.key.W: - self.player_list.change_y = 0 + self.player.change_y = 0 self.prev_keypress.remove(key) elif key == arcade.key.DOWN or key == arcade.key.S: - self.player_list.change_y = 0 + self.player.change_y = 0 self.prev_keypress.remove(key) elif key == arcade.key.LEFT or key == arcade.key.A: - self.player_list.change_x = 0 + self.player.change_x = 0 self.prev_keypress.remove(key) elif key == arcade.key.RIGHT or key == arcade.key.D: - self.player_list.change_x = 0 + self.player.change_x = 0 self.prev_keypress.remove(key) if self.prev_keypress: self.on_key_press(self.prev_keypress.pop(0), 0) @@ -127,29 +122,29 @@ class Game(arcade.Window): # Move the player with the physics engine self.physics_engine.update() - self.player_list.update_animation() + self.player.update_animation() changed = False # Track if we need to change the viewport # Below manages all scrolling mechanics # Scroll left left_boundary = self.view_left + Config.LEFT_VIEWPORT_MARGIN - if self.player_list.left < left_boundary: - self.view_left -= left_boundary - self.player_list.left + if self.player.left < left_boundary: + self.view_left -= left_boundary - self.player.left changed = True # Scroll right right_boundary = self.view_left + Config.SCREEN_WIDTH - Config.RIGHT_VIEWPORT_MARGIN - if self.player_list.right > right_boundary: - self.view_left += self.player_list.right - right_boundary + if self.player.right > right_boundary: + self.view_left += self.player.right - right_boundary changed = True # Scroll up top_boundary = self.view_bottom + Config.SCREEN_HEIGHT - Config.TOP_VIEWPORT_MARGIN - if self.player_list.top > top_boundary: - self.view_bottom += self.player_list.top - top_boundary + if self.player.top > top_boundary: + self.view_bottom += self.player.top - top_boundary changed = True # Scroll down bottom_boundary = self.view_bottom + Config.BOTTOM_VIEWPORT_MARGIN - if self.player_list.bottom < bottom_boundary: - self.view_bottom -= bottom_boundary - self.player_list.bottom + if self.player.bottom < bottom_boundary: + self.view_bottom -= bottom_boundary - self.player.bottom changed = True if changed: diff --git a/triple-dungeon/map.py b/triple-dungeon/map.py index be81f45..105d0e8 100644 --- a/triple-dungeon/map.py +++ b/triple-dungeon/map.py @@ -5,12 +5,16 @@ Pathfinding will also depend on objects here, and is thus integral to it's funct """ from __future__ import annotations -from config import Config + +import json import arcade -import json import numpy as np +from itertools import chain + +from config import Config + class Dungeon(object): """ @@ -24,44 +28,37 @@ class Dungeon(object): :param level_count: The number of Active Levels that should be stored within the Dungeon. :param size: The diameter of the dungeon. Allows for a total of size^2 slots for levels. """ - # setup + + self.level_count = level_count + self.size = size + self.floor_list = arcade.SpriteList() self.wall_list = arcade.SpriteList() - level_size = 10 * Config.TILE_SCALING * Config.TILE_WIDTH - # get center level + # center = Level.load_file(1, 1, 'resources/levels/map1/center.json') + # side = Level.load_file(2, 1, 'resources/levels/map1/room.json') - center = Level() - center.load_file('resources/levels/map1/center.json') - center.render() - center_floor, center_wall = center.floor_list, center.wall_list - self.floor_list.extend(center_floor) - self.wall_list.extend(center_wall) + center = "resources/levels/map1/center.json" + self.levels = [ + [Level.load_file(x, y, center) for y in range(size)] for x in range(size) + ] - # get a side room - room = Level() - room.load_file('resources/levels/map1/room.json') - room.rotate_level(2) - room.render() - room_floor, room_wall = room.get_lists() - room_floor.move(level_size, 0) - room_wall.move(level_size, 0) - self.floor_list.extend(room_floor) - self.wall_list.extend(room_wall) + def getWalls(self) -> arcade.SpriteList: + """ + Simple one time function for getting all Wall sprites from all Levels. + Used by the physics engine during game startup. - # get a side room - room = Level() - room.load_file('resources/levels/map1/room.json') - room.render() - room_floor, room_wall = room.get_lists() - room_floor.move(-level_size, 0) - room_wall.move(-level_size, 0) - self.floor_list.extend(room_floor) - self.wall_list.extend(room_wall) + :return: A SpriteList containing all Sprites. + """ - def add_level(self, sprit_list): - for x in sprit_list: - self.levels.append(x) + walls = arcade.SpriteList() + walls.extend( + list(chain.from_iterable( + chain.from_iterable([level.wallSprites for level in column if level is not None]) for column in + self.levels + )) + ) + return walls def render(self) -> None: """ @@ -71,7 +68,19 @@ class Dungeon(object): for column in self.levels: for level in column: if level is not None: - level.render() + level.floorSprites.draw() + level.wallSprites.draw() + + @property + def levelList(self) -> list: + """ + Retrieves all Level objects from Dungeon instance. + :return: A list containing all Level objects. + """ + + return list(filter( + lambda level: level is not None, chain.from_iterable(self.levels) + )) class Level: @@ -91,60 +100,70 @@ class Level: self.x, self.y = level_x, level_y self.sprites = [] - self.level = [] + self.structure = [] + + self.floorSprites = arcade.SpriteList() + self.wallSprites = arcade.SpriteList() # Tuples containing the Node positions of where walls, floor and entrances are. # All positions are generated based on the level's X and Y position, so that all points within # the dungeon can be mapped by a proper pathfinding system. self.floor_list = [] self.wall_list = [] - # self.entrances = [] - def load_file(self, path: str): + @staticmethod + def load_file(level_x: int, level_y: int, path: str) -> Level: """ Builds a Level from a given file path. + :param level_x: The level's X position within the Dungeon level matrix. + :param level_y: The level's Y position within the Dungeon level matrix. :param path: Path to the Level file. :return: The new generated Level file. """ - self.floor_list = arcade.SpriteList() - self.wall_list = arcade.SpriteList() + level = Level(level_x, level_y) with open(path) as file: - level = json.load(file) + data = json.load(file) + # Loads elements and structure data from level file + level.sprites = data['elements'] + level.structure = data['structure'] - self.sprites = level['elements'] - self.level = level['structure'] - - def render(self) -> None: + tile_scale = Config.TILE_WIDTH * Config.TILE_SCALING + + # Places all of the tiles & sprites + for x in range(0, 10): + for y in range(0, 10): + tilePath = level.sprites[level.structure[x][y]] + sprite = arcade.Sprite(tilePath, Config.TILE_SCALING) + sprite.center_x, sprite.center_y = x * tile_scale, y * tile_scale + + if 'floor' in tilePath: + level.floorSprites.append(sprite) + elif 'wall' in tilePath: + level.wallSprites.append(sprite) + else: + print(f'Could not handle Tile: {tilePath}') + + # Move everything into correct positions + level.floorSprites.move(*level.center()) + level.wallSprites.move(*level.center()) + + return level + + def center(self) -> tuple: """ - Calls render on all sprites. + Returns the pixel center of the level. + :return: A tuple containing the X and Y coordinates of the level's center """ - x = 0 - y = 0 - level_size = 10 * Config.TILE_SCALING * Config.TILE_WIDTH - - # Create the level - # This shows using a loop to place multiple sprites horizontally and vertically - for y_pos in range(0, level_size , 63 * Config.TILE_SCALING): - for x_pos in range(0, level_size, 63 * Config.TILE_SCALING): - cur_tile = self.level[y][x] - sprite = self.sprites[cur_tile] - floor = arcade.Sprite(sprite, Config.TILE_SCALING) - floor.center_x = x_pos - floor.center_y = y_pos - if cur_tile == ' ': - self.floor_list.append(floor) - elif cur_tile == 'w': - self.wall_list.append(floor) - x += 1 - x = 0 - y += 1 - - def get_lists(self): - return self.floor_list, self.wall_list + return self.x * Config.LEVEL_SIZE, self.y * Config.LEVEL_SIZE def rotate_level(self, times_rotated): + """ + Rotates the + :param times_rotated: + :return: + """ m = np.array(self.level) for i in range(0, times_rotated % 4): m = np.rot90(m) diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 5457745..9b9906b 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -5,19 +5,15 @@ Organizes all classes related to Mobs, Entities, Enemies, Players and Items. import arcade -from config import Config, Sprites +from config import Config, Enums, SpritePaths +from sprites import PlayerAnimations -# Constants used to track if the player is facing left or right -RIGHT_FACING = 0 -LEFT_FACING = 1 -FRONT_FACING = 2 -UP_FACING = 3 -DOWN_FACING = 4 class Mob(arcade.Sprite): """ Represents a Mob. No defined behaviour, it has no intelligence. """ + def __init__(self, max_health=100, max_armor=0, *args, **kwargs) -> None: # Set up parent class super().__init__() @@ -42,70 +38,52 @@ class Player(Mob): Represents a Player. While this is a instance, there should only be one in the world at any given time. """ + def __init__(self, *args, **kwargs) -> None: super(Player, self).__init__(*args, **kwargs) - main_path = "resources/images/character/knight/" + self.animations = PlayerAnimations(SpritePaths.KNIGHT) + # Used for mapping directions to animations + self.map = { + Enums.IDLE: self.animations.idles, + Enums.UP: self.animations.up, + Enums.DOWN: self.animations.down, + Enums.RIGHT: self.animations.right, + Enums.LEFT: self.animations.left + } - # Default to face-front - self.character_face_direction = FRONT_FACING + self.refreshIndex = 0 + self.prev = Enums.IDLE + self.texture = next(self.map[self.prev]) - # Load textures for idle standing - for i in range(4): - texture = arcade.load_texture(f"{main_path}knight iso char_idle_{i}.png") - self.idle_textures.append(texture) + def update_animation(self, delta_time: float = 1 / 60) -> None: + """ + Updates animations for the Player. + :param delta_time: No idea. + """ - # Load textures for running horizontally - for i in range(6): - self.walking_textures.append([arcade.load_texture(f"{main_path}knight iso char_run left_{i}.png"),arcade.load_texture(f"{main_path}knight iso char_run left_{i}.png", mirrored=True)]) - - # Load textures for running down - for i in range(5): - self.down_textures.append(arcade.load_texture(f"{main_path}knight iso char_run down_{i}.png")) + # Increase the refresh index according + self.refreshIndex = (self.refreshIndex + 1) % Config.RUN_UPDATES_PER_FRAME - # Load textures for running up - for i in range(5): - self.up_textures.append(arcade.load_texture(f"{main_path}knight iso char_run up_{i}.png")) - - def update_animation(self, delta_time: float = 1/60): - # Figure out if we need to flip face left, right, up, or down - if self.change_x > 0: - self.character_face_direction = LEFT_FACING - elif self.change_x < 0: - self.character_face_direction = RIGHT_FACING - elif self.change_x == 0 and self.change_y == 0: - self.character_face_direction = FRONT_FACING - - - # idle animation + # Logic to determine what direction we're in. if self.change_x == 0 and self.change_y == 0: - self.cur_texture += 1 - if self.cur_texture > 3 * Config.IDLE_UPDATES_PER_FRAME: - self.cur_texture = 0 - self.texture = self.idle_textures[self.cur_texture // Config.IDLE_UPDATES_PER_FRAME] - return + cur = Enums.IDLE + elif self.change_y > 0: # Up + cur = Enums.UP + elif self.change_y < 0: # Down + cur = Enums.DOWN + elif self.change_x > 0: # Left + cur = Enums.RIGHT + elif self.change_x < 0: # Right + cur = Enums.LEFT + else: # Idle + cur = Enums.IDLE - #walk up animation - if self.change_y > 0: - self.cur_texture += 1 - if self.cur_texture > 4 * Config.RUN_UPDATES_PER_FRAME: - self.cur_texture = 0 - self.texture = self.up_textures[self.cur_texture // Config.RUN_UPDATES_PER_FRAME] - return + # If we're in a new direction or the refresh index has reset + if self.prev is not cur or self.refreshIndex == 0: + self.texture = next(self.map[cur]) - #walk down animation - if self.change_y < 0: - self.cur_texture += 1 - if self.cur_texture > 4 * Config.RUN_UPDATES_PER_FRAME: - self.cur_texture = 0 - self.texture = self.down_textures[self.cur_texture // Config.RUN_UPDATES_PER_FRAME] - return - - # Walking left/right animation - self.cur_texture += 1 - if self.cur_texture > 5 * Config.RUN_UPDATES_PER_FRAME: - self.cur_texture = 0 - self.texture = self.walking_textures[self.cur_texture // Config.RUN_UPDATES_PER_FRAME][self.character_face_direction] + self.prev = cur def tick(self): """ @@ -120,12 +98,10 @@ class Enemy(Mob): Represents an Enemy Mob. Will take basic offensive actions against Player objects. """ + def __init__(self, *args, **kwargs) -> None: super(Enemy, self).__init__(*args, **kwargs) - def get_enemy(self): - return self - def tick(self) -> None: """ A on_update function, the Enemy Mob should scan for the player, decide how to path to it, and diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_idle_0.png b/triple-dungeon/resources/images/characters/knight/idle_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_idle_0.png rename to triple-dungeon/resources/images/characters/knight/idle_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_idle_1.png b/triple-dungeon/resources/images/characters/knight/idle_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_idle_1.png rename to triple-dungeon/resources/images/characters/knight/idle_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_idle_2.png b/triple-dungeon/resources/images/characters/knight/idle_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_idle_2.png rename to triple-dungeon/resources/images/characters/knight/idle_2.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_idle_3.png b/triple-dungeon/resources/images/characters/knight/idle_3.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_idle_3.png rename to triple-dungeon/resources/images/characters/knight/idle_3.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run down_0.png b/triple-dungeon/resources/images/characters/knight/run_down_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run down_0.png rename to triple-dungeon/resources/images/characters/knight/run_down_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run down_1.png b/triple-dungeon/resources/images/characters/knight/run_down_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run down_1.png rename to triple-dungeon/resources/images/characters/knight/run_down_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run down_2.png b/triple-dungeon/resources/images/characters/knight/run_down_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run down_2.png rename to triple-dungeon/resources/images/characters/knight/run_down_2.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run down_3.png b/triple-dungeon/resources/images/characters/knight/run_down_3.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run down_3.png rename to triple-dungeon/resources/images/characters/knight/run_down_3.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run down_4.png b/triple-dungeon/resources/images/characters/knight/run_down_4.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run down_4.png rename to triple-dungeon/resources/images/characters/knight/run_down_4.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run left_0.png b/triple-dungeon/resources/images/characters/knight/run_left_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run left_0.png rename to triple-dungeon/resources/images/characters/knight/run_left_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run left_1.png b/triple-dungeon/resources/images/characters/knight/run_left_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run left_1.png rename to triple-dungeon/resources/images/characters/knight/run_left_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run left_2.png b/triple-dungeon/resources/images/characters/knight/run_left_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run left_2.png rename to triple-dungeon/resources/images/characters/knight/run_left_2.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run left_3.png b/triple-dungeon/resources/images/characters/knight/run_left_3.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run left_3.png rename to triple-dungeon/resources/images/characters/knight/run_left_3.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run left_4.png b/triple-dungeon/resources/images/characters/knight/run_left_4.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run left_4.png rename to triple-dungeon/resources/images/characters/knight/run_left_4.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run left_5.png b/triple-dungeon/resources/images/characters/knight/run_left_5.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run left_5.png rename to triple-dungeon/resources/images/characters/knight/run_left_5.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run right_0.png b/triple-dungeon/resources/images/characters/knight/run_right_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run right_0.png rename to triple-dungeon/resources/images/characters/knight/run_right_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run right_1.png b/triple-dungeon/resources/images/characters/knight/run_right_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run right_1.png rename to triple-dungeon/resources/images/characters/knight/run_right_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run right_2.png b/triple-dungeon/resources/images/characters/knight/run_right_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run right_2.png rename to triple-dungeon/resources/images/characters/knight/run_right_2.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run right_3.png b/triple-dungeon/resources/images/characters/knight/run_right_3.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run right_3.png rename to triple-dungeon/resources/images/characters/knight/run_right_3.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run right_4.png b/triple-dungeon/resources/images/characters/knight/run_right_4.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run right_4.png rename to triple-dungeon/resources/images/characters/knight/run_right_4.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run right_5.png b/triple-dungeon/resources/images/characters/knight/run_right_5.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run right_5.png rename to triple-dungeon/resources/images/characters/knight/run_right_5.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run up_0.png b/triple-dungeon/resources/images/characters/knight/run_up_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run up_0.png rename to triple-dungeon/resources/images/characters/knight/run_up_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run up_1.png b/triple-dungeon/resources/images/characters/knight/run_up_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run up_1.png rename to triple-dungeon/resources/images/characters/knight/run_up_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run up_2.png b/triple-dungeon/resources/images/characters/knight/run_up_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run up_2.png rename to triple-dungeon/resources/images/characters/knight/run_up_2.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run up_3.png b/triple-dungeon/resources/images/characters/knight/run_up_3.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run up_3.png rename to triple-dungeon/resources/images/characters/knight/run_up_3.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_run up_4.png b/triple-dungeon/resources/images/characters/knight/run_up_4.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_run up_4.png rename to triple-dungeon/resources/images/characters/knight/run_up_4.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice down_0.png b/triple-dungeon/resources/images/characters/knight/slice_down_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice down_0.png rename to triple-dungeon/resources/images/characters/knight/slice_down_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice down_1.png b/triple-dungeon/resources/images/characters/knight/slice_down_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice down_1.png rename to triple-dungeon/resources/images/characters/knight/slice_down_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice down_2.png b/triple-dungeon/resources/images/characters/knight/slice_down_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice down_2.png rename to triple-dungeon/resources/images/characters/knight/slice_down_2.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice left_0.png b/triple-dungeon/resources/images/characters/knight/slice_left_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice left_0.png rename to triple-dungeon/resources/images/characters/knight/slice_left_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice left_1.png b/triple-dungeon/resources/images/characters/knight/slice_left_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice left_1.png rename to triple-dungeon/resources/images/characters/knight/slice_left_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice left_2.png b/triple-dungeon/resources/images/characters/knight/slice_left_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice left_2.png rename to triple-dungeon/resources/images/characters/knight/slice_left_2.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice right_0.png b/triple-dungeon/resources/images/characters/knight/slice_right_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice right_0.png rename to triple-dungeon/resources/images/characters/knight/slice_right_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice right_1.png b/triple-dungeon/resources/images/characters/knight/slice_right_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice right_1.png rename to triple-dungeon/resources/images/characters/knight/slice_right_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice right_2.png b/triple-dungeon/resources/images/characters/knight/slice_right_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice right_2.png rename to triple-dungeon/resources/images/characters/knight/slice_right_2.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice up_0.png b/triple-dungeon/resources/images/characters/knight/slice_up_0.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice up_0.png rename to triple-dungeon/resources/images/characters/knight/slice_up_0.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice up_1.png b/triple-dungeon/resources/images/characters/knight/slice_up_1.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice up_1.png rename to triple-dungeon/resources/images/characters/knight/slice_up_1.png diff --git a/triple-dungeon/resources/images/character/knight/knight iso char_slice up_2.png b/triple-dungeon/resources/images/characters/knight/slice_up_2.png similarity index 100% rename from triple-dungeon/resources/images/character/knight/knight iso char_slice up_2.png rename to triple-dungeon/resources/images/characters/knight/slice_up_2.png diff --git a/triple-dungeon/sprites.py b/triple-dungeon/sprites.py new file mode 100644 index 0000000..2b5f5f9 --- /dev/null +++ b/triple-dungeon/sprites.py @@ -0,0 +1,70 @@ +""" +sprites.py +A file dedicated to managing sprites and animations for characters. +""" +from itertools import cycle + +import arcade +import os +import re + +from typing import Pattern + + +class AnimationSet(object): + """ + A class that helps assist with grabbing new animations from a set. + """ + + def __init__(self, directory: str): + """ + Initializes the AnimationSet class by loading files and + + :param directory: A directory containing valid animation files in the correct format. + """ + + self.directory = directory + self.animations = os.listdir(directory) + + def getAnimations(self, pattern: Pattern) -> iter: + """ + Loads all animations from the AnimationSet's directory that match the pattern. + The pattern must have 1 group that specifies the animation's index. + + :param pattern: A RegEx Pattern object. + :return: A infinite iterable looping through arcade.Texture objects. + """ + + # Finds all matching files + matches = map(lambda file: re.match(pattern, file), self.animations) + matches = list(filter(lambda match: match is not None, matches)) + # Sort in ascending order based on the connected animation index. Zero-indexing or not does not affect order. + matches.sort(key=lambda match: int(match.group(1))) + # Grab the filename and load it to the file directory + matches = list(map(lambda match: arcade.load_texture(os.path.join(self.directory, match.group(0))), matches)) + return cycle(matches) + + +class PlayerAnimations(AnimationSet): + """ + A class dedicated to serving player animations. + Player animations must be served to the class in the correct format. + + The correct format is: {action}[_{direction}]_{index}.png + action: [idle, run, slice] - The action being taken. + direction: [down, right, left, up] - The direction of the action, if applicable. Omit the underscore if not. + index: [0,) - The index of the animation. Index should be enumerated in ascending order. + """ + + def __init__(self, directory: str): + """ + Initializes the PlayerAnimations class. + """ + super(PlayerAnimations, self).__init__(directory) + + # Grabs all animations needed. These are infinite iters, use next(iter) to grab the next animation. + self.idles = self.getAnimations(re.compile(r'idle_(\d+).png')) + self.down = self.getAnimations(re.compile(r'run_down_(\d+).png')) + self.right = self.getAnimations(re.compile(r'run_right_(\d+).png')) + self.up = self.getAnimations(re.compile(r'run_up_(\d+).png')) + self.left = self.getAnimations(re.compile(r'run_left_(\d+).png'))