sep-pm-platformer/project/sprite/Sprite.py

109 lines
3.7 KiB
Python

from typing import Optional
import pygame
from physics.CollisionDirection import CollisionDirection
from physics.TickData import TickData
from sprite.BoundingBox import BoundingBox
from sprite.PositionScale import PositionScale
from sprite.Spritesheet import Spritesheet
from ui_elements.KeyManager import KeyManager
from ui_elements.UiElement import UiElement
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.animated = True
self.image = None
self.is_collider = True
self.collides_with_elements: list[CollisionDirection] = []
def add_collides_with(self, collision_direction: CollisionDirection):
self.collides_with_elements.append(collision_direction)
def reset_collides_with(self):
self.collides_with_elements = []
def get_collides_with(self) -> list[CollisionDirection]:
return self.collides_with_elements
def get_collides_with_direction(self, direction: int) -> Optional[CollisionDirection]:
for collision_direction in self.collides_with_elements:
if collision_direction.direction == direction:
return collision_direction
return None
def tick(self, tick_data: TickData):
animation = self.spritesheet.animations[self.animation_state]
if self.animated:
self.animation_delay += tick_data.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'])
self.image = animation['images'][self.animation_frame % len(animation['images'])]
def set_animation_state(self, state: str):
if state in self.spritesheet.animations:
self.animation_state = state
self.animation_delay = 0
self.tick(self.empty_tick_data())
def set_animation_frame(self, frame: int):
self.animation_frame = frame
self.tick(self.empty_tick_data())
def empty_tick_data(self) -> TickData:
return TickData(0, [], KeyManager(), [], PositionScale())
def render_sprite_image(self) -> pygame.Surface:
return self.image
def get_bounding_box(self) -> BoundingBox:
return BoundingBox(
self.position_scale.position[0],
self.position_scale.position[1],
self.image.get_width() * self.position_scale.scale[0],
self.image.get_height() * self.position_scale.scale[1]
)
def dump(self, file):
# re-attach all the images to a single surface and save it to a file
width = 0
height = 0
for animation in self.spritesheet.animations.values():
max_height = 0
total_width = 0
for image in animation['images']:
total_width += image.get_width()
max_height = max(max_height, image.get_height())
width = max(width, total_width)
height += max_height
sheet = pygame.Surface((width, height))
x = 0
y = 0
for animation in self.spritesheet.animations.values():
max_height = 0
for image in animation['images']:
sheet.blit(image, (x, y))
x += image.get_width()
max_height = max(max_height, image.get_height())
y += max_height
x = 0
pygame.image.save(sheet, file)