Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

animation #66

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 42 additions & 12 deletions pyscroll/animation.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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

Expand All @@ -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:
Expand All @@ -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})"
4 changes: 2 additions & 2 deletions pyscroll/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def process_animation_queue(
# verify that there are tile substitutions ready
self._update_time()
try:
if self._animation_queue[0].next > self._last_time:
if self._animation_queue[0]._next > self._last_time:
return new_tiles

# raised with the animation queue is empty (no animations at all)
Expand All @@ -84,7 +84,7 @@ def process_animation_queue(
get_tile_image = self.get_tile_image

# test if the next scheduled tile change is ready
while self._animation_queue[0].next <= self._last_time:
while self._animation_queue[0]._next <= self._last_time:

# get the next tile/frame which is ready to be changed
token = heappop(self._animation_queue)
Expand Down