Generalized UI Elements
parent
8cbf623247
commit
72fd82c5a6
|
@ -1,2 +1,7 @@
|
|||
# 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 level.LevelManager import LevelManager
|
||||
from physics.SpriteManager import SpriteManager, DrawLayers
|
||||
from sprite.DynamicSprite import DynamicSprite
|
||||
from sprite.PositionScale import PositionScale
|
||||
from sprite.SpritesheetManager import SpritesheetManager
|
||||
|
@ -42,21 +43,24 @@ elif what_to_run == 'physics':
|
|||
|
||||
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.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.position_scale = PositionScale((130, 100), (1, 1))
|
||||
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.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:
|
||||
clock.tick(frame_rate)
|
||||
|
@ -75,8 +79,8 @@ elif what_to_run == 'physics':
|
|||
|
||||
screen.fill((0, 0, 0))
|
||||
|
||||
physics_handler.tick(apply_frame_rate(1))
|
||||
physics_handler.draw(screen, screen_transform)
|
||||
sprite_manager.tick(apply_frame_rate(1))
|
||||
sprite_manager.draw(screen, screen_transform)
|
||||
pygame.display.update()
|
||||
|
||||
|
||||
|
@ -88,9 +92,15 @@ elif what_to_run == 'textlabel':
|
|||
pygame.display.set_caption("PM GAME")
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
test1 = TextLabel("Das ist ein Test", 400, 0, 50, alignment="left")
|
||||
test2 = TextLabel("Das ist ein Test", 400, 10, 50, alignment="center")
|
||||
test3 = TextLabel("Das ist ein Test", 400, 20, 50, alignment="right")
|
||||
test1 = TextLabel("Das ist ein Test", 100, 0, 50, alignment="left")
|
||||
test2 = TextLabel("Das ist ein Test", 100, 50, 50, alignment="left")
|
||||
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:
|
||||
clock.tick(5)
|
||||
|
|
|
@ -4,6 +4,7 @@ from sprite.DynamicSprite import DynamicSprite
|
|||
from sprite.PositionScale import PositionScale
|
||||
from sprite.Sprite import Sprite
|
||||
from sprite.StaticSprite import StaticSprite
|
||||
from ui_elements.UiElement import UiElement
|
||||
|
||||
MOTION_STEPS = 10
|
||||
TOLERANCE = 1
|
||||
|
@ -11,16 +12,14 @@ TOLERANCE = 1
|
|||
|
||||
class PhysicsElementsHandler:
|
||||
def __init__(self):
|
||||
self.sprites: list[Sprite] = []
|
||||
pass
|
||||
|
||||
def add_sprite(self, sprite: Sprite):
|
||||
self.sprites.append(sprite)
|
||||
def tick_all_layers(self, dt: float, layers: dict[str, list[UiElement]]):
|
||||
for layer in layers:
|
||||
self.tick(dt, layers[layer])
|
||||
|
||||
def remove_sprite(self, sprite: Sprite):
|
||||
self.sprites.remove(sprite)
|
||||
|
||||
def tick(self, dt: float):
|
||||
for sprite in self.sprites:
|
||||
def tick(self, dt: float, sprites: list[UiElement]):
|
||||
for sprite in sprites:
|
||||
sprite.tick(dt)
|
||||
|
||||
# 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.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])
|
||||
|
||||
for sprite in sorted_dynamic_sprites:
|
||||
|
@ -97,7 +96,3 @@ class PhysicsElementsHandler:
|
|||
return True
|
||||
|
||||
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.PositionScale import PositionScale
|
||||
from sprite.Spritesheet import Spritesheet
|
||||
from ui_elements.UiElement import UiElement
|
||||
|
||||
sys.path.append('./sprite')
|
||||
|
||||
|
||||
class Sprite:
|
||||
class Sprite(UiElement):
|
||||
def __init__(self, spritesheet: Spritesheet):
|
||||
super().__init__()
|
||||
self.spritesheet = spritesheet
|
||||
|
||||
self.animation_state = list(self.spritesheet.animations.keys())[0]
|
||||
self.animation_frame = 0
|
||||
self.animation_delay = 0
|
||||
|
||||
self.position_scale = PositionScale()
|
||||
|
||||
self.visible = True
|
||||
self.animated = True
|
||||
|
||||
self.image = None
|
||||
|
@ -47,22 +46,8 @@ class Sprite:
|
|||
self.animation_frame = frame
|
||||
self.tick(0)
|
||||
|
||||
def draw(self, screen: pygame.Surface, screen_transform: PositionScale):
|
||||
if not self.visible:
|
||||
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 render_sprite_image(self) -> pygame.Surface:
|
||||
return self.image
|
||||
|
||||
def get_bounding_box(self) -> BoundingBox:
|
||||
return BoundingBox(
|
||||
|
@ -72,9 +57,6 @@ class Sprite:
|
|||
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):
|
||||
# re-attach all the images to a single surface and save it to a file
|
||||
width = 0
|
||||
|
|
|
@ -3,20 +3,29 @@ from pygame import Surface, Rect
|
|||
from pygame.font import Font
|
||||
|
||||
from sprite.PositionScale import PositionScale
|
||||
from ui_elements.UiElement import UiElement
|
||||
|
||||
|
||||
class TextLabel:
|
||||
def __init__(self, text: str, x_position: float, y_position: float, font_size: int,
|
||||
alignment: str = "left"):
|
||||
class TextLabel(UiElement):
|
||||
def tick(self, dt: float):
|
||||
pass
|
||||
|
||||
def __init__(self, text: str, x_position: float, y_position: float, font_size: int, alignment: str = "left"):
|
||||
super().__init__()
|
||||
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.alignment = alignment
|
||||
|
||||
self.font_size = 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):
|
||||
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()
|
||||
|
||||
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":
|
||||
screen.blit(rendered_font, (self.x_position, self.y_position))
|
||||
self.position_scale.position = (self.x_position, self.y_position)
|
||||
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],
|
||||
screen_transform.scale[1] * self.position_scale.scale[1])
|
||||
super().draw(screen, screen_transform)
|
||||
|
||||
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.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):
|
||||
def set_text(self, new_text: str):
|
||||
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