diff --git a/pyscroll/animation.py b/pyscroll/animation.py index 504d1ab..a955cfc 100644 --- a/pyscroll/animation.py +++ b/pyscroll/animation.py @@ -1,19 +1,30 @@ from __future__ import annotations -from collections import namedtuple from collections.abc import Sequence -from typing import Union +from typing import NamedTuple, Union + +from pygame import Surface + + +class AnimationFrame(NamedTuple): + image: Surface + duration: float + -AnimationFrame = namedtuple("AnimationFrame", "image duration") TimeLike = Union[float, int] __all__ = ("AnimationFrame", "AnimationToken") class AnimationToken: - __slots__ = ["next", "positions", "frames", "index"] - - def __init__(self, positions, frames: Sequence, initial_time: int = 0) -> None: + __slots__ = ["_next", "positions", "frames", "index"] + + def __init__( + self, + positions: set[tuple[int, int, int]], + frames: Sequence[AnimationFrame], + initial_time: float = 0.0, + ) -> None: """ Constructor @@ -22,14 +33,19 @@ def __init__(self, positions, frames: Sequence, initial_time: int = 0) -> None: frames: Sequence of frames that compromise the animation initial_time: Used to compensate time between starting and changing animations + Raises: + ValueError: If the frames sequence is empty """ - frames = tuple(AnimationFrame(*i) for i in frames) + if not frames: + raise ValueError("Frames sequence cannot be empty") + + frames = tuple(AnimationFrame(*frame_data) for frame_data in frames) self.positions = positions self.frames = frames - self.next = frames[0].duration + initial_time + self._next = frames[0].duration + initial_time self.index = 0 - def advance(self, last_time: TimeLike): + def advance(self, last_time: TimeLike) -> AnimationFrame: """ Advance the frame, and set timer for next frame @@ -43,6 +59,8 @@ def advance(self, last_time: TimeLike): Args: last_time: Duration of the last frame + Returns: + AnimationFrame: The next frame in the animation """ # advance the animation frame index, looping by default if self.index == len(self.frames) - 1: @@ -52,11 +70,23 @@ def advance(self, last_time: TimeLike): # set the timer for the next advance next_frame = self.frames[self.index] - self.next = next_frame.duration + last_time + self._next = next_frame.duration + last_time return next_frame def __lt__(self, other): + """ + Compare the animation token with another object based on the next frame time + + Args: + other: The object to compare with + + Returns: + bool: True if the next frame time is less than the other object's time + """ try: - return self.next < other.next + return self._next < other._next except AttributeError: - return self.next < other + return self._next < other + + def __repr__(self) -> str: + return f"AnimationToken(positions={self.positions}, frames={self.frames})"