#!/usr/bin/env python3 """ Animation Debug Tool ==================== Helps diagnose animation timing issues. """ import mcrfpy import sys # Track all active animations active_animations = {} animation_log = [] class AnimationTracker: """Tracks animation lifecycle for debugging""" def __init__(self, name, target, property_name, target_value, duration): self.name = name self.target = target self.property_name = property_name self.target_value = target_value self.duration = duration self.start_time = None self.animation = None def start(self): """Start the animation with tracking""" # Log the start log_entry = f"START: {self.name} - {self.property_name} to {self.target_value} over {self.duration}s" animation_log.append(log_entry) print(log_entry) # Create and start animation self.animation = mcrfpy.Animation(self.property_name, self.target_value, self.duration, "linear") self.animation.start(self.target) # Track it active_animations[self.name] = self # Set timer to check completion check_interval = 100 # ms mcrfpy.setTimer(f"check_{self.name}", self._check_complete, check_interval) def _check_complete(self, dt): """Check if animation is complete""" if self.animation and hasattr(self.animation, 'is_complete') and self.animation.is_complete: # Log completion log_entry = f"COMPLETE: {self.name}" animation_log.append(log_entry) print(log_entry) # Remove from active if self.name in active_animations: del active_animations[self.name] # Stop checking mcrfpy.delTimer(f"check_{self.name}") # Create test scene mcrfpy.createScene("anim_debug") # Simple grid grid = mcrfpy.Grid(grid_x=15, grid_y=10) for y in range(10): for x in range(15): cell = grid.at(x, y) cell.walkable = True cell.color = mcrfpy.Color(100, 100, 120) # Test entity entity = mcrfpy.Entity(5, 5, grid=grid) entity.sprite_index = 64 # UI ui = mcrfpy.sceneUI("anim_debug") ui.append(grid) grid.position = (100, 150) grid.size = (450, 300) title = mcrfpy.Caption("Animation Debug Tool", 250, 20) title.fill_color = mcrfpy.Color(255, 255, 255) ui.append(title) status = mcrfpy.Caption("Press keys to test animations", 100, 50) status.fill_color = mcrfpy.Color(200, 200, 200) ui.append(status) pos_display = mcrfpy.Caption("", 100, 70) pos_display.fill_color = mcrfpy.Color(255, 255, 100) ui.append(pos_display) active_display = mcrfpy.Caption("Active animations: 0", 100, 90) active_display.fill_color = mcrfpy.Color(100, 255, 255) ui.append(active_display) # Test scenarios def test_simultaneous(): """Test multiple animations at once (causes issues)""" print("\n=== TEST: Simultaneous Animations ===") status.text = "Testing simultaneous X and Y animations" # Start both at once anim1 = AnimationTracker("sim_x", entity, "x", 10.0, 1.0) anim2 = AnimationTracker("sim_y", entity, "y", 8.0, 1.5) anim1.start() anim2.start() def test_rapid_fire(): """Test starting new animation before previous completes""" print("\n=== TEST: Rapid Fire Animations ===") status.text = "Testing rapid fire animations (overlapping)" # Start first animation anim1 = AnimationTracker("rapid_1", entity, "x", 8.0, 2.0) anim1.start() # Start another after 500ms (before first completes) def start_second(dt): anim2 = AnimationTracker("rapid_2", entity, "x", 12.0, 1.0) anim2.start() mcrfpy.delTimer("rapid_timer") mcrfpy.setTimer("rapid_timer", start_second, 500) def test_sequential(): """Test proper sequential animations""" print("\n=== TEST: Sequential Animations ===") status.text = "Testing proper sequential animations" sequence = [ ("seq_1", "x", 8.0, 0.5), ("seq_2", "y", 7.0, 0.5), ("seq_3", "x", 6.0, 0.5), ("seq_4", "y", 5.0, 0.5), ] def run_sequence(index=0): if index >= len(sequence): print("Sequence complete!") return name, prop, value, duration = sequence[index] anim = AnimationTracker(name, entity, prop, value, duration) anim.start() # Schedule next delay = int(duration * 1000) + 100 # Add buffer mcrfpy.setTimer(f"seq_timer_{index}", lambda dt: run_sequence(index + 1), delay) run_sequence() def test_conflicting(): """Test conflicting animations on same property""" print("\n=== TEST: Conflicting Animations ===") status.text = "Testing conflicting animations (same property)" # Start animation to x=10 anim1 = AnimationTracker("conflict_1", entity, "x", 10.0, 2.0) anim1.start() # After 1 second, start conflicting animation to x=2 def start_conflict(dt): print("Starting conflicting animation!") anim2 = AnimationTracker("conflict_2", entity, "x", 2.0, 1.0) anim2.start() mcrfpy.delTimer("conflict_timer") mcrfpy.setTimer("conflict_timer", start_conflict, 1000) # Update display def update_display(dt): pos_display.text = f"Entity position: ({entity.x:.2f}, {entity.y:.2f})" active_display.text = f"Active animations: {len(active_animations)}" # Show active animation names if active_animations: names = ", ".join(active_animations.keys()) active_display.text += f" [{names}]" # Show log def show_log(): print("\n=== ANIMATION LOG ===") for entry in animation_log[-10:]: # Last 10 entries print(entry) print("===================") # Input handler def handle_input(key, state): if state != "start": return key = key.lower() if key == "q": sys.exit(0) elif key == "num1": test_simultaneous() elif key == "num2": test_rapid_fire() elif key == "num3": test_sequential() elif key == "num4": test_conflicting() elif key == "l": show_log() elif key == "r": entity.x = 5 entity.y = 5 animation_log.clear() active_animations.clear() print("Reset entity and cleared log") # Setup mcrfpy.setScene("anim_debug") mcrfpy.keypressScene(handle_input) mcrfpy.setTimer("update", update_display, 100) print("Animation Debug Tool") print("====================") print("This tool helps diagnose animation timing issues") print() print("Tests:") print(" 1 - Simultaneous X/Y (may cause issues)") print(" 2 - Rapid fire (overlapping animations)") print(" 3 - Sequential (proper chaining)") print(" 4 - Conflicting (same property)") print() print("Other keys:") print(" L - Show animation log") print(" R - Reset") print(" Q - Quit") print() print("Watch the console for animation lifecycle events")