Ninja-Jump-and-run/scripts/animation.py

129 lines
4.3 KiB
Python
Raw Normal View History

class Animation:
def __init__(self, images: list, image_duration: int = 5, loop: bool = True):
"""
Initialisiert eine Animation mit einer Liste von Bildern.
Anforderungen (damit die Tests bestehen):
- images speichern
- image_duration speichern
- loop speichern
- frame startet bei 0
- done startet bei False
"""
# TODO: Implementieren
self.images: list = images
self.image_duration: int = image_duration
self.loop: bool = loop
self.frame: int = 0
self.done: bool = False
def copy(self) -> "Animation":
"""
Erstellt eine Kopie der Animation.
Anforderungen:
- Rückgabewert ist ein neues Animation-Objekt (nicht dasselbe Objekt)
- gleiche images / image_duration / loop
- neue Animation startet wieder bei frame = 0 und done = False
"""
# TODO: Implementieren
copy_animation = Animation(self.images, self.image_duration, self.loop)
return copy_animation
def update(self) -> None:
"""
Aktualisiert die Animation um einen Frame weiter.
Anforderungen:
- Wenn loop=True:
frame wird erhöht und springt am Ende wieder auf 0
- Wenn loop=False:
frame wird erhöht, aber bleibt am Ende stehen
done wird True, sobald das letzte Bild erreicht ist (siehe Tests)
"""
# TODO: Implementieren
# SCHRITT A: Modulo (Der Loop-Trick)
# Sorgt dafür, dass wir nie über 14 hinausgehen (0 bis 14)
if self.loop:
gesamt_dauer = len(self.images) * self.image_duration # 5 * 5 = 25 Frames pro Durchlauf
self.frame = (self.frame+1) % gesamt_dauer
else:
self.frame = min(self.frame + 1, len(self.images) * self.image_duration -1)
if self.frame >= self.image_duration * (len(self.images) - 1):
self.done = True
def img(self):
"""
Gibt das aktuelle Bild der Animation zurück.
Anforderungen:
- Das aktuelle Bild hängt von frame und image_duration ab.
- Beispiel: image_duration=2
frame 0,1 -> images[0]
frame 2,3 -> images[1]
frame 4,5 -> images[2]
"""
# TODO: Implementieren
2026-03-04 15:50:44 +00:00
""" Gibt das aktuelle Bild der Animation zurück. """
return self.images[int(self.frame / self.image_duration)]
if __name__ == "__main__":
import unittest
class TestAnimation(unittest.TestCase):
def setUp(self):
self.images = ["img1", "img2", "img3"]
def test_initialization(self):
anim = Animation(self.images, image_duration=2, loop=False)
self.assertEqual(anim.images, self.images)
self.assertEqual(anim.image_duration, 2)
self.assertFalse(anim.loop)
self.assertEqual(anim.frame, 0)
self.assertFalse(anim.done)
def test_copy(self):
anim = Animation(self.images, image_duration=3, loop=False)
anim_copy = anim.copy()
self.assertIsNot(anim, anim_copy)
self.assertEqual(anim_copy.images, self.images)
self.assertEqual(anim_copy.image_duration, 3)
self.assertFalse(anim_copy.loop)
self.assertEqual(anim_copy.frame, 0)
def test_looping_update(self):
anim = Animation(self.images, image_duration=1, loop=True)
for _ in range(3):
anim.update()
# 3 Bilder * 1 Frame pro Bild = 3 Frames total -> wieder bei 0
self.assertEqual(anim.frame, 0)
def test_non_looping_update_and_done(self):
anim = Animation(self.images, image_duration=1, loop=False)
anim.update()
anim.update()
anim.update()
# Ohne Loop bleibt er beim letzten Frame (2) stehen
# und done soll True sein (siehe Logik in der Aufgabenbeschreibung)
self.assertTrue(anim.done)
self.assertEqual(anim.frame, 2)
def test_img_selection(self):
anim = Animation(self.images, image_duration=2, loop=True)
anim.update() # frame 1
self.assertEqual(anim.img(), "img1")
anim.update() # frame 2
self.assertEqual(anim.img(), "img2")
unittest.main()