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

109 lines
3.9 KiB
Python
Raw Normal View History

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
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
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
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-29 16:42:10 +02:00
def get_all_collides_with_direction(self, direction: int) -> list[CollisionDirection]:
return [collision_direction for collision_direction in self.collides_with_elements if
collision_direction.direction == direction]
def tick(self, tick_data: TickData):
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:
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
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
empty_tick_data = TickData(0, [], KeyManager(), [], PositionScale())
2023-03-25 15:41:32 +01:00
def set_animation_state(self, state: str):
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
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
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