94 lines
2.6 KiB
Python
94 lines
2.6 KiB
Python
|
|
"""Test Entity3D.animate() (issue #242)"""
|
||
|
|
import mcrfpy
|
||
|
|
import sys
|
||
|
|
|
||
|
|
errors = []
|
||
|
|
|
||
|
|
vp = mcrfpy.Viewport3D(pos=(0,0), size=(100,100))
|
||
|
|
vp.set_grid_size(16, 16)
|
||
|
|
|
||
|
|
# Test 1: Basic x animation
|
||
|
|
e = mcrfpy.Entity3D(pos=(0,0), scale=1.0)
|
||
|
|
vp.entities.append(e)
|
||
|
|
start_x = e.world_pos[0]
|
||
|
|
anim = e.animate('x', 10.0, 1.0, 'linear')
|
||
|
|
if anim is None:
|
||
|
|
errors.append("animate() should return Animation object")
|
||
|
|
for _ in range(5):
|
||
|
|
mcrfpy.step(0.25)
|
||
|
|
if abs(e.world_pos[0] - 10.0) > 0.5:
|
||
|
|
errors.append(f"x animation: expected ~10.0, got {e.world_pos[0]}")
|
||
|
|
|
||
|
|
# Test 2: Scale animation
|
||
|
|
e2 = mcrfpy.Entity3D(pos=(0,0), scale=1.0)
|
||
|
|
vp.entities.append(e2)
|
||
|
|
e2.animate('scale', 5.0, 0.5, 'linear')
|
||
|
|
for _ in range(3):
|
||
|
|
mcrfpy.step(0.25)
|
||
|
|
if abs(e2.scale - 5.0) > 0.5:
|
||
|
|
errors.append(f"scale animation: expected ~5.0, got {e2.scale}")
|
||
|
|
|
||
|
|
# Test 3: Rotation animation
|
||
|
|
e3 = mcrfpy.Entity3D(pos=(0,0), scale=1.0)
|
||
|
|
vp.entities.append(e3)
|
||
|
|
e3.animate('rotation', 90.0, 0.5, 'easeInOut')
|
||
|
|
for _ in range(3):
|
||
|
|
mcrfpy.step(0.25)
|
||
|
|
if abs(e3.rotation - 90.0) > 0.5:
|
||
|
|
errors.append(f"rotation animation: expected ~90.0, got {e3.rotation}")
|
||
|
|
|
||
|
|
# Test 4: Delta animation
|
||
|
|
e4 = mcrfpy.Entity3D(pos=(3,3), scale=1.0)
|
||
|
|
vp.entities.append(e4)
|
||
|
|
start_x = e4.world_pos[0]
|
||
|
|
e4.animate('x', 2.0, 0.5, 'linear', delta=True)
|
||
|
|
for _ in range(3):
|
||
|
|
mcrfpy.step(0.25)
|
||
|
|
expected = start_x + 2.0
|
||
|
|
if abs(e4.world_pos[0] - expected) > 0.5:
|
||
|
|
errors.append(f"delta animation: expected ~{expected}, got {e4.world_pos[0]}")
|
||
|
|
|
||
|
|
# Test 5: Invalid property raises ValueError
|
||
|
|
try:
|
||
|
|
e.animate('nonexistent', 1.0, 1.0, 'linear')
|
||
|
|
errors.append("Invalid property should raise ValueError")
|
||
|
|
except ValueError:
|
||
|
|
pass
|
||
|
|
|
||
|
|
# Test 6: Invalid target type raises TypeError
|
||
|
|
try:
|
||
|
|
e.animate('x', "not_a_number", 1.0, 'linear')
|
||
|
|
errors.append("String target should raise TypeError")
|
||
|
|
except TypeError:
|
||
|
|
pass
|
||
|
|
|
||
|
|
# Test 7: Callback
|
||
|
|
callback_called = [False]
|
||
|
|
def on_complete(target, prop, value):
|
||
|
|
callback_called[0] = True
|
||
|
|
|
||
|
|
e5 = mcrfpy.Entity3D(pos=(0,0), scale=1.0)
|
||
|
|
vp.entities.append(e5)
|
||
|
|
e5.animate('x', 5.0, 0.25, 'linear', callback=on_complete)
|
||
|
|
for _ in range(3):
|
||
|
|
mcrfpy.step(0.15)
|
||
|
|
if not callback_called[0]:
|
||
|
|
errors.append("Animation callback was not called")
|
||
|
|
|
||
|
|
# Test 8: Easing enum
|
||
|
|
e6 = mcrfpy.Entity3D(pos=(0,0), scale=1.0)
|
||
|
|
vp.entities.append(e6)
|
||
|
|
try:
|
||
|
|
e6.animate('x', 5.0, 1.0, mcrfpy.Easing.EASE_IN_OUT)
|
||
|
|
except Exception as ex:
|
||
|
|
errors.append(f"Easing enum should work: {ex}")
|
||
|
|
for _ in range(5):
|
||
|
|
mcrfpy.step(0.25)
|
||
|
|
|
||
|
|
if errors:
|
||
|
|
for err in errors:
|
||
|
|
print(f"FAIL: {err}", file=sys.stderr)
|
||
|
|
sys.exit(1)
|
||
|
|
else:
|
||
|
|
print("PASS: Entity3D.animate() (issue #242)", file=sys.stderr)
|
||
|
|
sys.exit(0)
|