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): self.update_image(tick_data) def update_image(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'])] empty_tick_data = TickData(0, [], KeyManager(), [], PositionScale()) def set_animation_state(self, state: str): if self.spritesheet is None or self.animation_state == state: return if state in self.spritesheet.animations: self.animation_state = state self.animation_delay = 0 self.update_image(self.empty_tick_data) else: print('Unknown animation state: ' + state) def set_animation_frame(self, frame: int): self.animation_frame = frame self.update_image(self.empty_tick_data) 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