So, I've been working on this animation player kinda thing lately to make it reusable in future projects. After i attempted to implement the reverse feature, it just didn't work properly, i start from the last frame of the spritesheet, keeps going, reaches the first frame and boom suddenly it works for the rest of the time the project is run. Here is my code (if you have any questions about how it functions feel free to ask):
class Spritesheet:
def __init__(self, filename, pos, scale, frame_h, frame_v, current_frame: Vector2):
self.filename = filename
self.pos = pos
self.scale = scale
self.frame = current_frame
self.frame_h = frame_h
self.frame_v = frame_v
self.image = load_image(self.filename)
self.texture = load_texture_from_image(self.image)
self.rect = Rectangle(self.frame.x * self.image.width / self.frame_h, self.frame.y * self.image.height / self.frame_v,
self.texture.width / self.frame_h, self.texture.height / self.frame_v)
def draw(self):
draw_texture_pro(
self.texture, self.rect,
Rectangle(self.pos.x, self.pos.y, self.rect.width * self.scale, self.rect.height * self.scale),
Vector2(0, 0), 0, WHITE
)
class Animation:
def __init__(self, spritesheet, start_frame, end_frame, loop,
vertical_anim: bool=False, speed: float = 10,
reverse: bool = False):
# Variables
self.spritesheet = spritesheet
self.start_frame = start_frame
self.end_frame = end_frame
self.loop = loop
self.speed = speed
self.reverse = reverse
self.vertical_anim = vertical_anim
self.frame_attr = 'y' if self.vertical_anim else 'x'
self.initial_frame = self.end_frame if self.reverse else self.start_frame
setattr(self.spritesheet.frame, self.frame_attr, self.initial_frame)
self.current_frame = getattr(self.spritesheet.frame, self.frame_attr)
self.frame_counter = 0
def update(self):
self.animate()
self.current_frame = getattr(self.spritesheet.frame, self.frame_attr)
print(self.initial_frame)
self.spritesheet.rect.x = self.spritesheet.frame.x * (self.spritesheet.image.width / self.spritesheet.frame_h)
self.spritesheet.rect.y = self.spritesheet.frame.y * (self.spritesheet.image.height / self.spritesheet.frame_v)
def animate(self):
if self.frame_counter >= (framerate / self.speed):
step = -1 if self.reverse else 1
new_frame = self.current_frame + step
setattr(self.spritesheet.frame, self.frame_attr, new_frame)
if self.is_finished():
if self.loop:
# Reset to the correct loop start
new_frame = self.end_frame if self.reverse else self.start_frame
setattr(self.spritesheet.frame, self.frame_attr, new_frame)
else:
# Ensure it stops at the correct frame
new_frame = self.start_frame if self.reverse else self.end_frame
setattr(self.spritesheet.frame, self.frame_attr, new_frame)
self.current_frame = new_frame
self.frame_counter = 0 # Reset counter
self.frame_counter += 1
def set_speed(self, new_speed):
self.speed = new_speed
def reset(self):
setattr(self.spritesheet.frame, self.frame_attr, self.start_frame)
self.frame_counter = 0
def is_finished(self):
if self.reverse:
return self.current_frame <= self.start_frame # Stop at start when reversing
return self.current_frame >= self.end_frame
def draw(self):
self.spritesheet.draw()
def run(self):
self.update()
self.draw()
class AnimationPlayer:
def __init__(self, animation_dict, default_animation):
self.animation_dict = animation_dict
self.current_animation = self.animation_dict[default_animation]
def play(self, animation_name):
if animation_name in self.animation_dict:
self.current_animation = self.animation_dict[animation_name]
self.current_animation.reset() # Reset animation when switching
def run(self):
self.current_animation.update() # Update animation frames
self.current_animation.draw() # Draw the updated frame
Here is the settings.py:
from pyray import *
from raylib import *
import math, os, sys, json
screen_width = 1280
screen_height = 720
framerate = 60
# Useful methods
def clamp(value, min_value, max_value):
return max(min_value, min(value, max_value))
def lerp(start, end, t):
return start + (end - start) * clamp(t, 0, 1)
def is_empty(obj):
return isinstance(obj, (list, tuple, dict, set)) and len(obj) == 0
# Timer
class Timer:
def __init__(self, duration: int, repeat = False, autostart = False, func = None):
self.duration = duration
self.start_time = 0
self.active = False
self.repeat = repeat
self.func = func
if autostart:
self.activate()
def activate(self):
self.active = True
self.start_time = get_time()
def deactivate(self):
self.active = False
self.start_time = 0
if self.repeat:
self.activate()
def update(self):
if self.active:
if get_time() - self.start_time >= self.duration:
if self.func and self.start_time: self.func()
self.deactivate()
I've tried to set the start_frame to the end_frame and vice versa with this piece of code:
self.start_frame, self.end_frame = self.end_frame, self.start_frame
But it just didn't work