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

103 lines
3.6 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: Optional[Spritesheet] = None):
super().__init__()
self.spritesheet = spritesheet
if self.spritesheet is not None:
self.animation_state = list(self.spritesheet.animations.keys())[0]
else:
self.animation_state = None
self.animation_frame = 0
self.animation_delay = 0
self.animated = True
self.image = None
self.last_image = None
self.is_collider = True
self.register_collisions = 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):
if self.spritesheet is None:
self.image = None
return
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.last_image = self.image
self.image = animation['images'][self.animation_frame % len(animation['images'])]
def set_animation_state(self, state: str):
if self.spritesheet is None:
return
if state in self.spritesheet.animations:
self.animation_state = state
self.animation_delay = 0
self.tick(self.empty_tick_data())
else:
print('Unknown animation state: ' + state)
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:
if self.image is None:
print('Sprite.refresh_bounding_box: No image for sprite: ' + str(self))
return self.bounding_box
if self.bounding_box.x != self.position_scale.position[0] or \
self.bounding_box.y != self.position_scale.position[1]:
self.bounding_box = 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]
)
return self.bounding_box