Ende des Unterrichts 13.02.2026 (Freitag)
This commit is contained in:
parent
1ee62cd5b2
commit
ca0c93b9d9
4 changed files with 135 additions and 4 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -217,4 +217,4 @@ __marimo__/
|
||||||
|
|
||||||
# Data
|
# Data
|
||||||
data/
|
data/
|
||||||
test.py
|
der_test.py
|
||||||
125
scripts/animation.py
Normal file
125
scripts/animation.py
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
class Animation:
|
||||||
|
def __init__(self, images, image_duration=5, loop=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 = images
|
||||||
|
self.image_duration = image_duration
|
||||||
|
self.loop = loop
|
||||||
|
self.frame = 0
|
||||||
|
self.done = False
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
"""
|
||||||
|
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):
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
pass
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
@ -13,9 +13,14 @@ class Tilemap:
|
||||||
def render(self, surface:pg.Surface, offset:tuple=(0,0)):
|
def render(self, surface:pg.Surface, offset:tuple=(0,0)):
|
||||||
for tile in self.offgrid_tiles:
|
for tile in self.offgrid_tiles:
|
||||||
surface.blit(self.game.assets[tile['type']][tile['variant']], (tile['pos'][0] - offset[0], tile['pos'][1] - offset[1]))
|
surface.blit(self.game.assets[tile['type']][tile['variant']], (tile['pos'][0] - offset[0], tile['pos'][1] - offset[1]))
|
||||||
for location in self.tilemap:
|
for x in range(offset[0] // self.tile_size, (offset[0] + surface.get_width()) // self.tile_size + 1):
|
||||||
tile = self.tilemap[location]
|
for y in range(offset[1] // self.tile_size, (offset[1] + surface.get_height()) // self.tile_size + 1):
|
||||||
surface.blit(self.game.assets[tile['type']][tile['variant']], (tile['pos'][0] * self.tile_size - offset[0], tile['pos'][1] * self.tile_size - offset[1]))
|
location_key = f"{x};{y}"
|
||||||
|
if location_key in self.tilemap:
|
||||||
|
tile = self.tilemap[location_key]
|
||||||
|
surface.blit(self.game.assets[tile['type']][tile['variant']], (tile['pos'][0] * self.tile_size - offset[0],
|
||||||
|
tile['pos'][1] * self.tile_size - offset[1]))
|
||||||
|
|
||||||
|
|
||||||
def tiles_around(self, pos):
|
def tiles_around(self, pos):
|
||||||
tiles = []
|
tiles = []
|
||||||
|
|
@ -25,6 +30,7 @@ class Tilemap:
|
||||||
if check_location in self.tilemap:
|
if check_location in self.tilemap:
|
||||||
tiles.append(self.tilemap[check_location])
|
tiles.append(self.tilemap[check_location])
|
||||||
return tiles
|
return tiles
|
||||||
|
|
||||||
def physics_rects_around(self, pos):
|
def physics_rects_around(self, pos):
|
||||||
# Erzeuge eine leere Liste für die Rechtecke
|
# Erzeuge eine leere Liste für die Rechtecke
|
||||||
rects = []
|
rects = []
|
||||||
|
|
|
||||||
0
test.py
0
test.py
Loading…
Reference in a new issue