Generalized UI Elements
parent
8cbf623247
commit
72fd82c5a6
|
@ -1,2 +1,7 @@
|
||||||
# sep-se-platformer
|
# sep-se-platformer
|
||||||
|
|
||||||
|
Links:
|
||||||
|
|
||||||
|
- [doc: Software design](https://docs.google.com/document/d/1GpieqcuPjXC1P-a0mXGLe61XF8xzZ_h2taeojuUqToA/edit#heading=h.a6o0m6lt88hs)
|
||||||
|
- [tab: Arbeitspakete](https://docs.google.com/spreadsheets/d/1zyScof0CLPPSmdI0Dq3QWAdLAvyMhk_QFo7VJDFPymk/edit#gid=0)
|
||||||
|
- [tab: Levels](https://docs.google.com/spreadsheets/d/1kIfnlJLYZ0p-zY8Jl699yGgnn6wju2nfAVBx9WdDkQI/edit#gid=741912808)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import pygame
|
||||||
from pygame.font import Font
|
from pygame.font import Font
|
||||||
|
|
||||||
from level.LevelManager import LevelManager
|
from level.LevelManager import LevelManager
|
||||||
|
from physics.SpriteManager import SpriteManager, DrawLayers
|
||||||
from sprite.DynamicSprite import DynamicSprite
|
from sprite.DynamicSprite import DynamicSprite
|
||||||
from sprite.PositionScale import PositionScale
|
from sprite.PositionScale import PositionScale
|
||||||
from sprite.SpritesheetManager import SpritesheetManager
|
from sprite.SpritesheetManager import SpritesheetManager
|
||||||
|
@ -42,21 +43,24 @@ elif what_to_run == 'physics':
|
||||||
|
|
||||||
spritesheet_manager = SpritesheetManager("data/sprites", "data/sprites/sprites.json")
|
spritesheet_manager = SpritesheetManager("data/sprites", "data/sprites/sprites.json")
|
||||||
|
|
||||||
physics_handler = PhysicsElementsHandler()
|
sprite_manager = SpriteManager()
|
||||||
|
|
||||||
test_1_sprite = DynamicSprite(spritesheet_manager.get_sheet("test_1"))
|
test_1_sprite = DynamicSprite(spritesheet_manager.get_sheet("test_1"))
|
||||||
test_1_sprite.position_scale = PositionScale((10, -100), (1, 1))
|
test_1_sprite.position_scale = PositionScale((10, -100), (1, 1))
|
||||||
physics_handler.add_sprite(test_1_sprite)
|
sprite_manager.add_sprite(DrawLayers.OBJECTS, test_1_sprite)
|
||||||
|
|
||||||
test_3_sprite = DynamicSprite(spritesheet_manager.get_sheet("test_1"))
|
test_3_sprite = DynamicSprite(spritesheet_manager.get_sheet("test_1"))
|
||||||
test_3_sprite.position_scale = PositionScale((130, 100), (1, 1))
|
test_3_sprite.position_scale = PositionScale((130, 100), (1, 1))
|
||||||
test_3_sprite.motion = (-9, -10)
|
test_3_sprite.motion = (-9, -10)
|
||||||
physics_handler.add_sprite(test_3_sprite)
|
sprite_manager.add_sprite(DrawLayers.OBJECTS, test_3_sprite)
|
||||||
|
|
||||||
test_2_sprite = StaticSprite(spritesheet_manager.get_sheet("test_1"))
|
test_2_sprite = StaticSprite(spritesheet_manager.get_sheet("test_1"))
|
||||||
test_2_sprite.position_scale = PositionScale((10, 80), (1, 1))
|
test_2_sprite.position_scale = PositionScale((10, 80), (1, 1))
|
||||||
physics_handler.add_sprite(test_2_sprite)
|
sprite_manager.add_sprite(DrawLayers.OBJECTS, test_2_sprite)
|
||||||
|
|
||||||
|
text_1 = TextLabel("Das ist ein Test", 10, 80, 50, alignment="left")
|
||||||
|
text_1.position_scale.scale = (0.1, 0.1)
|
||||||
|
sprite_manager.add_sprite(DrawLayers.UI, text_1)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
clock.tick(frame_rate)
|
clock.tick(frame_rate)
|
||||||
|
@ -75,8 +79,8 @@ elif what_to_run == 'physics':
|
||||||
|
|
||||||
screen.fill((0, 0, 0))
|
screen.fill((0, 0, 0))
|
||||||
|
|
||||||
physics_handler.tick(apply_frame_rate(1))
|
sprite_manager.tick(apply_frame_rate(1))
|
||||||
physics_handler.draw(screen, screen_transform)
|
sprite_manager.draw(screen, screen_transform)
|
||||||
pygame.display.update()
|
pygame.display.update()
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,9 +92,15 @@ elif what_to_run == 'textlabel':
|
||||||
pygame.display.set_caption("PM GAME")
|
pygame.display.set_caption("PM GAME")
|
||||||
clock = pygame.time.Clock()
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
test1 = TextLabel("Das ist ein Test", 400, 0, 50, alignment="left")
|
test1 = TextLabel("Das ist ein Test", 100, 0, 50, alignment="left")
|
||||||
test2 = TextLabel("Das ist ein Test", 400, 10, 50, alignment="center")
|
test2 = TextLabel("Das ist ein Test", 100, 50, 50, alignment="left")
|
||||||
test3 = TextLabel("Das ist ein Test", 400, 20, 50, alignment="right")
|
test3 = TextLabel("Das ist ein Test", 100, 20, 50, alignment="left")
|
||||||
|
|
||||||
|
test1.position_scale.scale = (0.2, 0.2)
|
||||||
|
test2.position_scale.scale = (0.4, 0.4)
|
||||||
|
test3.position_scale.scale = (0.2, 0.2)
|
||||||
|
|
||||||
|
test3.visible = False
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
clock.tick(5)
|
clock.tick(5)
|
||||||
|
|
|
@ -4,6 +4,7 @@ from sprite.DynamicSprite import DynamicSprite
|
||||||
from sprite.PositionScale import PositionScale
|
from sprite.PositionScale import PositionScale
|
||||||
from sprite.Sprite import Sprite
|
from sprite.Sprite import Sprite
|
||||||
from sprite.StaticSprite import StaticSprite
|
from sprite.StaticSprite import StaticSprite
|
||||||
|
from ui_elements.UiElement import UiElement
|
||||||
|
|
||||||
MOTION_STEPS = 10
|
MOTION_STEPS = 10
|
||||||
TOLERANCE = 1
|
TOLERANCE = 1
|
||||||
|
@ -11,16 +12,14 @@ TOLERANCE = 1
|
||||||
|
|
||||||
class PhysicsElementsHandler:
|
class PhysicsElementsHandler:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sprites: list[Sprite] = []
|
pass
|
||||||
|
|
||||||
def add_sprite(self, sprite: Sprite):
|
def tick_all_layers(self, dt: float, layers: dict[str, list[UiElement]]):
|
||||||
self.sprites.append(sprite)
|
for layer in layers:
|
||||||
|
self.tick(dt, layers[layer])
|
||||||
|
|
||||||
def remove_sprite(self, sprite: Sprite):
|
def tick(self, dt: float, sprites: list[UiElement]):
|
||||||
self.sprites.remove(sprite)
|
for sprite in sprites:
|
||||||
|
|
||||||
def tick(self, dt: float):
|
|
||||||
for sprite in self.sprites:
|
|
||||||
sprite.tick(dt)
|
sprite.tick(dt)
|
||||||
|
|
||||||
# handle motion and collisions. To do this:
|
# handle motion and collisions. To do this:
|
||||||
|
@ -34,9 +33,9 @@ class PhysicsElementsHandler:
|
||||||
# 4.2.2. If it does, move the sprite back to the previous position and stop the motion
|
# 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
|
# 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)]
|
colliders = [sprite for sprite in sprites if isinstance(sprite, StaticSprite) and sprite.is_collider]
|
||||||
|
|
||||||
dynamic_sprites = [sprite for sprite in self.sprites if isinstance(sprite, DynamicSprite)]
|
dynamic_sprites = [sprite for sprite in sprites if isinstance(sprite, DynamicSprite)]
|
||||||
sorted_dynamic_sprites = sorted(dynamic_sprites, key=lambda spr: spr.position_scale.position[1])
|
sorted_dynamic_sprites = sorted(dynamic_sprites, key=lambda spr: spr.position_scale.position[1])
|
||||||
|
|
||||||
for sprite in sorted_dynamic_sprites:
|
for sprite in sorted_dynamic_sprites:
|
||||||
|
@ -97,7 +96,3 @@ class PhysicsElementsHandler:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def draw(self, screen: Surface, screen_transform: PositionScale):
|
|
||||||
for sprite in self.sprites:
|
|
||||||
sprite.draw(screen, screen_transform)
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
from pygame import Surface
|
||||||
|
|
||||||
|
from physics.PhysicsElementsHandler import PhysicsElementsHandler
|
||||||
|
from sprite.PositionScale import PositionScale
|
||||||
|
from sprite.Sprite import Sprite
|
||||||
|
from ui_elements.UiElement import UiElement
|
||||||
|
|
||||||
|
|
||||||
|
class DrawLayers:
|
||||||
|
BACKGROUND = 'background'
|
||||||
|
LEVEL = 'level'
|
||||||
|
OBJECTS = 'objects'
|
||||||
|
PLAYER = 'player'
|
||||||
|
UI = 'ui'
|
||||||
|
|
||||||
|
DRAW_ORDER = [BACKGROUND, LEVEL, OBJECTS, PLAYER, UI]
|
||||||
|
|
||||||
|
|
||||||
|
class SpriteManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.physics_handler = PhysicsElementsHandler()
|
||||||
|
|
||||||
|
self.layers: dict[str, list[UiElement]] = {}
|
||||||
|
for layer in DrawLayers.DRAW_ORDER:
|
||||||
|
self.layers[layer] = []
|
||||||
|
|
||||||
|
def add_sprite(self, layer: str, sprite: UiElement):
|
||||||
|
self.layers[layer].append(sprite)
|
||||||
|
|
||||||
|
def remove_sprite(self, sprite: UiElement):
|
||||||
|
for layer in self.layers:
|
||||||
|
if sprite in self.layers[layer]:
|
||||||
|
self.layers[layer].remove(sprite)
|
||||||
|
|
||||||
|
def tick(self, dt: float):
|
||||||
|
self.physics_handler.tick_all_layers(dt, self.layers)
|
||||||
|
|
||||||
|
def draw(self, screen: Surface, screen_transform: PositionScale):
|
||||||
|
for layer in DrawLayers.DRAW_ORDER:
|
||||||
|
for sprite in self.layers[layer]:
|
||||||
|
sprite.draw(screen, screen_transform)
|
|
@ -4,21 +4,20 @@ import sys
|
||||||
from sprite.BoundingBox import BoundingBox
|
from sprite.BoundingBox import BoundingBox
|
||||||
from sprite.PositionScale import PositionScale
|
from sprite.PositionScale import PositionScale
|
||||||
from sprite.Spritesheet import Spritesheet
|
from sprite.Spritesheet import Spritesheet
|
||||||
|
from ui_elements.UiElement import UiElement
|
||||||
|
|
||||||
sys.path.append('./sprite')
|
sys.path.append('./sprite')
|
||||||
|
|
||||||
|
|
||||||
class Sprite:
|
class Sprite(UiElement):
|
||||||
def __init__(self, spritesheet: Spritesheet):
|
def __init__(self, spritesheet: Spritesheet):
|
||||||
|
super().__init__()
|
||||||
self.spritesheet = spritesheet
|
self.spritesheet = spritesheet
|
||||||
|
|
||||||
self.animation_state = list(self.spritesheet.animations.keys())[0]
|
self.animation_state = list(self.spritesheet.animations.keys())[0]
|
||||||
self.animation_frame = 0
|
self.animation_frame = 0
|
||||||
self.animation_delay = 0
|
self.animation_delay = 0
|
||||||
|
|
||||||
self.position_scale = PositionScale()
|
|
||||||
|
|
||||||
self.visible = True
|
|
||||||
self.animated = True
|
self.animated = True
|
||||||
|
|
||||||
self.image = None
|
self.image = None
|
||||||
|
@ -47,22 +46,8 @@ class Sprite:
|
||||||
self.animation_frame = frame
|
self.animation_frame = frame
|
||||||
self.tick(0)
|
self.tick(0)
|
||||||
|
|
||||||
def draw(self, screen: pygame.Surface, screen_transform: PositionScale):
|
def render_sprite_image(self) -> pygame.Surface:
|
||||||
if not self.visible:
|
return self.image
|
||||||
return
|
|
||||||
|
|
||||||
if self.image is not None:
|
|
||||||
target_scale = (screen_transform.scale[0] * self.position_scale.scale[0],
|
|
||||||
screen_transform.scale[1] * self.position_scale.scale[1])
|
|
||||||
|
|
||||||
target_position = ((self.position_scale.position[0] + screen_transform.position[0]) * target_scale[0],
|
|
||||||
(self.position_scale.position[1] + screen_transform.position[1]) * target_scale[1])
|
|
||||||
|
|
||||||
target_size = (int(target_scale[0] * self.image.get_width()),
|
|
||||||
int(target_scale[1] * self.image.get_height()))
|
|
||||||
|
|
||||||
target_image = self.get_scaled_image(self.image, target_size)
|
|
||||||
screen.blit(target_image, target_position)
|
|
||||||
|
|
||||||
def get_bounding_box(self) -> BoundingBox:
|
def get_bounding_box(self) -> BoundingBox:
|
||||||
return BoundingBox(
|
return BoundingBox(
|
||||||
|
@ -72,9 +57,6 @@ class Sprite:
|
||||||
self.image.get_height() * self.position_scale.scale[1]
|
self.image.get_height() * self.position_scale.scale[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_scaled_image(self, image, resize):
|
|
||||||
return pygame.transform.scale(image, resize)
|
|
||||||
|
|
||||||
def dump(self, file):
|
def dump(self, file):
|
||||||
# re-attach all the images to a single surface and save it to a file
|
# re-attach all the images to a single surface and save it to a file
|
||||||
width = 0
|
width = 0
|
||||||
|
|
|
@ -3,20 +3,29 @@ from pygame import Surface, Rect
|
||||||
from pygame.font import Font
|
from pygame.font import Font
|
||||||
|
|
||||||
from sprite.PositionScale import PositionScale
|
from sprite.PositionScale import PositionScale
|
||||||
|
from ui_elements.UiElement import UiElement
|
||||||
|
|
||||||
|
|
||||||
class TextLabel:
|
class TextLabel(UiElement):
|
||||||
def __init__(self, text: str, x_position: float, y_position: float, font_size: int,
|
def tick(self, dt: float):
|
||||||
alignment: str = "left"):
|
pass
|
||||||
|
|
||||||
|
def __init__(self, text: str, x_position: float, y_position: float, font_size: int, alignment: str = "left"):
|
||||||
|
super().__init__()
|
||||||
self.text = text
|
self.text = text
|
||||||
|
|
||||||
self.x_position = x_position
|
self.x_position = x_position
|
||||||
self.y_position = y_position
|
self.y_position = y_position
|
||||||
self.alignment = alignment
|
|
||||||
self.current_width = 0
|
self.current_width = 0
|
||||||
self.current_height = 0
|
self.current_height = 0
|
||||||
|
|
||||||
|
self.alignment = alignment
|
||||||
|
|
||||||
self.font_size = font_size
|
self.font_size = font_size
|
||||||
self.font = Font('data/font/MilkyNice.ttf', self.font_size)
|
self.font = Font('data/font/MilkyNice.ttf', self.font_size)
|
||||||
self.position_scale = PositionScale()
|
|
||||||
|
def render_sprite_image(self) -> pygame.Surface:
|
||||||
|
return self.font.render(str(self.text), True, pygame.Color('white'))
|
||||||
|
|
||||||
def draw(self, screen: Surface, screen_transform: PositionScale):
|
def draw(self, screen: Surface, screen_transform: PositionScale):
|
||||||
rendered_font = self.font.render(str(self.text), True, pygame.Color('white'))
|
rendered_font = self.font.render(str(self.text), True, pygame.Color('white'))
|
||||||
|
@ -25,23 +34,13 @@ class TextLabel:
|
||||||
self.current_height = rendered_font.get_height()
|
self.current_height = rendered_font.get_height()
|
||||||
|
|
||||||
if self.alignment == "right":
|
if self.alignment == "right":
|
||||||
screen.blit(rendered_font, (self.x_position - self.current_width, self.y_position))
|
self.position_scale.position = (self.x_position - self.current_width, self.y_position)
|
||||||
elif self.alignment == "left":
|
elif self.alignment == "left":
|
||||||
screen.blit(rendered_font, (self.x_position, self.y_position))
|
self.position_scale.position = (self.x_position, self.y_position)
|
||||||
elif self.alignment == "center":
|
elif self.alignment == "center":
|
||||||
screen.blit(rendered_font, (self.x_position - self.current_width / 2, self.y_position))
|
self.position_scale.position = (self.x_position - self.current_width / 2, self.y_position)
|
||||||
|
|
||||||
target_scale = (screen_transform.scale[0] * self.position_scale.scale[0],
|
super().draw(screen, screen_transform)
|
||||||
screen_transform.scale[1] * self.position_scale.scale[1])
|
|
||||||
|
|
||||||
target_position = ((self.position_scale.position[0] + screen_transform.position[0]) * target_scale[0],
|
def set_text(self, new_text: str):
|
||||||
(self.position_scale.position[1] + screen_transform.position[1]) * target_scale[1])
|
|
||||||
|
|
||||||
target_size = (int(target_scale[0] * self.x_position),
|
|
||||||
int(target_scale[1] * self.y_position))
|
|
||||||
|
|
||||||
target_image = pygame.transform.scale(rendered_font, target_size)
|
|
||||||
|
|
||||||
|
|
||||||
def set_text(self, new_text: str):
|
|
||||||
self.text = new_text
|
self.text = new_text
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import abc
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
from pygame import Surface
|
||||||
|
|
||||||
|
from sprite.PositionScale import PositionScale
|
||||||
|
|
||||||
|
|
||||||
|
class UiElement:
|
||||||
|
def __init__(self):
|
||||||
|
self.position_scale = PositionScale()
|
||||||
|
self.visible = True
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def tick(self, dt: float):
|
||||||
|
return
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def render_sprite_image(self) -> Optional[Surface]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def draw(self, screen: pygame.Surface, screen_transform: PositionScale):
|
||||||
|
if not self.visible:
|
||||||
|
return
|
||||||
|
|
||||||
|
image = self.render_sprite_image()
|
||||||
|
|
||||||
|
if image is not None:
|
||||||
|
# target_scale = (screen_transform.scale[0] * self.position_scale.scale[0],
|
||||||
|
# screen_transform.scale[1] * self.position_scale.scale[1])
|
||||||
|
|
||||||
|
# target_position = ((self.position_scale.position[0] + screen_transform.position[0]) * target_scale[0],
|
||||||
|
# (self.position_scale.position[1] + screen_transform.position[1]) * target_scale[1])
|
||||||
|
|
||||||
|
# target_size = (int(target_scale[0] * image.get_width()),
|
||||||
|
# int(target_scale[1] * image.get_height()))
|
||||||
|
|
||||||
|
# target_image = self.get_scaled_image(image, target_size)
|
||||||
|
# screen.blit(target_image, target_position)
|
||||||
|
|
||||||
|
screen_scale = screen_transform.scale
|
||||||
|
screen_position = screen_transform.position
|
||||||
|
|
||||||
|
object_scale = self.position_scale.scale
|
||||||
|
object_position = self.position_scale.position
|
||||||
|
|
||||||
|
target_position = ((object_position[0] + screen_position[0]) * screen_scale[0],
|
||||||
|
(object_position[1] + screen_position[1]) * screen_scale[1])
|
||||||
|
|
||||||
|
target_size = (int(screen_scale[0] * object_scale[0] * image.get_width()),
|
||||||
|
int(screen_scale[1] * object_scale[1] * image.get_height()))
|
||||||
|
|
||||||
|
target_image = self.get_scaled_image(image, target_size)
|
||||||
|
screen.blit(target_image, target_position)
|
||||||
|
|
||||||
|
def get_scaled_image(self, image, resize):
|
||||||
|
return pygame.transform.scale(image, resize)
|
Loading…
Reference in New Issue