diff --git a/project/data/font/MilkyNice.ttf b/project/data/font/MilkyNice.ttf new file mode 100644 index 0000000..a1cc8bd Binary files /dev/null and b/project/data/font/MilkyNice.ttf differ diff --git a/project/data/levels/1-1.csv b/project/data/levels/1-1.csv new file mode 100644 index 0000000..6fe1a88 --- /dev/null +++ b/project/data/levels/1-1.csv @@ -0,0 +1,43 @@ +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,X,X,X,X,X,X,X,X,X,,,,,,,,,,,,,,,,,D,,, +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,,,,,,,,,,,,,,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +3,3,id=HEBEL,requires=HEBEL;HEBEL-2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/project/data/levels/levels.json b/project/data/levels/levels.json new file mode 100644 index 0000000..159da51 --- /dev/null +++ b/project/data/levels/levels.json @@ -0,0 +1,10 @@ +[ + { + "name": "1-1", + "theme": "ghost", + "abilities": [ + "dash" + ], + "file": "1-1.csv" + } +] \ No newline at end of file diff --git a/project/sprites/sprites.json b/project/data/sprites/sprites.json similarity index 100% rename from project/sprites/sprites.json rename to project/data/sprites/sprites.json diff --git a/project/sprites/test_1.png b/project/data/sprites/test_1.png similarity index 100% rename from project/sprites/test_1.png rename to project/data/sprites/test_1.png diff --git a/project/level/Level.py b/project/level/Level.py new file mode 100644 index 0000000..bbefd3b --- /dev/null +++ b/project/level/Level.py @@ -0,0 +1,44 @@ +LEVEL_SIZE = (71, 40) + + +class Level: + def __init__(self, name: str, theme: str, abilities: list[str], csv_grid: list[str]): + self.name = name + self.theme = theme + self.abilities = abilities + self.tiles = self.parse_csv_to_2darray(csv_grid) + + def __str__(self): + return 'name: ' + self.name + ', theme: ' + self.theme + ', allowed abilities: ' + str(self.abilities) + + def parse_csv_to_2darray(self, csv_grid: list[str]): + tiles = [] + + for line_number, line in enumerate(csv_grid): + if line_number <= LEVEL_SIZE[1]: + tiles.append([]) + for item_number, item in enumerate(line): + if item_number <= LEVEL_SIZE[0]: + tiles[line_number].append({'tile': item}) + else: + print('Level is too wide:', item_number, '>', LEVEL_SIZE[0]) + break + + elif line[0] != '': + x = int(line[0]) + y = int(line[1]) + tile = tiles[x][y] + + for i in range(2, len(line)): + if line[i] == '': + break + + split_item = line[i].split('=') + if split_item[0] == 'id': + tile[split_item[0]] = split_item[1] + elif split_item[0] == 'requires': + tile[split_item[0]] = split_item[1].split(';') + else: + raise ValueError('Incorrect attribute name: ' + split_item[0]) + tiles[x][y] = tile + return tiles diff --git a/project/level/LevelElementSymbols.py b/project/level/LevelElementSymbols.py new file mode 100644 index 0000000..07ea959 --- /dev/null +++ b/project/level/LevelElementSymbols.py @@ -0,0 +1,18 @@ +import csv + +SCREEN_WIDTH = 71 +SCREEN_HEIGHT = 40 + +STATIC = 'static' +DYNAMIC = 'dynamic' + + +class LevelElementSymbols: + SOLID_BLOCK = { + 'symbol': '#', + 'type': STATIC + } + AIR = { + 'symbol': '', + 'type': STATIC + } diff --git a/project/level/LevelManager.py b/project/level/LevelManager.py new file mode 100644 index 0000000..6cf6a30 --- /dev/null +++ b/project/level/LevelManager.py @@ -0,0 +1,29 @@ +import sys +import os +import json + +from level.Level import Level + + +class LevelManager: + def __init__(self, level_dir: str): + self.level_dir = level_dir + self.levels = [] + + def load_from_config(self, config_file: str): + print('Loading levels from sprite sheet config file', config_file) + config = json.load(open(config_file)) + + for level_data in config: + csv = self.parse_csv(self.level_dir + '/' + level_data['file']) + level = Level(level_data['name'], level_data['theme'], level_data['abilities'], csv) + self.levels.append(level) + + def parse_csv(self, file: str): + csv_array = [] + with open(file) as csvfile: + for row in csvfile: + split_row = row.split(',') + filtered_row = list(map(lambda x: x.replace('\n', ''), split_row)) + csv_array.append(filtered_row) + return csv_array diff --git a/project/main.py b/project/main.py index c7d06a2..ad255f6 100644 --- a/project/main.py +++ b/project/main.py @@ -1,35 +1,117 @@ import random import pygame +from pygame.font import Font -from PositionScale import PositionScale -from SpritesheetManager import SpritesheetManager -from Sprite import Sprite +from level.LevelManager import LevelManager +from sprite.DynamicSprite import DynamicSprite +from sprite.PositionScale import PositionScale +from sprite.SpritesheetManager import SpritesheetManager +from physics.PhysicsElementsHandler import PhysicsElementsHandler +from sprite.Sprite import Sprite +from sprite.StaticSprite import StaticSprite +from ui_elements.TextLabel import TextLabel -pygame.init() -screen = pygame.display.set_mode((300, 300)) -pygame.display.set_caption("PE GAME") -clock = pygame.time.Clock() -spritesheet_manager = SpritesheetManager("sprites", "sprites/sprites.json") +what_to_run = 'physics' -test_1_sprite = Sprite(spritesheet_manager.get_sheet("test_1")) +if what_to_run == 'level': + csv_parse_test = LevelManager('data/levels') + csv_parse_test.load_from_config('data/levels/levels.json') + print(csv_parse_test.levels[0]) -test_1_sprite.dump("debug.png") -while True: - clock.tick(5) +elif what_to_run == 'physics': + screen_transform = PositionScale((0, 0), (4, 4)) - for event in pygame.event.get(): - if event.type == pygame.QUIT: - pygame.quit() + pygame.init() + screen = pygame.display.set_mode((600, 500)) + pygame.display.set_caption("PE GAME") + clock = pygame.time.Clock() - screen.fill((0, 0, 0)) + spritesheet_manager = SpritesheetManager("data/sprites", "data/sprites/sprites.json") - test_1_sprite.tick(1) - test_1_sprite.draw(screen, PositionScale((40, 40), (3, 3))) - pygame.display.update() + test_1_sprite = DynamicSprite(spritesheet_manager.get_sheet("test_1")) + test_2_sprite = StaticSprite(spritesheet_manager.get_sheet("test_1")) - if random.randint(1, 10) == 1: - test_1_sprite.set_animation_state(random.choice(["walk_r", "walk_l", "idle", "other_test"])) - print(test_1_sprite.animation_state) + test_1_sprite.position_scale = PositionScale((10, 10), (1, 1)) + test_2_sprite.position_scale = PositionScale((100, 100), (1, 1)) + + physics_handler = PhysicsElementsHandler() + physics_handler.add_sprite(test_1_sprite) + physics_handler.add_sprite(test_2_sprite) + + while True: + clock.tick(10) + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + exit(0) + + screen.fill((0, 0, 0)) + + physics_handler.tick(1) + physics_handler.draw(screen, screen_transform) + pygame.display.update() + + +elif what_to_run == 'textlabel': + screen_transform = PositionScale((0, 0), (4, 4)) + + pygame.init() + screen = pygame.display.set_mode((300, 300)) + pygame.display.set_caption("PM GAME") + clock = pygame.time.Clock() + + test = TextLabel("Hallo", 100, 100, 50, Font('data/font/MilkyNice.otf')) + + while True: + clock.tick(5) + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + + screen.fill((0, 0, 0)) + + test.draw(screen, screen_transform) + pygame.display.update() + + +elif what_to_run == 'sprite': + screen_transform = PositionScale((0, 0), (4, 4)) + + pygame.init() + screen = pygame.display.set_mode((300, 300)) + pygame.display.set_caption("PE GAME") + clock = pygame.time.Clock() + + spritesheet_manager = SpritesheetManager("data/sprites", "data/sprites/sprites.json") + + test_1_sprite = Sprite(spritesheet_manager.get_sheet("test_1")) + test_2_sprite = Sprite(spritesheet_manager.get_sheet("test_1")) + + test_1_sprite.position_scale = PositionScale((10, 10), (1, 1)) + test_2_sprite.position_scale = PositionScale((60, 60), (1, 1)) + + # test_1_sprite.dump("debug.png") + + while True: + clock.tick(5) + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + + screen.fill((0, 0, 0)) + + test_1_sprite.tick(1) + test_1_sprite.draw(screen, screen_transform) + test_2_sprite.tick(1) + test_2_sprite.draw(screen, screen_transform) + pygame.display.update() + + if random.randint(1, 10) == 1: + test_1_sprite.set_animation_state(random.choice(["walk_r", "walk_l", "idle", "other_test"])) + print(test_1_sprite.animation_state) diff --git a/project/physics/PhysicsElementsHandler.py b/project/physics/PhysicsElementsHandler.py new file mode 100644 index 0000000..11e8392 --- /dev/null +++ b/project/physics/PhysicsElementsHandler.py @@ -0,0 +1,62 @@ +from pygame.surface import Surface + +from sprite.DynamicSprite import DynamicSprite +from sprite.PositionScale import PositionScale +from sprite.Sprite import Sprite +from sprite.StaticSprite import StaticSprite + +MOTION_STEPS = 10 + +class PhysicsElementsHandler: + def __init__(self): + self.sprites: list[Sprite] = [] + + def add_sprite(self, sprite: Sprite): + self.sprites.append(sprite) + + def remove_sprite(self, sprite: Sprite): + self.sprites.remove(sprite) + + def tick(self, dt: float): + for sprite in self.sprites: + sprite.tick(dt) + + # handle motion and collisions. To do this: + # 1. Find all sprites that have collision enabled and store them in a list + # 2. Create a list of all sprites that are dynamic sprites + # 3. Sort the sprites by their y position + # 4. For each sprite: + # 4.1. Divide the motion into MOTION_STEPS steps + # 4.2. For each step: + # 4.2.1. Check if the sprite collides with any other sprite + # 4.2.2. If it does, move the sprite back to the previous position and stop the motion + # 4.2.3. If it doesn't, move the sprite to the new position + + colliders = [sprite for sprite in self.sprites if sprite.is_collider and isinstance(sprite, StaticSprite)] + + dynamic_sprites = [sprite for sprite in self.sprites if isinstance(sprite, DynamicSprite)] + sorted_dynamic_sprites = sorted(dynamic_sprites, key=lambda spr: spr.position_scale.position[1]) + + for sprite in sorted_dynamic_sprites: + total_motion = sprite.motion + motion_step = (total_motion[0] / MOTION_STEPS, total_motion[1] / MOTION_STEPS) + + for i in range(MOTION_STEPS): + sprite.position_scale.position = ( + sprite.position_scale.position[0] + motion_step[0], + sprite.position_scale.position[1] + motion_step[1] + ) + + for collider in colliders: + if sprite is not collider and sprite.collides_with(collider): + sprite.position_scale.position = ( + sprite.position_scale.position[0] - motion_step[0], + sprite.position_scale.position[1] - motion_step[1] + ) + + sprite.motion = (0, 0) + break + + def draw(self, screen: Surface, screen_transform: PositionScale): + for sprite in self.sprites: + sprite.draw(screen, screen_transform) diff --git a/project/sprite/BoundingBox.py b/project/sprite/BoundingBox.py new file mode 100644 index 0000000..d6eb886 --- /dev/null +++ b/project/sprite/BoundingBox.py @@ -0,0 +1,13 @@ + +class BoundingBox: + def __init__(self, x, y, width, height): + self.x = x + self.y = y + self.width = width + self.height = height + + def get_dimensions(self): + return self.width, self.height + + def get_position(self): + return self.x, self.y diff --git a/project/sprite/DynamicSprite.py b/project/sprite/DynamicSprite.py new file mode 100644 index 0000000..6dd9207 --- /dev/null +++ b/project/sprite/DynamicSprite.py @@ -0,0 +1,25 @@ +import pygame +import sys + +from sprite.Sprite import Sprite +from sprite.Spritesheet import Spritesheet +from sprite.StaticSprite import StaticSprite + +sys.path.append('./sprite') + + +class DynamicSprite(StaticSprite): + def __init__(self, spritesheet: Spritesheet): + super().__init__(spritesheet) + + self.motion = (0, 0) + self.deceleration_horizontal = 0 + self.gravity = 0 + + def tick(self, dt: float): + super().tick(dt) + + self.motion = ( + self.motion[0] - self.deceleration_horizontal * dt, + self.motion[1] + self.gravity * dt + ) diff --git a/project/PositionScale.py b/project/sprite/PositionScale.py similarity index 82% rename from project/PositionScale.py rename to project/sprite/PositionScale.py index 90fde85..1666c63 100644 --- a/project/PositionScale.py +++ b/project/sprite/PositionScale.py @@ -1,5 +1,5 @@ class PositionScale: - def __init__(self, position=(0, 0), scale=(1, 1)): + def __init__(self, position: tuple[int, int] = (0, 0), scale: tuple[int, int] = (1, 1)): self.position = position self.scale = scale diff --git a/project/Sprite.py b/project/sprite/Sprite.py similarity index 64% rename from project/Sprite.py rename to project/sprite/Sprite.py index 9ace5b2..0628199 100644 --- a/project/Sprite.py +++ b/project/sprite/Sprite.py @@ -1,10 +1,15 @@ import pygame +import sys -from PositionScale import PositionScale +from sprite.BoundingBox import BoundingBox +from sprite.PositionScale import PositionScale +from sprite.Spritesheet import Spritesheet + +sys.path.append('./sprite') class Sprite: - def __init__(self, spritesheet): + def __init__(self, spritesheet: Spritesheet): self.spritesheet = spritesheet self.animation_state = list(self.spritesheet.animations.keys())[0] @@ -18,34 +23,40 @@ class Sprite: self.image = None - def tick(self, dt): + self.is_collider = True + + def tick(self, dt: float): animation = self.spritesheet.animations[self.animation_state] if self.animated: self.animation_delay += dt - while self.animation_delay >= animation["delays"][self.animation_frame % len(animation["delays"])]: - self.animation_delay -= animation["delays"][self.animation_frame % len(animation["delays"])] - self.animation_frame = (self.animation_frame + 1) % len(animation["images"]) + while self.animation_delay >= animation['delays'][self.animation_frame % len(animation['delays'])]: + self.animation_delay -= animation['delays'][self.animation_frame % len(animation['delays'])] + self.animation_frame = (self.animation_frame + 1) % len(animation['images']) - self.image = animation["images"][self.animation_frame % len(animation["images"])] + self.image = animation['images'][self.animation_frame % len(animation['images'])] - def set_animation_state(self, state): + def set_animation_state(self, state: str): if state in self.spritesheet.animations: self.animation_state = state self.animation_delay = 0 self.tick(0) - def set_animation_frame(self, frame): + def set_animation_frame(self, frame: int): self.animation_frame = frame self.tick(0) - def draw(self, screen, screen_transform): + def draw(self, screen: pygame.Surface, screen_transform: PositionScale): if not self.visible: return if self.image is not None: target_position = screen_transform.apply_scale_to_position() + target_position = ( + target_position[0] + self.position_scale.position[0], + target_position[1] + self.position_scale.position[1] + ) target_scale = ( screen_transform.scale[0] * self.position_scale.scale[0], @@ -60,6 +71,14 @@ class Sprite: screen.blit(target_image, target_position) + def get_bounding_box(self) -> BoundingBox: + return BoundingBox( + self.position_scale.position[0], + self.position_scale.position[1], + self.image.get_width(), + self.image.get_height() + ) + def get_scaled_image(self, image, resize): return pygame.transform.scale(image, resize) @@ -71,7 +90,7 @@ class Sprite: for animation in self.spritesheet.animations.values(): max_height = 0 total_width = 0 - for image in animation["images"]: + for image in animation['images']: total_width += image.get_width() max_height = max(max_height, image.get_height()) width = max(width, total_width) @@ -83,7 +102,7 @@ class Sprite: y = 0 for animation in self.spritesheet.animations.values(): max_height = 0 - for image in animation["images"]: + for image in animation['images']: sheet.blit(image, (x, y)) x += image.get_width() max_height = max(max_height, image.get_height()) diff --git a/project/Spritesheet.py b/project/sprite/Spritesheet.py similarity index 100% rename from project/Spritesheet.py rename to project/sprite/Spritesheet.py diff --git a/project/SpritesheetManager.py b/project/sprite/SpritesheetManager.py similarity index 91% rename from project/SpritesheetManager.py rename to project/sprite/SpritesheetManager.py index 50abcb4..ea704a2 100644 --- a/project/SpritesheetManager.py +++ b/project/sprite/SpritesheetManager.py @@ -1,7 +1,9 @@ -import pygame import json +import sys -from Spritesheet import Spritesheet +from sprite.Spritesheet import Spritesheet + +sys.path.append('./sprite') # This class is used to load named sprite sheets from the img folder. diff --git a/project/sprite/StaticSprite.py b/project/sprite/StaticSprite.py new file mode 100644 index 0000000..a346c08 --- /dev/null +++ b/project/sprite/StaticSprite.py @@ -0,0 +1,41 @@ +import pygame +import sys + +from sprite.Sprite import Sprite +from sprite.Spritesheet import Spritesheet + +sys.path.append('./sprite') + + +class StaticSprite(Sprite): + def __init__(self, spritesheet: Spritesheet): + super().__init__(spritesheet) + + self.position = (0, 0) + + def collides_with(self, collider: 'StaticSprite'): + if not self.is_collider or not collider.is_collider: + return False + + self_bounds = self.get_bounding_box() + other_bounds = collider.get_bounding_box() + + self_dimensions = self_bounds.get_dimensions() + other_dimensions = other_bounds.get_dimensions() + + self_position = self_bounds.get_position() + other_position = other_bounds.get_position() + + if self_position[0] + self_dimensions[0] < other_position[0]: + return False + + if self_position[0] > other_position[0] + other_dimensions[0]: + return False + + if self_position[1] + self_dimensions[1] < other_position[1]: + return False + + if self_position[1] > other_position[1] + other_dimensions[1]: + return False + + return True diff --git a/project/ui_elements/TextLabel.py b/project/ui_elements/TextLabel.py new file mode 100644 index 0000000..8000788 --- /dev/null +++ b/project/ui_elements/TextLabel.py @@ -0,0 +1,35 @@ +import pygame +from pygame.examples.textinput import Screen +from pygame.font import Font + +from sprite.PositionScale import PositionScale + + +class TextLabel: + # pygame.font.Font('data/font/arcade.TTF') + def __init__(self, text: str, x_position: float, y_position: float, font_size: float, font: Font, + alignment: str = "left"): + self.text = text + self.x_position = x_position + self.y_position = y_position + self.alignment = alignment + self.current_width = 0 + self.current_height = 0 + self.font_size = font_size + self.font = font + self.position_scale = PositionScale() + + def draw(self, screen: Screen, screen_transform: PositionScale): + rendered_font = self.font.render(str(self.text), True, (255, 255, 255)) + self.current_width = rendered_font.get_width() + self.current_height = rendered_font.get_height() + + if self.alignment == "right": + screen.blit(rendered_font, (self.x_position - self.current_width / 2, self.y_position)) + elif self.alignment == "right": + screen.blit(rendered_font, (self.x_position, self.y_position)) + elif self.alignment == "center": + screen.blit(rendered_font, (self.x_position - self.current_width, self.y_position)) + + def set_text(self, new_text: str): + self.text = new_text