2023-03-26 17:01:28 +02:00
|
|
|
from typing import Optional
|
|
|
|
|
2023-03-24 17:41:48 +01:00
|
|
|
import pygame
|
|
|
|
|
2023-03-26 17:01:28 +02:00
|
|
|
from physics.CollisionDirection import CollisionDirection
|
2023-03-26 12:46:41 +02:00
|
|
|
from physics.TickData import TickData
|
2023-03-25 15:41:32 +01:00
|
|
|
from sprite.BoundingBox import BoundingBox
|
|
|
|
from sprite.PositionScale import PositionScale
|
|
|
|
from sprite.Spritesheet import Spritesheet
|
2023-03-26 15:00:29 +02:00
|
|
|
from ui_elements.KeyManager import KeyManager
|
2023-03-26 09:51:11 +02:00
|
|
|
from ui_elements.UiElement import UiElement
|
2023-03-25 15:41:32 +01:00
|
|
|
|
2023-03-24 17:41:48 +01:00
|
|
|
|
2023-03-26 09:51:11 +02:00
|
|
|
class Sprite(UiElement):
|
2023-03-27 11:46:03 +02:00
|
|
|
def __init__(self, spritesheet: Optional[Spritesheet] = None):
|
2023-03-26 09:51:11 +02:00
|
|
|
super().__init__()
|
2023-03-24 17:41:48 +01:00
|
|
|
self.spritesheet = spritesheet
|
|
|
|
|
2023-03-27 11:46:03 +02:00
|
|
|
if self.spritesheet is not None:
|
|
|
|
self.animation_state = list(self.spritesheet.animations.keys())[0]
|
|
|
|
else:
|
|
|
|
self.animation_state = None
|
2023-03-24 17:41:48 +01:00
|
|
|
self.animation_frame = 0
|
|
|
|
self.animation_delay = 0
|
|
|
|
|
|
|
|
self.animated = True
|
|
|
|
|
|
|
|
self.image = None
|
2023-03-28 19:35:42 +02:00
|
|
|
self.last_image = None
|
2023-03-24 17:41:48 +01:00
|
|
|
|
2023-03-25 15:41:32 +01:00
|
|
|
self.is_collider = True
|
2023-03-27 14:38:52 +02:00
|
|
|
self.register_collisions = True
|
2023-03-26 17:01:28 +02:00
|
|
|
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
|
2023-03-25 15:41:32 +01:00
|
|
|
|
2023-03-26 12:46:41 +02:00
|
|
|
def tick(self, tick_data: TickData):
|
2023-03-29 07:37:50 +02:00
|
|
|
self.update_image(tick_data)
|
|
|
|
|
|
|
|
def update_image(self, tick_data: TickData):
|
2023-03-27 11:46:03 +02:00
|
|
|
if self.spritesheet is None:
|
|
|
|
self.image = None
|
|
|
|
return
|
|
|
|
|
2023-03-24 17:41:48 +01:00
|
|
|
animation = self.spritesheet.animations[self.animation_state]
|
|
|
|
|
|
|
|
if self.animated:
|
2023-03-26 12:46:41 +02:00
|
|
|
self.animation_delay += tick_data.dt
|
2023-03-24 17:41:48 +01:00
|
|
|
|
2023-03-25 15:41:32 +01:00
|
|
|
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'])
|
2023-03-24 17:41:48 +01:00
|
|
|
|
2023-03-28 19:35:42 +02:00
|
|
|
self.last_image = self.image
|
2023-03-25 15:41:32 +01:00
|
|
|
self.image = animation['images'][self.animation_frame % len(animation['images'])]
|
2023-03-24 17:41:48 +01:00
|
|
|
|
2023-03-29 07:37:50 +02:00
|
|
|
empty_tick_data = TickData(0, [], KeyManager(), [], PositionScale())
|
|
|
|
|
2023-03-25 15:41:32 +01:00
|
|
|
def set_animation_state(self, state: str):
|
2023-03-29 07:37:50 +02:00
|
|
|
if self.spritesheet is None or self.animation_state == state:
|
2023-03-27 11:46:03 +02:00
|
|
|
return
|
|
|
|
|
2023-03-24 17:41:48 +01:00
|
|
|
if state in self.spritesheet.animations:
|
|
|
|
self.animation_state = state
|
|
|
|
self.animation_delay = 0
|
2023-03-29 07:37:50 +02:00
|
|
|
self.update_image(self.empty_tick_data)
|
2023-03-27 11:46:03 +02:00
|
|
|
else:
|
|
|
|
print('Unknown animation state: ' + state)
|
2023-03-24 17:41:48 +01:00
|
|
|
|
2023-03-25 15:41:32 +01:00
|
|
|
def set_animation_frame(self, frame: int):
|
2023-03-24 17:41:48 +01:00
|
|
|
self.animation_frame = frame
|
2023-03-29 07:37:50 +02:00
|
|
|
self.update_image(self.empty_tick_data)
|
2023-03-24 17:41:48 +01:00
|
|
|
|
2023-03-26 09:51:11 +02:00
|
|
|
def render_sprite_image(self) -> pygame.Surface:
|
|
|
|
return self.image
|
2023-03-24 17:41:48 +01:00
|
|
|
|
2023-03-25 15:41:32 +01:00
|
|
|
def get_bounding_box(self) -> BoundingBox:
|
2023-03-27 11:57:35 +02:00
|
|
|
if self.image is None:
|
2023-03-27 14:38:52 +02:00
|
|
|
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
|