Timer overhaul: update tests

This commit is contained in:
John McCardle 2026-01-03 22:44:53 -05:00
commit cec76b63dc
78 changed files with 521 additions and 495 deletions

View file

@ -97,7 +97,7 @@ def handle_key(key, state):
benchmark.on_key = handle_key benchmark.on_key = handle_key
# Update entity positions # Update entity positions
def update_entities(ms): def update_entities(timer, ms):
dt = ms / 1000.0 # Convert to seconds dt = ms / 1000.0 # Convert to seconds
for entity in entities: for entity in entities:
@ -119,13 +119,13 @@ def update_entities(ms):
entity.y = new_y entity.y = new_y
# Run movement update every frame (16ms) # Run movement update every frame (16ms)
mcrfpy.setTimer("movement", update_entities, 16) movement_timer = mcrfpy.Timer("movement", update_entities, 16)
# Benchmark statistics # Benchmark statistics
frame_count = 0 frame_count = 0
start_time = None start_time = None
def benchmark_timer(ms): def benchmark_callback(timer, ms):
global frame_count, start_time global frame_count, start_time
if start_time is None: if start_time is None:
@ -152,4 +152,4 @@ def benchmark_timer(ms):
print("=" * 60) print("=" * 60)
# Don't exit - let user review # Don't exit - let user review
mcrfpy.setTimer("benchmark", benchmark_timer, 100) benchmark_timer = mcrfpy.Timer("benchmark", benchmark_callback, 100)

View file

@ -31,7 +31,7 @@ frame_count = 0
metrics_samples = [] metrics_samples = []
def collect_metrics(runtime): def collect_metrics(timer, runtime):
"""Timer callback to collect metrics each frame.""" """Timer callback to collect metrics each frame."""
global frame_count, metrics_samples global frame_count, metrics_samples
@ -65,9 +65,9 @@ def collect_metrics(runtime):
def finish_scenario(): def finish_scenario():
"""Calculate statistics and store results for current scenario.""" """Calculate statistics and store results for current scenario."""
global results, current_scenario, metrics_samples global results, current_scenario, metrics_samples, benchmark_timer
mcrfpy.delTimer("benchmark_collect") benchmark_timer.stop()
if not metrics_samples: if not metrics_samples:
print(f" WARNING: No samples collected for {current_scenario}") print(f" WARNING: No samples collected for {current_scenario}")
@ -149,7 +149,8 @@ def run_next_scenario():
scenarios[next_idx][1]() scenarios[next_idx][1]()
# Start collection timer (runs every frame) # Start collection timer (runs every frame)
mcrfpy.setTimer("benchmark_collect", collect_metrics, 1) global benchmark_timer
benchmark_timer = mcrfpy.Timer("benchmark_collect", collect_metrics, 1)
# ============================================================================ # ============================================================================

View file

@ -427,7 +427,7 @@ def print_analysis():
print(f" Note: This overhead is acceptable given query speedups") print(f" Note: This overhead is acceptable given query speedups")
def run_benchmarks(runtime=None): def run_benchmarks(timer=None, runtime=None):
"""Main benchmark runner.""" """Main benchmark runner."""
global results global results
@ -458,4 +458,4 @@ if __name__ == "__main__":
if "--headless" in sys.argv or True: # Always run immediately for benchmarks if "--headless" in sys.argv or True: # Always run immediately for benchmarks
run_benchmarks() run_benchmarks()
else: else:
mcrfpy.setTimer("run_bench", run_benchmarks, 100) bench_timer = mcrfpy.Timer("run_bench", run_benchmarks, 100, once=True)

View file

@ -34,7 +34,7 @@ frame_count = 0
test_results = {} # Store filenames for each test test_results = {} # Store filenames for each test
def run_test_phase(runtime): def run_test_phase(timer, runtime):
"""Run through warmup and measurement phases.""" """Run through warmup and measurement phases."""
global frame_count global frame_count
@ -51,7 +51,7 @@ def run_test_phase(runtime):
test_results[current_test] = filename test_results[current_test] = filename
print(f" {current_test}: saved to {filename}") print(f" {current_test}: saved to {filename}")
mcrfpy.delTimer("test_phase") timer.stop()
run_next_test() run_next_test()
@ -90,7 +90,8 @@ def run_next_test():
print(f"\n[{next_idx + 1}/{len(tests)}] Running: {current_test}") print(f"\n[{next_idx + 1}/{len(tests)}] Running: {current_test}")
tests[next_idx][1]() tests[next_idx][1]()
mcrfpy.setTimer("test_phase", run_test_phase, 1) global test_phase_timer
test_phase_timer = mcrfpy.Timer("test_phase", run_test_phase, 1)
# ============================================================================ # ============================================================================
@ -130,14 +131,15 @@ def setup_base_layer_modified():
# Timer to modify one cell per frame (triggers dirty flag each frame) # Timer to modify one cell per frame (triggers dirty flag each frame)
mod_counter = [0] mod_counter = [0]
def modify_cell(runtime): def modify_cell(timer, runtime):
x = mod_counter[0] % GRID_SIZE x = mod_counter[0] % GRID_SIZE
y = (mod_counter[0] // GRID_SIZE) % GRID_SIZE y = (mod_counter[0] // GRID_SIZE) % GRID_SIZE
layer.set(x, y, mcrfpy.Color(255, 0, 0, 255)) layer.set(x, y, mcrfpy.Color(255, 0, 0, 255))
mod_counter[0] += 1 mod_counter[0] += 1
test_base_mod.activate() test_base_mod.activate()
mcrfpy.setTimer("modify", modify_cell, 1) global modify_timer
modify_timer = mcrfpy.Timer("modify", modify_cell, 1)
def setup_color_layer_static(): def setup_color_layer_static():
@ -170,14 +172,15 @@ def setup_color_layer_modified():
# Timer to modify one cell per frame - triggers re-render # Timer to modify one cell per frame - triggers re-render
mod_counter = [0] mod_counter = [0]
def modify_cell(runtime): def modify_cell(timer, runtime):
x = mod_counter[0] % GRID_SIZE x = mod_counter[0] % GRID_SIZE
y = (mod_counter[0] // GRID_SIZE) % GRID_SIZE y = (mod_counter[0] // GRID_SIZE) % GRID_SIZE
layer.set(x, y, mcrfpy.Color(255, 0, 0, 255)) layer.set(x, y, mcrfpy.Color(255, 0, 0, 255))
mod_counter[0] += 1 mod_counter[0] += 1
test_color_mod.activate() test_color_mod.activate()
mcrfpy.setTimer("modify", modify_cell, 1) global modify_timer
modify_timer = mcrfpy.Timer("modify", modify_cell, 1)
def setup_tile_layer_static(): def setup_tile_layer_static():
@ -222,7 +225,7 @@ def setup_tile_layer_modified():
# Timer to modify one cell per frame # Timer to modify one cell per frame
mod_counter = [0] mod_counter = [0]
def modify_cell(runtime): def modify_cell(timer, runtime):
if layer: if layer:
x = mod_counter[0] % GRID_SIZE x = mod_counter[0] % GRID_SIZE
y = (mod_counter[0] // GRID_SIZE) % GRID_SIZE y = (mod_counter[0] // GRID_SIZE) % GRID_SIZE
@ -230,7 +233,8 @@ def setup_tile_layer_modified():
mod_counter[0] += 1 mod_counter[0] += 1
test_tile_mod.activate() test_tile_mod.activate()
mcrfpy.setTimer("modify", modify_cell, 1) global modify_timer
modify_timer = mcrfpy.Timer("modify", modify_cell, 1)
def setup_multi_layer_static(): def setup_multi_layer_static():

View file

@ -31,7 +31,7 @@ class StressTestRunner:
def add_test(self, name, setup_fn, description=""): def add_test(self, name, setup_fn, description=""):
self.tests.append({'name': name, 'setup': setup_fn, 'description': description}) self.tests.append({'name': name, 'setup': setup_fn, 'description': description})
def tick(self, runtime): def tick(self, timer, runtime):
"""Single timer callback that manages all test flow""" """Single timer callback that manages all test flow"""
self.frames_counted += 1 self.frames_counted += 1
@ -103,7 +103,7 @@ class StressTestRunner:
self.results[test['name']] = {'error': str(e)} self.results[test['name']] = {'error': str(e)}
def finish_suite(self): def finish_suite(self):
mcrfpy.delTimer("tick") self.tick_timer.stop()
print("\n" + "="*50) print("\n" + "="*50)
print("STRESS TEST COMPLETE") print("STRESS TEST COMPLETE")
@ -137,7 +137,7 @@ class StressTestRunner:
ui = init.children ui = init.children
ui.append(mcrfpy.Frame(pos=(0,0), size=(10,10))) # Required for timer to fire ui.append(mcrfpy.Frame(pos=(0,0), size=(10,10))) # Required for timer to fire
init.activate() init.activate()
mcrfpy.setTimer("tick", self.tick, TIMER_INTERVAL_MS) self.tick_timer = mcrfpy.Timer("tick", self.tick, TIMER_INTERVAL_MS)
# ============================================================================= # =============================================================================

View file

@ -6,7 +6,7 @@ import mcrfpy
import sys import sys
import time import time
def run_test(runtime): def run_test(timer, runtime):
print("=" * 60) print("=" * 60)
print("FOV Isolation Test - Is TCOD slow, or is it the Python wrapper?") print("FOV Isolation Test - Is TCOD slow, or is it the Python wrapper?")
print("=" * 60) print("=" * 60)
@ -96,4 +96,4 @@ def run_test(runtime):
init = mcrfpy.Scene("init") init = mcrfpy.Scene("init")
init.activate() init.activate()
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -134,7 +134,7 @@ init = mcrfpy.Scene("init")
init.activate() init.activate()
# Use a timer to let the engine initialize # Use a timer to let the engine initialize
def run_benchmark(runtime): def run_benchmark(timer, runtime):
main() main()
mcrfpy.setTimer("bench", run_benchmark, 100) bench_timer = mcrfpy.Timer("bench", run_benchmark, 100, once=True)

View file

@ -114,7 +114,7 @@ class DemoRunner:
self.current_index = 0 self.current_index = 0
self.render_wait = 0 self.render_wait = 0
def screenshot_cycle(runtime): def screenshot_cycle(timer, runtime):
if self.render_wait == 0: if self.render_wait == 0:
# Set scene and wait for render # Set scene and wait for render
if self.current_index >= len(self.screens): if self.current_index >= len(self.screens):
@ -139,7 +139,7 @@ class DemoRunner:
print("Done!") print("Done!")
sys.exit(0) sys.exit(0)
mcrfpy.setTimer("screenshot", screenshot_cycle, 50) self.screenshot_timer = mcrfpy.Timer("screenshot", screenshot_cycle, 50)
def run_interactive(self): def run_interactive(self):
"""Run in interactive mode with menu.""" """Run in interactive mode with menu."""

View file

@ -126,9 +126,10 @@ def setup_scene():
patrol_demo.on_key = on_keypress patrol_demo.on_key = on_keypress
# Start patrol timer # Start patrol timer
mcrfpy.setTimer("patrol", patrol_step, move_timer_ms) global patrol_timer
patrol_timer = mcrfpy.Timer("patrol", patrol_step, move_timer_ms)
def patrol_step(runtime): def patrol_step(timer, runtime):
"""Move entity one step toward current waypoint""" """Move entity one step toward current waypoint"""
global current_waypoint, patrol_paused global current_waypoint, patrol_paused

View file

@ -784,12 +784,12 @@ def run_demo():
demo_state = create_demo_scene() demo_state = create_demo_scene()
# Set up exit timer for headless testing # Set up exit timer for headless testing
def check_exit(dt): def check_exit(timer, dt):
# In headless mode, exit after a short delay # In headless mode, exit after a short delay
# In interactive mode, this won't trigger # In interactive mode, this won't trigger
pass pass
# mcrfpy.setTimer("demo_check", check_exit, 100) # check_exit_timer = mcrfpy.Timer("demo_check", check_exit, 100)
# Run if executed directly # Run if executed directly
@ -801,8 +801,8 @@ if __name__ == "__main__":
# If --screenshot flag, take a screenshot and exit # If --screenshot flag, take a screenshot and exit
if "--screenshot" in sys.argv or len(sys.argv) > 1: if "--screenshot" in sys.argv or len(sys.argv) > 1:
def take_screenshot(dt): def take_screenshot(timer, dt):
automation.screenshot("focus_demo_screenshot.png") automation.screenshot("focus_demo_screenshot.png")
print("Screenshot saved: focus_demo_screenshot.png") print("Screenshot saved: focus_demo_screenshot.png")
sys.exit(0) sys.exit(0)
mcrfpy.setTimer("screenshot", take_screenshot, 200) screenshot_timer = mcrfpy.Timer("screenshot", take_screenshot, 200, once=True)

View file

@ -135,7 +135,7 @@ class GeometryDemoRunner:
self.current_index = 0 self.current_index = 0
self.render_wait = 0 self.render_wait = 0
def screenshot_cycle(runtime): def screenshot_cycle(timer, runtime):
if self.render_wait == 0: if self.render_wait == 0:
if self.current_index >= len(self.screens): if self.current_index >= len(self.screens):
print("Done!") print("Done!")
@ -162,7 +162,7 @@ class GeometryDemoRunner:
print("Done!") print("Done!")
sys.exit(0) sys.exit(0)
mcrfpy.setTimer("screenshot", screenshot_cycle, 100) self.screenshot_timer = mcrfpy.Timer("screenshot", screenshot_cycle, 100)
def run_interactive(self): def run_interactive(self):
"""Run in interactive mode with menu.""" """Run in interactive mode with menu."""

View file

@ -46,17 +46,19 @@ class GeometryDemoScreen:
def cleanup(self): def cleanup(self):
"""Clean up timers when leaving screen.""" """Clean up timers when leaving screen."""
for timer_name in self.timers: for timer in self.timers:
try: try:
mcrfpy.delTimer(timer_name) timer.stop()
except: except:
pass pass
def restart_timers(self): def restart_timers(self):
"""Re-register timers after cleanup.""" """Re-register timers after cleanup."""
self.timers = [] # Clear old timer references
for name, callback, interval in self._timer_configs: for name, callback, interval in self._timer_configs:
try: try:
mcrfpy.setTimer(name, callback, interval) timer = mcrfpy.Timer(name, callback, interval)
self.timers.append(timer)
except Exception as e: except Exception as e:
print(f"Timer restart failed: {e}") print(f"Timer restart failed: {e}")
@ -111,6 +113,6 @@ class GeometryDemoScreen:
if callback is None: if callback is None:
print(f"Warning: Timer '{name}' callback is None, skipping") print(f"Warning: Timer '{name}' callback is None, skipping")
return return
mcrfpy.setTimer(name, callback, interval) timer = mcrfpy.Timer(name, callback, interval)
self.timers.append(name) self.timers.append(timer)
self._timer_configs.append((name, callback, interval)) self._timer_configs.append((name, callback, interval))

View file

@ -269,7 +269,7 @@ class PathfindingAnimatedDemo(GeometryDemoScreen):
self.dist_label.fill_color = mcrfpy.Color(150, 150, 150) self.dist_label.fill_color = mcrfpy.Color(150, 150, 150)
self.ui.append(self.dist_label) self.ui.append(self.dist_label)
def _tick(self, runtime): def _tick(self, timer, runtime):
"""Advance one turn.""" """Advance one turn."""
self.current_time += 1 self.current_time += 1
self.time_label.text = f"Turn: {self.current_time}" self.time_label.text = f"Turn: {self.current_time}"

View file

@ -255,7 +255,7 @@ class SolarSystemDemo(GeometryDemoScreen):
self.ui.append(moon_path) self.ui.append(moon_path)
self.orbit_rings[moon.name + "_path"] = moon_path self.orbit_rings[moon.name + "_path"] = moon_path
def _tick(self, runtime): def _tick(self, timer, runtime):
"""Advance time by one turn and update planet positions.""" """Advance time by one turn and update planet positions."""
self.current_time += 1 self.current_time += 1

View file

@ -266,7 +266,7 @@ def handle_keypress(scene_name, keycode):
sys.exit(0) sys.exit(0)
# Timer callback for animation # Timer callback for animation
def update_animation(dt): def update_animation(timer, dt):
"""Update animation state""" """Update animation state"""
animate_movement(dt / 1000.0) # Convert ms to seconds animate_movement(dt / 1000.0) # Convert ms to seconds
@ -335,7 +335,7 @@ for i, entity in enumerate(entities):
dijkstra_enhanced.on_key = handle_keypress dijkstra_enhanced.on_key = handle_keypress
# Set up animation timer (60 FPS) # Set up animation timer (60 FPS)
mcrfpy.setTimer("animation", update_animation, 16) animation_timer = mcrfpy.Timer("animation", update_animation, 16)
# Show the scene # Show the scene
dijkstra_enhanced.activate() dijkstra_enhanced.activate()

View file

@ -88,11 +88,11 @@ def test_dijkstra(grid, entities):
return results return results
def run_test(runtime): def run_test(timer, runtime):
"""Timer callback to run tests and take screenshot""" """Timer callback to run tests and take screenshot"""
# Run pathfinding tests # Run pathfinding tests
results = test_dijkstra(grid, entities) results = test_dijkstra(grid, entities)
# Update display with results # Update display with results
y_pos = 380 y_pos = 380
for result in results: for result in results:
@ -100,9 +100,9 @@ def run_test(runtime):
caption.fill_color = mcrfpy.Color(200, 200, 200) caption.fill_color = mcrfpy.Color(200, 200, 200)
ui.append(caption) ui.append(caption)
y_pos += 20 y_pos += 20
# Take screenshot # Take screenshot (one-shot timer)
mcrfpy.setTimer("screenshot", lambda rt: take_screenshot(), 500) screenshot_timer = mcrfpy.Timer("screenshot", lambda t, rt: take_screenshot(), 500, once=True)
def take_screenshot(): def take_screenshot():
"""Take screenshot and exit""" """Take screenshot and exit"""
@ -140,7 +140,7 @@ ui.append(legend)
# Set scene # Set scene
dijkstra_test.activate() dijkstra_test.activate()
# Run test after scene loads # Run test after scene loads (one-shot timer)
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)
print("Running Dijkstra tests...") print("Running Dijkstra tests...")

View file

@ -9,7 +9,7 @@ This test verifies that:
import mcrfpy import mcrfpy
import sys import sys
def timer_that_raises(runtime): def timer_that_raises(timer, runtime):
"""A timer callback that raises an exception""" """A timer callback that raises an exception"""
raise ValueError("Intentional test exception") raise ValueError("Intentional test exception")
@ -17,8 +17,8 @@ def timer_that_raises(runtime):
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule the timer - it will fire after 50ms # Schedule the timer - it will fire after 50ms (one-shot timer)
mcrfpy.setTimer("raise_exception", timer_that_raises, 50) exception_timer = mcrfpy.Timer("raise_exception", timer_that_raises, 50, once=True)
# This test expects: # This test expects:
# - Default behavior: exit with code 1 after first exception # - Default behavior: exit with code 1 after first exception

View file

@ -158,7 +158,7 @@ def test_edge_cases():
print(" Edge cases: PASS") print(" Edge cases: PASS")
return True return True
def run_test(runtime): def run_test(timer, runtime):
"""Timer callback to run tests after scene is active""" """Timer callback to run tests after scene is active"""
results = [] results = []
@ -185,4 +185,4 @@ if __name__ == "__main__":
test.activate() test.activate()
# Run tests after scene is active # Run tests after scene is active
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -14,7 +14,7 @@ import mcrfpy
import sys import sys
import time import time
def run_test(runtime): def run_test(timer, runtime):
print("=" * 60) print("=" * 60)
print("Issue #146 Regression Test: compute_fov() returns None") print("Issue #146 Regression Test: compute_fov() returns None")
print("=" * 60) print("=" * 60)
@ -111,4 +111,4 @@ def run_test(runtime):
# Initialize and run # Initialize and run
init = mcrfpy.Scene("init") init = mcrfpy.Scene("init")
init.activate() init.activate()
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -11,7 +11,7 @@ Tests:
import mcrfpy import mcrfpy
import sys import sys
def run_test(runtime): def run_test(timer, runtime):
print("=" * 60) print("=" * 60)
print("Issue #147 Regression Test: Dynamic Layer System for Grid") print("Issue #147 Regression Test: Dynamic Layer System for Grid")
print("=" * 60) print("=" * 60)
@ -190,4 +190,4 @@ def run_test(runtime):
# Initialize and run # Initialize and run
init = mcrfpy.Scene("init") init = mcrfpy.Scene("init")
init.activate() init.activate()
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -14,7 +14,7 @@ import mcrfpy
import sys import sys
import time import time
def run_test(runtime): def run_test(timer, runtime):
print("=" * 60) print("=" * 60)
print("Issue #148 Regression Test: Layer Dirty Flags and Caching") print("Issue #148 Regression Test: Layer Dirty Flags and Caching")
print("=" * 60) print("=" * 60)
@ -154,4 +154,4 @@ def run_test(runtime):
# Initialize and run # Initialize and run
init = mcrfpy.Scene("init") init = mcrfpy.Scene("init")
init.activate() init.activate()
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -17,7 +17,7 @@ class CustomEntity(mcrfpy.Entity):
def custom_method(self): def custom_method(self):
return "Custom method called" return "Custom method called"
def run_test(runtime): def run_test(timer, runtime):
"""Test that derived entity classes maintain their type in collections""" """Test that derived entity classes maintain their type in collections"""
try: try:
# Create a grid # Create a grid
@ -85,4 +85,4 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test to run after game loop starts # Schedule test to run after game loop starts
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -149,7 +149,7 @@ def test_color_properties():
return tests_passed == tests_total return tests_passed == tests_total
def run_test(runtime): def run_test(timer, runtime):
"""Timer callback to run the test""" """Timer callback to run the test"""
try: try:
success = test_color_properties() success = test_color_properties()
@ -167,4 +167,4 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test to run after game loop starts # Schedule test to run after game loop starts
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -183,7 +183,7 @@ def test_property_introspection():
return tests_passed, tests_total return tests_passed, tests_total
def run_test(runtime): def run_test(timer, runtime):
"""Timer callback to run the test""" """Timer callback to run the test"""
try: try:
print("=== Testing Texture and Font Properties (Issue #99) ===\n") print("=== Testing Texture and Font Properties (Issue #99) ===\n")
@ -221,4 +221,4 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test to run after game loop starts # Schedule test to run after game loop starts
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -7,7 +7,7 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
import sys import sys
def run_test(runtime): def run_test(timer, runtime):
"""Test RenderTexture resizing""" """Test RenderTexture resizing"""
print("Testing Issue #9: RenderTexture resize (minimal)") print("Testing Issue #9: RenderTexture resize (minimal)")
@ -64,4 +64,4 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test # Schedule test
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -209,7 +209,7 @@ def test_rendertexture_resize():
print(f"\nScreenshots saved to /tmp/issue_9_*.png") print(f"\nScreenshots saved to /tmp/issue_9_*.png")
def run_test(runtime): def run_test(timer, runtime):
"""Timer callback to run the test""" """Timer callback to run the test"""
try: try:
test_rendertexture_resize() test_rendertexture_resize()
@ -226,4 +226,4 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test to run after game loop starts # Schedule test to run after game loop starts
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -9,7 +9,7 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
import sys import sys
def run_test(runtime): def run_test(timer, runtime):
"""Test that UIGrid properly handles resizing""" """Test that UIGrid properly handles resizing"""
try: try:
# Create a grid with initial size # Create a grid with initial size
@ -86,4 +86,4 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test to run after game loop starts # Schedule test to run after game loop starts
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -64,7 +64,7 @@ def demonstrate_solution():
} }
""") """)
def run_test(runtime): def run_test(timer, runtime):
"""Timer callback""" """Timer callback"""
try: try:
demonstrate_solution() demonstrate_solution()
@ -74,10 +74,10 @@ def run_test(runtime):
print(f"\nError: {e}") print(f"\nError: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
sys.exit(0) sys.exit(0)
# Set up scene and run # Set up scene and run
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
test.activate() test.activate()
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -4,43 +4,44 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
from datetime import datetime from datetime import datetime
def run_automation_tests(): def run_automation_tests(timer, runtime):
"""This runs AFTER the game loop has started and rendered frames""" """This runs AFTER the game loop has started and rendered frames"""
print("\n=== Automation Test Running (1 second after start) ===") print("\n=== Automation Test Running (1 second after start) ===")
# NOW we can take screenshots that will show content! # NOW we can take screenshots that will show content!
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"WORKING_screenshot_{timestamp}.png" filename = f"WORKING_screenshot_{timestamp}.png"
# Take screenshot - this should now show our red frame # Take screenshot - this should now show our red frame
result = automation.screenshot(filename) result = automation.screenshot(filename)
print(f"Screenshot taken: {filename} - Result: {result}") print(f"Screenshot taken: {filename} - Result: {result}")
# Test clicking on the frame # Test clicking on the frame
automation.click(200, 200) # Click in center of red frame automation.click(200, 200) # Click in center of red frame
# Test keyboard input # Test keyboard input
automation.typewrite("Hello from timer callback!") automation.typewrite("Hello from timer callback!")
# Take another screenshot to show any changes # Take another screenshot to show any changes
filename2 = f"WORKING_screenshot_after_click_{timestamp}.png" filename2 = f"WORKING_screenshot_after_click_{timestamp}.png"
automation.screenshot(filename2) automation.screenshot(filename2)
print(f"Second screenshot: {filename2}") print(f"Second screenshot: {filename2}")
print("Test completed successfully!") print("Test completed successfully!")
print("\nThis works because:") print("\nThis works because:")
print("1. The game loop has been running for 1 second") print("1. The game loop has been running for 1 second")
print("2. The scene has been rendered multiple times") print("2. The scene has been rendered multiple times")
print("3. The RenderTexture now contains actual rendered content") print("3. The RenderTexture now contains actual rendered content")
# Cancel this timer so it doesn't repeat # Cancel this timer so it doesn't repeat
mcrfpy.delTimer("automation_test") timer.stop()
# Optional: exit after a moment # Optional: exit after a moment
def exit_game(): def exit_game(t, r):
print("Exiting...") print("Exiting...")
mcrfpy.exit() mcrfpy.exit()
mcrfpy.setTimer("exit", exit_game, 500) # Exit 500ms later global exit_timer
exit_timer = mcrfpy.Timer("exit", exit_game, 500, once=True)
# This code runs during --exec script execution # This code runs during --exec script execution
print("=== Setting Up Test Scene ===") print("=== Setting Up Test Scene ===")
@ -73,7 +74,7 @@ frame.on_click = frame_clicked
print("Scene setup complete. Setting timer for automation tests...") print("Scene setup complete. Setting timer for automation tests...")
# THIS IS THE KEY: Set timer to run AFTER the game loop starts # THIS IS THE KEY: Set timer to run AFTER the game loop starts
mcrfpy.setTimer("automation_test", run_automation_tests, 1000) automation_test_timer = mcrfpy.Timer("automation_test", run_automation_tests, 1000, once=True)
print("Timer set. Game loop will start after this script completes.") print("Timer set. Game loop will start after this script completes.")
print("Automation tests will run 1 second later when content is visible.") print("Automation tests will run 1 second later when content is visible.")

View file

@ -5,7 +5,7 @@ import sys
import os import os
import json import json
def run_test(runtime): def run_test(timer, runtime):
"""Timer callback to test benchmark logging""" """Timer callback to test benchmark logging"""
# Stop the benchmark and get filename # Stop the benchmark and get filename
try: try:
@ -132,4 +132,4 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test completion after ~100ms (to capture some frames) # Schedule test completion after ~100ms (to capture some frames)
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)

View file

@ -68,13 +68,13 @@ print("\nTest 7: Path after potential sync")
path4 = grid.compute_astar_path(0, 0, 5, 5) path4 = grid.compute_astar_path(0, 0, 5, 5)
print(f" A* path: {path4}") print(f" A* path: {path4}")
def timer_cb(dt): def timer_cb(timer, runtime):
sys.exit(0) sys.exit(0)
# Quick UI setup # Quick UI setup
ui = debug.children ui = debug.children
ui.append(grid) ui.append(grid)
debug.activate() debug.activate()
mcrfpy.setTimer("exit", timer_cb, 100) exit_timer = mcrfpy.Timer("exit", timer_cb, 100, once=True)
print("\nStarting timer...") print("\nStarting timer...")

View file

@ -404,48 +404,50 @@ screenshots = [
("combined_example", "ui_combined_example.png") ("combined_example", "ui_combined_example.png")
] ]
def take_screenshots(runtime): def take_screenshots(timer, runtime):
"""Timer callback to take screenshots sequentially""" """Timer callback to take screenshots sequentially"""
global current_screenshot global current_screenshot
if current_screenshot >= len(screenshots): if current_screenshot >= len(screenshots):
print("\nAll screenshots captured successfully!") print("\nAll screenshots captured successfully!")
print(f"Screenshots saved to: {output_dir}/") print(f"Screenshots saved to: {output_dir}/")
mcrfpy.exit() mcrfpy.exit()
return return
scene_name, filename = screenshots[current_screenshot] scene_name, filename = screenshots[current_screenshot]
# Switch to the scene # Switch to the scene
mcrfpy.current_scene = scene_name mcrfpy.current_scene = scene_name
# Take screenshot after a short delay to ensure rendering # Take screenshot after a short delay to ensure rendering
def capture(): def capture(t, r):
global current_screenshot global current_screenshot
full_path = f"{output_dir}/{filename}" full_path = f"{output_dir}/{filename}"
result = automation.screenshot(full_path) result = automation.screenshot(full_path)
print(f"Screenshot {current_screenshot + 1}/{len(screenshots)}: {filename} - {'Success' if result else 'Failed'}") print(f"Screenshot {current_screenshot + 1}/{len(screenshots)}: {filename} - {'Success' if result else 'Failed'}")
current_screenshot += 1 current_screenshot += 1
# Schedule next screenshot # Schedule next screenshot
mcrfpy.setTimer("next_screenshot", take_screenshots, 200) global next_screenshot_timer
next_screenshot_timer = mcrfpy.Timer("next_screenshot", take_screenshots, 200, once=True)
# Give scene time to render # Give scene time to render
mcrfpy.setTimer("capture", lambda r: capture(), 100) global capture_timer
capture_timer = mcrfpy.Timer("capture", capture, 100, once=True)
# Start with the first scene # Start with the first scene
caption_example.activate() caption_example.activate()
# Start the screenshot process # Start the screenshot process
print(f"\nStarting screenshot capture of {len(screenshots)} scenes...") print(f"\nStarting screenshot capture of {len(screenshots)} scenes...")
mcrfpy.setTimer("start", take_screenshots, 500) start_timer = mcrfpy.Timer("start", take_screenshots, 500, once=True)
# Safety timeout # Safety timeout
def safety_exit(runtime): def safety_exit(timer, runtime):
print("\nERROR: Safety timeout reached! Exiting...") print("\nERROR: Safety timeout reached! Exiting...")
mcrfpy.exit() mcrfpy.exit()
mcrfpy.setTimer("safety", safety_exit, 30000) safety_timer = mcrfpy.Timer("safety", safety_exit, 30000, once=True)
print("Setup complete. Game loop starting...") print("Setup complete. Game loop starting...")

View file

@ -5,13 +5,13 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
import sys import sys
def capture_grid(runtime): def capture_grid(timer, runtime):
"""Capture grid example after render loop starts""" """Capture grid example after render loop starts"""
# Take screenshot # Take screenshot
automation.screenshot("mcrogueface.github.io/images/ui_grid_example.png") automation.screenshot("mcrogueface.github.io/images/ui_grid_example.png")
print("Grid screenshot saved!") print("Grid screenshot saved!")
# Exit after capturing # Exit after capturing
sys.exit(0) sys.exit(0)
@ -112,4 +112,4 @@ ui.append(info)
grid.activate() grid.activate()
# Set timer to capture after rendering starts # Set timer to capture after rendering starts
mcrfpy.setTimer("capture", capture_grid, 100) capture_timer = mcrfpy.Timer("capture", capture_grid, 100, once=True)

View file

@ -5,13 +5,13 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
import sys import sys
def capture_sprites(runtime): def capture_sprites(timer, runtime):
"""Capture sprite examples after render loop starts""" """Capture sprite examples after render loop starts"""
# Take screenshot # Take screenshot
automation.screenshot("mcrogueface.github.io/images/ui_sprite_example.png") automation.screenshot("mcrogueface.github.io/images/ui_sprite_example.png")
print("Sprite screenshot saved!") print("Sprite screenshot saved!")
# Exit after capturing # Exit after capturing
sys.exit(0) sys.exit(0)
@ -157,4 +157,4 @@ ui.append(scale_label)
sprites.activate() sprites.activate()
# Set timer to capture after rendering starts # Set timer to capture after rendering starts
mcrfpy.setTimer("capture", capture_sprites, 100) capture_timer = mcrfpy.Timer("capture", capture_sprites, 100, once=True)

View file

@ -3,7 +3,7 @@
Test for keypressScene() validation - should reject non-callable arguments Test for keypressScene() validation - should reject non-callable arguments
""" """
def test_keypress_validation(timer_name): def test_keypress_validation(timer, runtime):
"""Test that keypressScene validates its argument is callable""" """Test that keypressScene validates its argument is callable"""
import mcrfpy import mcrfpy
import sys import sys
@ -90,4 +90,4 @@ def test_keypress_validation(timer_name):
# Execute the test after a short delay # Execute the test after a short delay
import mcrfpy import mcrfpy
mcrfpy.setTimer("test", test_keypress_validation, 100) test_timer = mcrfpy.Timer("test", test_keypress_validation, 100, once=True)

View file

@ -6,17 +6,17 @@ from mcrfpy import automation
import sys import sys
import time import time
def take_screenshot(runtime): def take_screenshot(timer, runtime):
"""Take screenshot after render starts""" """Take screenshot after render starts"""
print(f"Timer callback fired at runtime: {runtime}") print(f"Timer callback fired at runtime: {runtime}")
# Try different paths # Try different paths
paths = [ paths = [
"test_screenshot.png", "test_screenshot.png",
"./test_screenshot.png", "./test_screenshot.png",
"mcrogueface.github.io/images/test_screenshot.png" "mcrogueface.github.io/images/test_screenshot.png"
] ]
for path in paths: for path in paths:
try: try:
print(f"Trying to save to: {path}") print(f"Trying to save to: {path}")
@ -24,7 +24,7 @@ def take_screenshot(runtime):
print(f"Success: {path}") print(f"Success: {path}")
except Exception as e: except Exception as e:
print(f"Failed {path}: {e}") print(f"Failed {path}: {e}")
sys.exit(0) sys.exit(0)
# Create minimal scene # Create minimal scene
@ -41,5 +41,5 @@ test.activate()
# Use timer to ensure rendering has started # Use timer to ensure rendering has started
print("Setting timer...") print("Setting timer...")
mcrfpy.setTimer("screenshot", take_screenshot, 500) # Wait 0.5 seconds mcrfpy.Timer("screenshot", take_screenshot, 500, once=True) # Wait 0.5 seconds
print("Timer set, entering game loop...") print("Timer set, entering game loop...")

View file

@ -6,18 +6,18 @@ from mcrfpy import automation
# Counter to track timer calls # Counter to track timer calls
call_count = 0 call_count = 0
def take_screenshot_and_exit(): def take_screenshot_and_exit(timer, runtime):
"""Timer callback that takes screenshot then exits""" """Timer callback that takes screenshot then exits"""
global call_count global call_count
call_count += 1 call_count += 1
print(f"\nTimer callback fired! (call #{call_count})") print(f"\nTimer callback fired! (call #{call_count})")
# Take screenshot # Take screenshot
filename = f"timer_screenshot_test_{call_count}.png" filename = f"timer_screenshot_test_{call_count}.png"
result = automation.screenshot(filename) result = automation.screenshot(filename)
print(f"Screenshot result: {result} -> {filename}") print(f"Screenshot result: {result} -> {filename}")
# Exit after first call # Exit after first call
if call_count >= 1: if call_count >= 1:
print("Exiting game...") print("Exiting game...")
@ -35,6 +35,6 @@ frame = mcrfpy.Frame(pos=(100, 100), size=(200, 200),
ui.append(frame) ui.append(frame)
print("Setting timer to fire in 100ms...") print("Setting timer to fire in 100ms...")
mcrfpy.setTimer("screenshot_timer", take_screenshot_and_exit, 100) mcrfpy.Timer("screenshot_timer", take_screenshot_and_exit, 100, once=True)
print("Setup complete. Game loop starting...") print("Setup complete. Game loop starting...")

View file

@ -6,6 +6,7 @@ import sys
# Global state to track callback # Global state to track callback
callback_count = 0 callback_count = 0
callback_demo = None # Will be set in setup_and_run
def my_callback(anim, target): def my_callback(anim, target):
"""Simple callback that prints when animation completes""" """Simple callback that prints when animation completes"""
@ -16,47 +17,48 @@ def my_callback(anim, target):
def setup_and_run(): def setup_and_run():
"""Set up scene and run animation with callback""" """Set up scene and run animation with callback"""
global callback_demo
# Create scene # Create scene
callback_demo = mcrfpy.Scene("callback_demo") callback_demo = mcrfpy.Scene("callback_demo")
callback_demo.activate() callback_demo.activate()
# Create a frame to animate # Create a frame to animate
frame = mcrfpy.Frame((100, 100), (200, 200), fill_color=(255, 0, 0)) frame = mcrfpy.Frame((100, 100), (200, 200), fill_color=(255, 0, 0))
ui = callback_demo.children ui = callback_demo.children
ui.append(frame) ui.append(frame)
# Create animation with callback # Create animation with callback
print("Starting animation with callback...") print("Starting animation with callback...")
anim = mcrfpy.Animation("x", 400.0, 1.0, "easeInOutQuad", callback=my_callback) anim = mcrfpy.Animation("x", 400.0, 1.0, "easeInOutQuad", callback=my_callback)
anim.start(frame) anim.start(frame)
# Schedule check after animation should complete
mcrfpy.setTimer("check", check_result, 1500)
def check_result(runtime): # Schedule check after animation should complete
mcrfpy.Timer("check", check_result, 1500, once=True)
def check_result(timer, runtime):
"""Check if callback fired correctly""" """Check if callback fired correctly"""
global callback_count global callback_count, callback_demo
if callback_count == 1: if callback_count == 1:
print("SUCCESS: Callback fired exactly once!") print("SUCCESS: Callback fired exactly once!")
# Test 2: Animation without callback # Test 2: Animation without callback
print("\nTesting animation without callback...") print("\nTesting animation without callback...")
ui = callback_demo.children ui = callback_demo.children
frame = ui[0] frame = ui[0]
anim2 = mcrfpy.Animation("y", 300.0, 0.5, "linear") anim2 = mcrfpy.Animation("y", 300.0, 0.5, "linear")
anim2.start(frame) anim2.start(frame)
mcrfpy.setTimer("final", final_check, 700) mcrfpy.Timer("final", final_check, 700, once=True)
else: else:
print(f"FAIL: Expected 1 callback, got {callback_count}") print(f"FAIL: Expected 1 callback, got {callback_count}")
sys.exit(1) sys.exit(1)
def final_check(runtime): def final_check(timer, runtime):
"""Final check - callback count should still be 1""" """Final check - callback count should still be 1"""
global callback_count global callback_count
if callback_count == 1: if callback_count == 1:
print("SUCCESS: No unexpected callbacks fired!") print("SUCCESS: No unexpected callbacks fired!")
print("\nAnimation callback feature working correctly!") print("\nAnimation callback feature working correctly!")
@ -68,4 +70,4 @@ def final_check(runtime):
# Start the demo # Start the demo
print("Animation Callback Demo") print("Animation Callback Demo")
print("=" * 30) print("=" * 30)
setup_and_run() setup_and_run()

View file

@ -35,35 +35,36 @@ class PathAnimator:
if self.current_index >= len(self.path): if self.current_index >= len(self.path):
# Path complete # Path complete
self.animating = False self.animating = False
mcrfpy.delTimer(self.check_timer_name) if hasattr(self, '_check_timer'):
self._check_timer.stop()
if self.on_complete: if self.on_complete:
self.on_complete() self.on_complete()
return return
# Get target position # Get target position
target_x, target_y = self.path[self.current_index] target_x, target_y = self.path[self.current_index]
# Create animations # Create animations
self.anim_x = mcrfpy.Animation("x", float(target_x), self.step_duration, "easeInOut") self.anim_x = mcrfpy.Animation("x", float(target_x), self.step_duration, "easeInOut")
self.anim_y = mcrfpy.Animation("y", float(target_y), self.step_duration, "easeInOut") self.anim_y = mcrfpy.Animation("y", float(target_y), self.step_duration, "easeInOut")
# Start animations # Start animations
self.anim_x.start(self.entity) self.anim_x.start(self.entity)
self.anim_y.start(self.entity) self.anim_y.start(self.entity)
# Update visibility if entity has this method # Update visibility if entity has this method
if hasattr(self.entity, 'update_visibility'): if hasattr(self.entity, 'update_visibility'):
self.entity.update_visibility() self.entity.update_visibility()
# Set timer to check completion # Set timer to check completion
mcrfpy.setTimer(self.check_timer_name, self._check_completion, 50) self._check_timer = mcrfpy.Timer(self.check_timer_name, self._check_completion, 50)
def _check_completion(self, dt): def _check_completion(self, timer, runtime):
"""Check if current animation is complete""" """Check if current animation is complete"""
if hasattr(self.anim_x, 'is_complete') and self.anim_x.is_complete: if hasattr(self.anim_x, 'is_complete') and self.anim_x.is_complete:
# Move to next step # Move to next step
self.current_index += 1 self.current_index += 1
mcrfpy.delTimer(self.check_timer_name) timer.stop()
self._animate_next_step() self._animate_next_step()
# Create test scene # Create test scene
@ -165,7 +166,7 @@ def animate_both():
# Camera follow test # Camera follow test
camera_follow = False camera_follow = False
def update_camera(dt): def update_camera(timer, runtime):
"""Update camera to follow player if enabled""" """Update camera to follow player if enabled"""
if camera_follow and player_animator and player_animator.animating: if camera_follow and player_animator and player_animator.animating:
# Smooth camera follow # Smooth camera follow
@ -205,7 +206,7 @@ chain_test.activate()
chain_test.on_key = handle_input chain_test.on_key = handle_input
# Camera update timer # Camera update timer
mcrfpy.setTimer("cam_update", update_camera, 100) cam_update_timer = mcrfpy.Timer("cam_update", update_camera, 100)
print("Animation Chaining Test") print("Animation Chaining Test")
print("=======================") print("=======================")

View file

@ -38,25 +38,25 @@ class AnimationTracker:
# Track it # Track it
active_animations[self.name] = self active_animations[self.name] = self
# Set timer to check completion # Set timer to check completion
check_interval = 100 # ms check_interval = 100 # ms
mcrfpy.setTimer(f"check_{self.name}", self._check_complete, check_interval) self._check_timer = mcrfpy.Timer(f"check_{self.name}", self._check_complete, check_interval)
def _check_complete(self, dt): def _check_complete(self, timer, runtime):
"""Check if animation is complete""" """Check if animation is complete"""
if self.animation and hasattr(self.animation, 'is_complete') and self.animation.is_complete: if self.animation and hasattr(self.animation, 'is_complete') and self.animation.is_complete:
# Log completion # Log completion
log_entry = f"COMPLETE: {self.name}" log_entry = f"COMPLETE: {self.name}"
animation_log.append(log_entry) animation_log.append(log_entry)
print(log_entry) print(log_entry)
# Remove from active # Remove from active
if self.name in active_animations: if self.name in active_animations:
del active_animations[self.name] del active_animations[self.name]
# Stop checking # Stop checking
mcrfpy.delTimer(f"check_{self.name}") timer.stop()
# Create test scene # Create test scene
anim_debug = mcrfpy.Scene("anim_debug") anim_debug = mcrfpy.Scene("anim_debug")
@ -117,14 +117,15 @@ def test_rapid_fire():
# Start first animation # Start first animation
anim1 = AnimationTracker("rapid_1", entity, "x", 8.0, 2.0) anim1 = AnimationTracker("rapid_1", entity, "x", 8.0, 2.0)
anim1.start() anim1.start()
# Start another after 500ms (before first completes) # Start another after 500ms (before first completes)
def start_second(dt): def start_second(timer, runtime):
anim2 = AnimationTracker("rapid_2", entity, "x", 12.0, 1.0) anim2 = AnimationTracker("rapid_2", entity, "x", 12.0, 1.0)
anim2.start() anim2.start()
mcrfpy.delTimer("rapid_timer") timer.stop()
mcrfpy.setTimer("rapid_timer", start_second, 500) global rapid_timer
rapid_timer = mcrfpy.Timer("rapid_timer", start_second, 500, once=True)
def test_sequential(): def test_sequential():
"""Test proper sequential animations""" """Test proper sequential animations"""
@ -142,14 +143,14 @@ def test_sequential():
if index >= len(sequence): if index >= len(sequence):
print("Sequence complete!") print("Sequence complete!")
return return
name, prop, value, duration = sequence[index] name, prop, value, duration = sequence[index]
anim = AnimationTracker(name, entity, prop, value, duration) anim = AnimationTracker(name, entity, prop, value, duration)
anim.start() anim.start()
# Schedule next # Schedule next
delay = int(duration * 1000) + 100 # Add buffer delay = int(duration * 1000) + 100 # Add buffer
mcrfpy.setTimer(f"seq_timer_{index}", lambda dt: run_sequence(index + 1), delay) mcrfpy.Timer(f"seq_timer_{index}", lambda t, r: run_sequence(index + 1), delay, once=True)
run_sequence() run_sequence()
@ -163,19 +164,20 @@ def test_conflicting():
anim1.start() anim1.start()
# After 1 second, start conflicting animation to x=2 # After 1 second, start conflicting animation to x=2
def start_conflict(dt): def start_conflict(timer, runtime):
print("Starting conflicting animation!") print("Starting conflicting animation!")
anim2 = AnimationTracker("conflict_2", entity, "x", 2.0, 1.0) anim2 = AnimationTracker("conflict_2", entity, "x", 2.0, 1.0)
anim2.start() anim2.start()
mcrfpy.delTimer("conflict_timer") timer.stop()
mcrfpy.setTimer("conflict_timer", start_conflict, 1000) global conflict_timer
conflict_timer = mcrfpy.Timer("conflict_timer", start_conflict, 1000, once=True)
# Update display # Update display
def update_display(dt): def update_display(timer, runtime):
pos_display.text = f"Entity position: ({entity.x:.2f}, {entity.y:.2f})" pos_display.text = f"Entity position: ({entity.x:.2f}, {entity.y:.2f})"
active_display.text = f"Active animations: {len(active_animations)}" active_display.text = f"Active animations: {len(active_animations)}"
# Show active animation names # Show active animation names
if active_animations: if active_animations:
names = ", ".join(active_animations.keys()) names = ", ".join(active_animations.keys())
@ -217,7 +219,7 @@ def handle_input(key, state):
# Setup # Setup
anim_debug.activate() anim_debug.activate()
anim_debug.on_key = handle_input anim_debug.on_key = handle_input
mcrfpy.setTimer("update", update_display, 100) update_display_timer = mcrfpy.Timer("update", update_display, 100)
print("Animation Debug Tool") print("Animation Debug Tool")
print("====================") print("====================")

View file

@ -210,7 +210,7 @@ def test_8_replace_completes_old():
test_result("Replace completes old animation", False, str(e)) test_result("Replace completes old animation", False, str(e))
def run_all_tests(runtime): def run_all_tests(timer, runtime):
"""Run all property locking tests""" """Run all property locking tests"""
print("\nRunning Animation Property Locking Tests...") print("\nRunning Animation Property Locking Tests...")
print("-" * 50) print("-" * 50)
@ -246,4 +246,4 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Start tests after a brief delay to allow scene to initialize # Start tests after a brief delay to allow scene to initialize
mcrfpy.setTimer("start", run_all_tests, 100) mcrfpy.Timer("start", run_all_tests, 100, once=True)

View file

@ -93,32 +93,32 @@ def test_3_complete_animation():
def test_4_multiple_animations_timer(): def test_4_multiple_animations_timer():
"""Test creating multiple animations in timer callback""" """Test creating multiple animations in timer callback"""
success = False success = False
def create_animations(runtime): def create_animations(timer, runtime):
nonlocal success nonlocal success
try: try:
ui = test.children ui = test.children
frame = mcrfpy.Frame(pos=(200, 200), size=(100, 100)) frame = mcrfpy.Frame(pos=(200, 200), size=(100, 100))
ui.append(frame) ui.append(frame)
# Create multiple animations rapidly (this used to crash) # Create multiple animations rapidly (this used to crash)
for i in range(10): for i in range(10):
anim = mcrfpy.Animation("x", 300.0 + i * 10, 1000, "linear") anim = mcrfpy.Animation("x", 300.0 + i * 10, 1000, "linear")
anim.start(frame) anim.start(frame)
success = True success = True
except Exception as e: except Exception as e:
print(f"Timer animation error: {e}") print(f"Timer animation error: {e}")
finally: finally:
mcrfpy.setTimer("exit", lambda t: None, 100) mcrfpy.Timer("exit", lambda t, r: None, 100, once=True)
# Clear scene # Clear scene
ui = test.children ui = test.children
while len(ui) > 0: while len(ui) > 0:
ui.remove(len(ui) - 1) ui.remove(len(ui) - 1)
mcrfpy.setTimer("test", create_animations, 50) mcrfpy.Timer("test", create_animations, 50, once=True)
mcrfpy.setTimer("check", lambda t: test_result("Multiple animations in timer", success), 200) mcrfpy.Timer("check", lambda t, r: test_result("Multiple animations in timer", success), 200, once=True)
def test_5_scene_cleanup(): def test_5_scene_cleanup():
"""Test that changing scenes cleans up animations""" """Test that changing scenes cleans up animations"""
@ -168,38 +168,38 @@ def test_6_animation_after_clear():
except Exception as e: except Exception as e:
test_result("Animation after UI clear", False, str(e)) test_result("Animation after UI clear", False, str(e))
def run_all_tests(runtime): def run_all_tests(timer, runtime):
"""Run all RAII tests""" """Run all RAII tests"""
print("\nRunning RAII Animation Tests...") print("\nRunning RAII Animation Tests...")
print("-" * 40) print("-" * 40)
test_1_basic_animation() test_1_basic_animation()
test_2_remove_animated_object() test_2_remove_animated_object()
test_3_complete_animation() test_3_complete_animation()
test_4_multiple_animations_timer() test_4_multiple_animations_timer()
test_5_scene_cleanup() test_5_scene_cleanup()
test_6_animation_after_clear() test_6_animation_after_clear()
# Schedule result summary
mcrfpy.setTimer("results", print_results, 500)
def print_results(runtime): # Schedule result summary
mcrfpy.Timer("results", print_results, 500, once=True)
def print_results(timer, runtime):
"""Print test results""" """Print test results"""
print("\n" + "=" * 40) print("\n" + "=" * 40)
print(f"Tests passed: {tests_passed}") print(f"Tests passed: {tests_passed}")
print(f"Tests failed: {tests_failed}") print(f"Tests failed: {tests_failed}")
if tests_failed == 0: if tests_failed == 0:
print("\n All tests passed! RAII implementation is working correctly.") print("\n+ All tests passed! RAII implementation is working correctly.")
else: else:
print(f"\n {tests_failed} tests failed.") print(f"\nx {tests_failed} tests failed.")
print("\nFailed tests:") print("\nFailed tests:")
for name, passed, details in test_results: for name, passed, details in test_results:
if not passed: if not passed:
print(f" - {name}: {details}") print(f" - {name}: {details}")
# Exit # Exit
mcrfpy.setTimer("exit", lambda t: sys.exit(0 if tests_failed == 0 else 1), 500) mcrfpy.Timer("exit", lambda t, r: sys.exit(0 if tests_failed == 0 else 1), 500, once=True)
# Setup and run # Setup and run
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
@ -212,4 +212,4 @@ bg.fill_color = mcrfpy.Color(20, 20, 30)
ui.append(bg) ui.append(bg)
# Start tests # Start tests
mcrfpy.setTimer("start", run_all_tests, 100) start_timer = mcrfpy.Timer("start", run_all_tests, 100, once=True)

View file

@ -6,7 +6,7 @@ Test if the crash is related to removing animated objects
import mcrfpy import mcrfpy
import sys import sys
def clear_and_recreate(runtime): def clear_and_recreate(timer, runtime):
"""Clear UI and recreate - mimics demo switching""" """Clear UI and recreate - mimics demo switching"""
print(f"\nTimer called at {runtime}") print(f"\nTimer called at {runtime}")
@ -31,9 +31,10 @@ def clear_and_recreate(runtime):
anim.start(f) anim.start(f)
print("New objects created and animated") print("New objects created and animated")
# Schedule exit # Schedule exit
mcrfpy.setTimer("exit", lambda t: sys.exit(0), 2000) global exit_timer
exit_timer = mcrfpy.Timer("exit", lambda t, r: sys.exit(0), 2000, once=True)
# Create initial scene # Create initial scene
print("Creating scene...") print("Creating scene...")
@ -60,6 +61,6 @@ for i in range(10):
print(f"Initial scene has {len(ui)} elements") print(f"Initial scene has {len(ui)} elements")
# Schedule the clear and recreate # Schedule the clear and recreate
mcrfpy.setTimer("switch", clear_and_recreate, 1000) switch_timer = mcrfpy.Timer("switch", clear_and_recreate, 1000, once=True)
print("\nEntering game loop...") print("\nEntering game loop...")

View file

@ -114,7 +114,7 @@ print(" - Empty paths returned for blocked destinations")
print(" - Diagonal movement supported") print(" - Diagonal movement supported")
# Quick visual test # Quick visual test
def visual_test(runtime): def visual_test(timer, runtime):
print("\nVisual test timer fired") print("\nVisual test timer fired")
sys.exit(0) sys.exit(0)
@ -125,6 +125,6 @@ grid.position = (50, 50)
grid.size = (400, 400) grid.size = (400, 400)
astar_test.activate() astar_test.activate()
mcrfpy.setTimer("visual", visual_test, 100) visual_test_timer = mcrfpy.Timer("visual", visual_test, 100, once=True)
print("\nStarting visual test...") print("\nStarting visual test...")

View file

@ -6,7 +6,7 @@ Test #94: Color helper methods - from_hex, to_hex, lerp
import mcrfpy import mcrfpy
import sys import sys
def test_color_helpers(runtime): def test_color_helpers(timer, runtime):
"""Test Color helper methods""" """Test Color helper methods"""
all_pass = True all_pass = True
@ -179,4 +179,4 @@ def test_color_helpers(runtime):
# Run test # Run test
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
mcrfpy.setTimer("test", test_color_helpers, 100) test_timer = mcrfpy.Timer("test", test_color_helpers, 100, once=True)

View file

@ -183,7 +183,7 @@ def test_multi_target_scenario():
cell.tilesprite = 83 # S for safe cell.tilesprite = 83 # S for safe
grid._color_layer.set(best_pos[0], best_pos[1], mcrfpy.Color(0, 255, 0)) grid._color_layer.set(best_pos[0], best_pos[1], mcrfpy.Color(0, 255, 0))
def run_test(runtime): def run_test(timer, runtime):
"""Timer callback to run tests after scene loads""" """Timer callback to run tests after scene loads"""
test_basic_dijkstra() test_basic_dijkstra()
test_libtcod_interface() test_libtcod_interface()
@ -221,7 +221,7 @@ title.fill_color = mcrfpy.Color(255, 255, 255)
ui.append(title) ui.append(title)
# Set timer to run tests # Set timer to run tests
mcrfpy.setTimer("test", run_test, 100) test_timer = mcrfpy.Timer("test", run_test, 100, once=True)
# Show scene # Show scene
dijkstra_test.activate() dijkstra_test.activate()

View file

@ -20,7 +20,7 @@ def test_method_docs():
'createSoundBuffer', 'loadMusic', 'setMusicVolume', 'setSoundVolume', 'createSoundBuffer', 'loadMusic', 'setMusicVolume', 'setSoundVolume',
'playSound', 'getMusicVolume', 'getSoundVolume', 'sceneUI', 'playSound', 'getMusicVolume', 'getSoundVolume', 'sceneUI',
'currentScene', 'setScene', 'createScene', 'keypressScene', 'currentScene', 'setScene', 'createScene', 'keypressScene',
'setTimer', 'delTimer', 'exit', 'setScale', 'find', 'findAll', 'exit', 'setScale', 'find', 'findAll',
'getMetrics' 'getMetrics'
] ]
@ -40,7 +40,7 @@ def test_class_docs():
"""Test class documentation.""" """Test class documentation."""
print("=== Class Documentation ===") print("=== Class Documentation ===")
classes = ['Frame', 'Caption', 'Sprite', 'Grid', 'Entity', 'Color', 'Vector', 'Texture', 'Font'] classes = ['Frame', 'Caption', 'Sprite', 'Grid', 'Entity', 'Color', 'Vector', 'Texture', 'Font', 'Timer']
for class_name in classes: for class_name in classes:
if hasattr(mcrfpy, class_name): if hasattr(mcrfpy, class_name):
@ -80,12 +80,12 @@ def test_method_signatures():
else: else:
print("✗ setScene signature incorrect or missing") print("✗ setScene signature incorrect or missing")
if hasattr(mcrfpy, 'setTimer'): if hasattr(mcrfpy, 'Timer'):
doc = mcrfpy.setTimer.__doc__ doc = mcrfpy.Timer.__doc__
if doc and 'setTimer(name: str, handler: callable, interval: int)' in doc: if doc and 'Timer' in doc:
print("✓ setTimer signature correct") print("+ Timer class documentation present")
else: else:
print("✗ setTimer signature incorrect or missing") print("x Timer class documentation missing")
if hasattr(mcrfpy, 'find'): if hasattr(mcrfpy, 'find'):
doc = mcrfpy.find.__doc__ doc = mcrfpy.find.__doc__

View file

@ -12,9 +12,9 @@ test.activate()
print("Scene created, no animations added") print("Scene created, no animations added")
print("Starting game loop in 100ms...") print("Starting game loop in 100ms...")
def check_alive(runtime): def check_alive(timer, runtime):
print(f"Timer fired at {runtime}ms - AnimationManager survived!") print(f"Timer fired at {runtime}ms - AnimationManager survived!")
mcrfpy.setTimer("exit", lambda t: mcrfpy.exit(), 100) mcrfpy.Timer("exit", lambda t, r: mcrfpy.exit(), 100, once=True)
mcrfpy.setTimer("check", check_alive, 1000) mcrfpy.Timer("check", check_alive, 1000, once=True)
print("If this crashes immediately, AnimationManager has an issue with empty state") print("If this crashes immediately, AnimationManager has an issue with empty state")

View file

@ -77,10 +77,10 @@ current_waypoint = 0
animating = False animating = False
waypoints = [(5,5), (10,5), (10,10), (5,10), (5,5)] waypoints = [(5,5), (10,5), (10,10), (5,10), (5,5)]
def update_position_display(dt): def update_position_display(timer, runtime):
"""Update position display every 200ms""" """Update position display every 200ms"""
pos_display.text = f"Entity Position: ({entity.x:.2f}, {entity.y:.2f})" pos_display.text = f"Entity Position: ({entity.x:.2f}, {entity.y:.2f})"
# Check if entity is at expected position # Check if entity is at expected position
if animating and current_waypoint > 0: if animating and current_waypoint > 0:
target = waypoints[current_waypoint - 1] target = waypoints[current_waypoint - 1]
@ -124,9 +124,10 @@ def animate_to_next_waypoint():
print(f"Started animations: x to {float(target_x)}, y to {float(target_y)}, duration: {duration}s") print(f"Started animations: x to {float(target_x)}, y to {float(target_y)}, duration: {duration}s")
current_waypoint += 1 current_waypoint += 1
# Schedule next waypoint # Schedule next waypoint
mcrfpy.setTimer("next_waypoint", lambda dt: animate_to_next_waypoint(), int(duration * 1000 + 100)) global next_waypoint_timer
next_waypoint_timer = mcrfpy.Timer("next_waypoint", lambda t, r: animate_to_next_waypoint(), int(duration * 1000 + 100), once=True)
def start_animation(): def start_animation():
"""Start or restart the animation sequence""" """Start or restart the animation sequence"""
@ -186,7 +187,7 @@ test_anim.activate()
test_anim.on_key = handle_input test_anim.on_key = handle_input
# Start position update timer # Start position update timer
mcrfpy.setTimer("update_pos", update_position_display, 200) update_pos_timer = mcrfpy.Timer("update_pos", update_position_display, 200)
# No perspective (omniscient view) # No perspective (omniscient view)
grid.perspective = -1 grid.perspective = -1

View file

@ -72,7 +72,7 @@ status.fill_color = mcrfpy.Color(200, 200, 200)
ui.append(status) ui.append(status)
# Update display # Update display
def update_display(dt): def update_display(timer, runtime):
pos_info.text = f"Entity Grid Position: ({entity.x:.2f}, {entity.y:.2f})" pos_info.text = f"Entity Grid Position: ({entity.x:.2f}, {entity.y:.2f})"
# We can't access sprite position from Python, but in C++ it would show # We can't access sprite position from Python, but in C++ it would show
# the issue: sprite position would be (2, 2) instead of pixel coords # the issue: sprite position would be (2, 2) instead of pixel coords
@ -113,7 +113,7 @@ def handle_input(key, state):
# Setup # Setup
fix_demo.activate() fix_demo.activate()
fix_demo.on_key = handle_input fix_demo.on_key = handle_input
mcrfpy.setTimer("update", update_display, 100) update_timer = mcrfpy.Timer("update", update_display, 100)
print("Ready to demonstrate the issue.") print("Ready to demonstrate the issue.")
print() print()

View file

@ -8,9 +8,9 @@ import sys
# Module-level state to avoid closures # Module-level state to avoid closures
_test_state = {} _test_state = {}
def take_second_screenshot(runtime): def take_second_screenshot(timer, runtime):
"""Take final screenshot and exit""" """Take final screenshot and exit"""
mcrfpy.delTimer("screenshot2") timer.stop()
from mcrfpy import automation from mcrfpy import automation
automation.screenshot("frame_clipping_animated.png") automation.screenshot("frame_clipping_animated.png")
print("\nTest completed successfully!") print("\nTest completed successfully!")
@ -19,20 +19,21 @@ def take_second_screenshot(runtime):
print(" - frame_clipping_animated.png (with animation)") print(" - frame_clipping_animated.png (with animation)")
sys.exit(0) sys.exit(0)
def animate_frames(runtime): def animate_frames(timer, runtime):
"""Animate frames to demonstrate clipping""" """Animate frames to demonstrate clipping"""
mcrfpy.delTimer("animate") timer.stop()
scene = test.children scene = test.children
# Move child frames # Move child frames
parent1 = scene[0] parent1 = scene[0]
parent2 = scene[1] parent2 = scene[1]
parent1.children[1].x = 50 parent1.children[1].x = 50
parent2.children[1].x = 50 parent2.children[1].x = 50
mcrfpy.setTimer("screenshot2", take_second_screenshot, 500) global screenshot2_timer
screenshot2_timer = mcrfpy.Timer("screenshot2", take_second_screenshot, 500, once=True)
def test_clipping(runtime): def test_clipping(timer, runtime):
"""Test that clip_children property works correctly""" """Test that clip_children property works correctly"""
mcrfpy.delTimer("test_clipping") timer.stop()
print("Testing UIFrame clipping functionality...") print("Testing UIFrame clipping functionality...")
@ -115,7 +116,8 @@ def test_clipping(runtime):
print(f"PASS: clip_children correctly rejected non-boolean: {e}") print(f"PASS: clip_children correctly rejected non-boolean: {e}")
# Start animation after a short delay # Start animation after a short delay
mcrfpy.setTimer("animate", animate_frames, 100) global animate_timer
animate_timer = mcrfpy.Timer("animate", animate_frames, 100, once=True)
def handle_keypress(key, modifiers): def handle_keypress(key, modifiers):
if key == "c": if key == "c":
@ -129,5 +131,5 @@ print("Creating test scene...")
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
test.activate() test.activate()
test.on_key = handle_keypress test.on_key = handle_keypress
mcrfpy.setTimer("test_clipping", test_clipping, 100) test_clipping_timer = mcrfpy.Timer("test_clipping", test_clipping, 100, once=True)
print("Test scheduled, running...") print("Test scheduled, running...")

View file

@ -5,9 +5,9 @@ import mcrfpy
from mcrfpy import Color, Frame, Caption, Vector from mcrfpy import Color, Frame, Caption, Vector
import sys import sys
def test_nested_clipping(runtime): def test_nested_clipping(timer, runtime):
"""Test nested frames with clipping""" """Test nested frames with clipping"""
mcrfpy.delTimer("test_nested_clipping") timer.stop()
print("Testing advanced UIFrame clipping with nested frames...") print("Testing advanced UIFrame clipping with nested frames...")
@ -62,8 +62,8 @@ def test_nested_clipping(runtime):
print(f"Inner frame size: {inner.w}x{inner.h}") print(f"Inner frame size: {inner.w}x{inner.h}")
# Dynamically resize frames to test RenderTexture recreation # Dynamically resize frames to test RenderTexture recreation
def resize_test(runtime): def resize_test(timer, runtime):
mcrfpy.delTimer("resize_test") timer.stop()
print("Resizing frames to test RenderTexture recreation...") print("Resizing frames to test RenderTexture recreation...")
outer.w = 450 outer.w = 450
outer.h = 350 outer.h = 350
@ -71,12 +71,13 @@ def test_nested_clipping(runtime):
inner.h = 250 inner.h = 250
print(f"New outer frame size: {outer.w}x{outer.h}") print(f"New outer frame size: {outer.w}x{outer.h}")
print(f"New inner frame size: {inner.w}x{inner.h}") print(f"New inner frame size: {inner.w}x{inner.h}")
# Take screenshot after resize # Take screenshot after resize
mcrfpy.setTimer("screenshot_resize", take_resize_screenshot, 500) global screenshot_resize_timer
screenshot_resize_timer = mcrfpy.Timer("screenshot_resize", take_resize_screenshot, 500, once=True)
def take_resize_screenshot(runtime):
mcrfpy.delTimer("screenshot_resize") def take_resize_screenshot(timer, runtime):
timer.stop()
from mcrfpy import automation from mcrfpy import automation
automation.screenshot("frame_clipping_resized.png") automation.screenshot("frame_clipping_resized.png")
print("\nAdvanced test completed!") print("\nAdvanced test completed!")
@ -88,9 +89,10 @@ def test_nested_clipping(runtime):
from mcrfpy import automation from mcrfpy import automation
automation.screenshot("frame_clipping_nested.png") automation.screenshot("frame_clipping_nested.png")
print("Initial screenshot saved: frame_clipping_nested.png") print("Initial screenshot saved: frame_clipping_nested.png")
# Schedule resize test # Schedule resize test
mcrfpy.setTimer("resize_test", resize_test, 1000) global resize_test_timer
resize_test_timer = mcrfpy.Timer("resize_test", resize_test, 1000, once=True)
# Main execution # Main execution
print("Creating advanced test scene...") print("Creating advanced test scene...")
@ -98,6 +100,6 @@ test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule the test # Schedule the test
mcrfpy.setTimer("test_nested_clipping", test_nested_clipping, 100) test_nested_clipping_timer = mcrfpy.Timer("test_nested_clipping", test_nested_clipping, 100, once=True)
print("Advanced test scheduled, running...") print("Advanced test scheduled, running...")

View file

@ -42,25 +42,25 @@ def test_grid_background():
# Activate the scene # Activate the scene
test.activate() test.activate()
def run_tests(dt): def run_tests(timer, runtime):
"""Run background color tests""" """Run background color tests"""
mcrfpy.delTimer("run_tests") timer.stop()
print("\nTest 1: Default background color") print("\nTest 1: Default background color")
default_color = grid.background_color default_color = grid.background_color
print(f"Default: R={default_color.r}, G={default_color.g}, B={default_color.b}, A={default_color.a}") print(f"Default: R={default_color.r}, G={default_color.g}, B={default_color.b}, A={default_color.a}")
color_display.text = f"R:{default_color.r} G:{default_color.g} B:{default_color.b}" color_display.text = f"R:{default_color.r} G:{default_color.g} B:{default_color.b}"
def test_set_color(dt): def test_set_color(timer, runtime):
mcrfpy.delTimer("test_set") timer.stop()
print("\nTest 2: Set background to blue") print("\nTest 2: Set background to blue")
grid.background_color = mcrfpy.Color(20, 40, 100) grid.background_color = mcrfpy.Color(20, 40, 100)
new_color = grid.background_color new_color = grid.background_color
print(f" Set to: R={new_color.r}, G={new_color.g}, B={new_color.b}") print(f"+ Set to: R={new_color.r}, G={new_color.g}, B={new_color.b}")
color_display.text = f"R:{new_color.r} G:{new_color.g} B:{new_color.b}" color_display.text = f"R:{new_color.r} G:{new_color.g} B:{new_color.b}"
def test_animation(dt): def test_animation(timer, runtime):
mcrfpy.delTimer("test_anim") timer.stop()
print("\nTest 3: Manual color cycling") print("\nTest 3: Manual color cycling")
# Manually change color to test property is working # Manually change color to test property is working
colors = [ colors = [
@ -68,55 +68,55 @@ def test_grid_background():
mcrfpy.Color(20, 200, 20), # Green mcrfpy.Color(20, 200, 20), # Green
mcrfpy.Color(20, 20, 200), # Blue mcrfpy.Color(20, 20, 200), # Blue
] ]
color_index = [0] # Use list to allow modification in nested function color_index = [0] # Use list to allow modification in nested function
def cycle_red(dt): def cycle_red(t, r):
mcrfpy.delTimer("cycle_0") t.stop()
grid.background_color = colors[0] grid.background_color = colors[0]
c = grid.background_color c = grid.background_color
color_display.text = f"R:{c.r} G:{c.g} B:{c.b}" color_display.text = f"R:{c.r} G:{c.g} B:{c.b}"
print(f" Set to Red: R={c.r}, G={c.g}, B={c.b}") print(f"+ Set to Red: R={c.r}, G={c.g}, B={c.b}")
def cycle_green(dt): def cycle_green(t, r):
mcrfpy.delTimer("cycle_1") t.stop()
grid.background_color = colors[1] grid.background_color = colors[1]
c = grid.background_color c = grid.background_color
color_display.text = f"R:{c.r} G:{c.g} B:{c.b}" color_display.text = f"R:{c.r} G:{c.g} B:{c.b}"
print(f" Set to Green: R={c.r}, G={c.g}, B={c.b}") print(f"+ Set to Green: R={c.r}, G={c.g}, B={c.b}")
def cycle_blue(dt): def cycle_blue(t, r):
mcrfpy.delTimer("cycle_2") t.stop()
grid.background_color = colors[2] grid.background_color = colors[2]
c = grid.background_color c = grid.background_color
color_display.text = f"R:{c.r} G:{c.g} B:{c.b}" color_display.text = f"R:{c.r} G:{c.g} B:{c.b}"
print(f" Set to Blue: R={c.r}, G={c.g}, B={c.b}") print(f"+ Set to Blue: R={c.r}, G={c.g}, B={c.b}")
# Cycle through colors # Cycle through colors
mcrfpy.setTimer("cycle_0", cycle_red, 100) mcrfpy.Timer("cycle_0", cycle_red, 100, once=True)
mcrfpy.setTimer("cycle_1", cycle_green, 400) mcrfpy.Timer("cycle_1", cycle_green, 400, once=True)
mcrfpy.setTimer("cycle_2", cycle_blue, 700) mcrfpy.Timer("cycle_2", cycle_blue, 700, once=True)
def test_complete(dt): def test_complete(timer, runtime):
mcrfpy.delTimer("complete") timer.stop()
print("\nTest 4: Final color check") print("\nTest 4: Final color check")
final_color = grid.background_color final_color = grid.background_color
print(f"Final: R={final_color.r}, G={final_color.g}, B={final_color.b}") print(f"Final: R={final_color.r}, G={final_color.g}, B={final_color.b}")
print("\n Grid background color tests completed!") print("\n+ Grid background color tests completed!")
print("- Default background color works") print("- Default background color works")
print("- Setting background color works") print("- Setting background color works")
print("- Color cycling works") print("- Color cycling works")
sys.exit(0) sys.exit(0)
# Schedule tests # Schedule tests
mcrfpy.setTimer("test_set", test_set_color, 1000) mcrfpy.Timer("test_set", test_set_color, 1000, once=True)
mcrfpy.setTimer("test_anim", test_animation, 2000) mcrfpy.Timer("test_anim", test_animation, 2000, once=True)
mcrfpy.setTimer("complete", test_complete, 4500) mcrfpy.Timer("complete", test_complete, 4500, once=True)
# Start tests # Start tests
mcrfpy.setTimer("run_tests", run_tests, 100) mcrfpy.Timer("run_tests", run_tests, 100, once=True)
if __name__ == "__main__": if __name__ == "__main__":
test_grid_background() test_grid_background()

View file

@ -4,18 +4,18 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
import sys import sys
def take_screenshot(runtime): def take_screenshot(timer, runtime):
"""Take screenshot after render completes""" """Take screenshot after render completes"""
mcrfpy.delTimer("screenshot") timer.stop()
automation.screenshot("test_grid_children_result.png") automation.screenshot("test_grid_children_result.png")
print("Screenshot saved to test_grid_children_result.png") print("Screenshot saved to test_grid_children_result.png")
print("PASS - Grid.children test completed") print("PASS - Grid.children test completed")
sys.exit(0) sys.exit(0)
def run_test(runtime): def run_test(timer, runtime):
"""Main test - runs after scene is set up""" """Main test - runs after scene is set up"""
mcrfpy.delTimer("test") timer.stop()
# Get the scene UI # Get the scene UI
ui = test.children ui = test.children
@ -119,11 +119,11 @@ def run_test(runtime):
print(f"\nFinal children count: {len(grid.children)}") print(f"\nFinal children count: {len(grid.children)}")
# Schedule screenshot for next frame # Schedule screenshot for next frame
mcrfpy.setTimer("screenshot", take_screenshot, 100) mcrfpy.Timer("screenshot", take_screenshot, 100, once=True)
# Create a test scene # Create a test scene
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test to run after game loop starts # Schedule test to run after game loop starts
mcrfpy.setTimer("test", run_test, 50) mcrfpy.Timer("test", run_test, 50, once=True)

View file

@ -15,12 +15,12 @@ frame = mcrfpy.Frame(pos=(100, 100), size=(200, 200))
frame.fill_color = mcrfpy.Color(255, 100, 100, 255) frame.fill_color = mcrfpy.Color(255, 100, 100, 255)
ui.append(frame) ui.append(frame)
def test_mode(runtime): def test_mode(timer, runtime):
try: try:
# Try to take a screenshot - this should work in both modes # Try to take a screenshot - this should work in both modes
automation.screenshot("test_screenshot.png") automation.screenshot("test_screenshot.png")
print("PASS: Screenshot capability available") print("PASS: Screenshot capability available")
# Check if we can interact with the window # Check if we can interact with the window
try: try:
# In headless mode, this should still work but via the headless renderer # In headless mode, this should still work but via the headless renderer
@ -28,12 +28,12 @@ def test_mode(runtime):
print("PASS: Click automation available") print("PASS: Click automation available")
except Exception as e: except Exception as e:
print(f"Click failed: {e}") print(f"Click failed: {e}")
except Exception as e: except Exception as e:
print(f"Screenshot failed: {e}") print(f"Screenshot failed: {e}")
print("Test complete") print("Test complete")
sys.exit(0) sys.exit(0)
# Run test after render loop starts # Run test after render loop starts
mcrfpy.setTimer("test", test_mode, 100) test_timer = mcrfpy.Timer("test", test_mode, 100, once=True)

View file

@ -22,8 +22,8 @@ ui.append(caption)
print("Script started. Window should appear unless --headless was specified.") print("Script started. Window should appear unless --headless was specified.")
# Exit after 2 seconds # Exit after 2 seconds
def exit_test(runtime): def exit_test(timer, runtime):
print("Test complete. Exiting.") print("Test complete. Exiting.")
sys.exit(0) sys.exit(0)
mcrfpy.setTimer("exit", exit_test, 2000) exit_timer = mcrfpy.Timer("exit", exit_test, 2000, once=True)

View file

@ -5,13 +5,17 @@ import mcrfpy
import sys import sys
import time import time
def test_metrics(runtime): # Track success across callbacks
success = True
def test_metrics(timer, runtime):
"""Test the metrics after timer starts""" """Test the metrics after timer starts"""
global success
print("\nRunning metrics test...") print("\nRunning metrics test...")
# Get metrics # Get metrics
metrics = mcrfpy.getMetrics() metrics = mcrfpy.getMetrics()
print("\nPerformance Metrics:") print("\nPerformance Metrics:")
print(f" Frame Time: {metrics['frame_time']:.2f} ms") print(f" Frame Time: {metrics['frame_time']:.2f} ms")
print(f" Avg Frame Time: {metrics['avg_frame_time']:.2f} ms") print(f" Avg Frame Time: {metrics['avg_frame_time']:.2f} ms")
@ -21,17 +25,16 @@ def test_metrics(runtime):
print(f" Visible Elements: {metrics['visible_elements']}") print(f" Visible Elements: {metrics['visible_elements']}")
print(f" Current Frame: {metrics['current_frame']}") print(f" Current Frame: {metrics['current_frame']}")
print(f" Runtime: {metrics['runtime']:.2f} seconds") print(f" Runtime: {metrics['runtime']:.2f} seconds")
# Test that metrics are reasonable # Test that metrics are reasonable
success = True
# Frame time should be positive # Frame time should be positive
if metrics['frame_time'] <= 0: if metrics['frame_time'] <= 0:
print(" FAIL: Frame time should be positive") print(" FAIL: Frame time should be positive")
success = False success = False
else: else:
print(" PASS: Frame time is positive") print(" PASS: Frame time is positive")
# FPS should be reasonable (between 1 and 20000 in headless mode) # FPS should be reasonable (between 1 and 20000 in headless mode)
# In headless mode, FPS can be very high since there's no vsync # In headless mode, FPS can be very high since there's no vsync
if metrics['fps'] < 1 or metrics['fps'] > 20000: if metrics['fps'] < 1 or metrics['fps'] > 20000:
@ -39,72 +42,76 @@ def test_metrics(runtime):
success = False success = False
else: else:
print(f" PASS: FPS {metrics['fps']} is reasonable") print(f" PASS: FPS {metrics['fps']} is reasonable")
# UI elements count (may be 0 if scene hasn't rendered yet) # UI elements count (may be 0 if scene hasn't rendered yet)
if metrics['ui_elements'] < 0: if metrics['ui_elements'] < 0:
print(f" FAIL: UI elements count {metrics['ui_elements']} is negative") print(f" FAIL: UI elements count {metrics['ui_elements']} is negative")
success = False success = False
else: else:
print(f" PASS: UI element count {metrics['ui_elements']} is valid") print(f" PASS: UI element count {metrics['ui_elements']} is valid")
# Visible elements should be <= total elements # Visible elements should be <= total elements
if metrics['visible_elements'] > metrics['ui_elements']: if metrics['visible_elements'] > metrics['ui_elements']:
print(" FAIL: Visible elements > total elements") print(" FAIL: Visible elements > total elements")
success = False success = False
else: else:
print(" PASS: Visible element count is valid") print(" PASS: Visible element count is valid")
# Current frame should be > 0 # Current frame should be > 0
if metrics['current_frame'] <= 0: if metrics['current_frame'] <= 0:
print(" FAIL: Current frame should be > 0") print(" FAIL: Current frame should be > 0")
success = False success = False
else: else:
print(" PASS: Current frame is positive") print(" PASS: Current frame is positive")
# Runtime should be > 0 # Runtime should be > 0
if metrics['runtime'] <= 0: if metrics['runtime'] <= 0:
print(" FAIL: Runtime should be > 0") print(" FAIL: Runtime should be > 0")
success = False success = False
else: else:
print(" PASS: Runtime is positive") print(" PASS: Runtime is positive")
# Test metrics update over multiple frames # Test metrics update over multiple frames
print("\n\nTesting metrics over multiple frames...") print("\n\nTesting metrics over multiple frames...")
# Store initial metrics for comparison
initial_frame = metrics['current_frame']
initial_runtime = metrics['runtime']
# Schedule another check after 100ms # Schedule another check after 100ms
def check_later(runtime2): def check_later(timer2, runtime2):
global success
metrics2 = mcrfpy.getMetrics() metrics2 = mcrfpy.getMetrics()
print(f"\nMetrics after 100ms:") print(f"\nMetrics after 100ms:")
print(f" Frame Time: {metrics2['frame_time']:.2f} ms") print(f" Frame Time: {metrics2['frame_time']:.2f} ms")
print(f" Avg Frame Time: {metrics2['avg_frame_time']:.2f} ms") print(f" Avg Frame Time: {metrics2['avg_frame_time']:.2f} ms")
print(f" FPS: {metrics2['fps']}") print(f" FPS: {metrics2['fps']}")
print(f" Current Frame: {metrics2['current_frame']}") print(f" Current Frame: {metrics2['current_frame']}")
# Frame count should have increased # Frame count should have increased
if metrics2['current_frame'] > metrics['current_frame']: if metrics2['current_frame'] > initial_frame:
print(" PASS: Frame count increased") print(" PASS: Frame count increased")
else: else:
print(" FAIL: Frame count did not increase") print(" FAIL: Frame count did not increase")
nonlocal success
success = False success = False
# Runtime should have increased # Runtime should have increased
if metrics2['runtime'] > metrics['runtime']: if metrics2['runtime'] > initial_runtime:
print(" PASS: Runtime increased") print(" PASS: Runtime increased")
else: else:
print(" FAIL: Runtime did not increase") print(" FAIL: Runtime did not increase")
success = False success = False
print("\n" + "="*50) print("\n" + "="*50)
if success: if success:
print("ALL METRICS TESTS PASSED!") print("ALL METRICS TESTS PASSED!")
else: else:
print("SOME METRICS TESTS FAILED!") print("SOME METRICS TESTS FAILED!")
sys.exit(0 if success else 1) sys.exit(0 if success else 1)
mcrfpy.setTimer("check_later", check_later, 100) mcrfpy.Timer("check_later", check_later, 100, once=True)
# Set up test scene # Set up test scene
print("Setting up metrics test scene...") print("Setting up metrics test scene...")
@ -136,4 +143,4 @@ ui.append(grid)
print(f"Created {len(ui)} UI elements (1 invisible)") print(f"Created {len(ui)} UI elements (1 invisible)")
# Schedule test to run after render loop starts # Schedule test to run after render loop starts
mcrfpy.setTimer("test", test_metrics, 50) mcrfpy.Timer("test", test_metrics, 50, once=True)

View file

@ -7,7 +7,7 @@ This verifies the fix for requiring arguments even with safe default constructor
import mcrfpy import mcrfpy
import sys import sys
def test_ui_constructors(runtime): def test_ui_constructors(timer, runtime):
"""Test that UI classes can be instantiated without arguments""" """Test that UI classes can be instantiated without arguments"""
print("Testing UI class instantiation without arguments...") print("Testing UI class instantiation without arguments...")
@ -88,4 +88,4 @@ def test_ui_constructors(runtime):
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
# Schedule the test to run after game initialization # Schedule the test to run after game initialization
mcrfpy.setTimer("test", test_ui_constructors, 100) test_timer = mcrfpy.Timer("test", test_ui_constructors, 100, once=True)

View file

@ -63,7 +63,7 @@ for y in range(5):
print("\nIf colors are changing in data but not visually, it may be a rendering issue.") print("\nIf colors are changing in data but not visually, it may be a rendering issue.")
# Quick visual test # Quick visual test
def check_visual(runtime): def check_visual(timer, runtime):
print("\nTimer fired - checking if scene is rendering...") print("\nTimer fired - checking if scene is rendering...")
# Take screenshot to see actual rendering # Take screenshot to see actual rendering
try: try:
@ -81,6 +81,6 @@ grid.position = (50, 50)
grid.size = (250, 250) grid.size = (250, 250)
test.activate() test.activate()
mcrfpy.setTimer("check", check_visual, 500) check_timer = mcrfpy.Timer("check", check_visual, 500, once=True)
print("\nStarting render test...") print("\nStarting render test...")

View file

@ -48,11 +48,11 @@ print("\n✓ Pathfinding integration working correctly!")
print("Enhanced demos are ready for interactive use.") print("Enhanced demos are ready for interactive use.")
# Quick animation test # Quick animation test
def test_timer(dt): def test_timer(timer, runtime):
print(f"Timer callback received: dt={dt}ms") print(f"Timer callback received: runtime={runtime}ms")
sys.exit(0) sys.exit(0)
# Set a quick timer to test animation system # Set a quick timer to test animation system
mcrfpy.setTimer("test", test_timer, 100) timer = mcrfpy.Timer("test", test_timer, 100, once=True)
print("\nTesting timer system for animations...") print("\nTesting timer system for animations...")

View file

@ -3,8 +3,8 @@
import mcrfpy import mcrfpy
import sys import sys
def test_properties(runtime): def test_properties(timer, runtime):
mcrfpy.delTimer("test_properties") timer.stop()
print("\n=== Testing Properties ===") print("\n=== Testing Properties ===")
@ -54,4 +54,4 @@ def test_properties(runtime):
sys.exit(0) sys.exit(0)
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
mcrfpy.setTimer("test_properties", test_properties, 100) test_properties_timer = mcrfpy.Timer("test_properties", test_properties, 100, once=True)

View file

@ -21,7 +21,7 @@ def test(condition, message):
test_results.append(f"{message}") test_results.append(f"{message}")
test_passed = False test_passed = False
def run_tests(runtime): def run_tests(timer, runtime):
"""Timer callback to run tests after game loop starts""" """Timer callback to run tests after game loop starts"""
global test_passed global test_passed
@ -146,6 +146,6 @@ test_scene = mcrfpy.Scene("test_scene")
test_scene.activate() test_scene.activate()
# Schedule tests to run after game loop starts # Schedule tests to run after game loop starts
mcrfpy.setTimer("test", run_tests, 100) test_timer = mcrfpy.Timer("test", run_tests, 100, once=True)
print("Python object cache test initialized. Running tests...") print("Python object cache test initialized. Running tests...")

View file

@ -186,7 +186,7 @@ for s in (red_scene, blue_scene, green_scene, menu_scene):
# Option to run automatic test # Option to run automatic test
if len(sys.argv) > 1 and sys.argv[1] == "--auto": if len(sys.argv) > 1 and sys.argv[1] == "--auto":
mcrfpy.setTimer("auto_test", test_automatic_transitions, 1000) mcrfpy.Timer("auto_test", lambda t, r: test_automatic_transitions(r), 1000, once=True)
else: else:
print("\nManual test mode. Use keyboard controls shown on screen.") print("\nManual test mode. Use keyboard controls shown on screen.")
print("Run with --auto flag for automatic transition demo.") print("Run with --auto flag for automatic transition demo.")

View file

@ -7,8 +7,8 @@ def cb(a, t):
print("CB") print("CB")
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
test.activate() test.activate()
e = mcrfpy.Entity((0, 0), texture=None, sprite_index=0) e = mcrfpy.Entity((0, 0), texture=None, sprite_index=0)
a = mcrfpy.Animation("x", 1.0, 0.1, "linear", callback=cb) a = mcrfpy.Animation("x", 1.0, 0.1, "linear", callback=cb)
a.start(e) a.start(e)
mcrfpy.setTimer("exit", lambda r: sys.exit(0), 200) mcrfpy.Timer("exit", lambda t, r: sys.exit(0), 200, once=True)

View file

@ -3,8 +3,8 @@
import mcrfpy import mcrfpy
import sys import sys
def simple_test(runtime): def simple_test(timer, runtime):
mcrfpy.delTimer("simple_test") timer.stop()
try: try:
# Test basic functionality # Test basic functionality
@ -27,4 +27,4 @@ def simple_test(runtime):
sys.exit(0) sys.exit(0)
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
mcrfpy.setTimer("simple_test", simple_test, 100) simple_test_timer = mcrfpy.Timer("simple_test", simple_test, 100, once=True)

View file

@ -16,7 +16,7 @@ def create_demo():
# Create scene # Create scene
text_demo = mcrfpy.Scene("text_demo") text_demo = mcrfpy.Scene("text_demo")
scene = text_demo.children scene = text_demo.children
# Background # Background
bg = mcrfpy.Frame(pos=(0, 0), size=(800, 600)) bg = mcrfpy.Frame(pos=(0, 0), size=(800, 600))
bg.fill_color = mcrfpy.Color(40, 40, 40, 255) bg.fill_color = mcrfpy.Color(40, 40, 40, 255)
@ -26,55 +26,55 @@ def create_demo():
title = mcrfpy.Caption(pos=(20, 20), text="Text Input Widget Demo") title = mcrfpy.Caption(pos=(20, 20), text="Text Input Widget Demo")
title.fill_color = mcrfpy.Color(255, 255, 255, 255) title.fill_color = mcrfpy.Color(255, 255, 255, 255)
scene.append(title) scene.append(title)
# Focus manager # Focus manager
focus_mgr = FocusManager() focus_mgr = FocusManager()
# Create inputs # Create inputs
inputs = [] inputs = []
# Name input # Name input
name_input = TextInput(50, 100, 300, label="Name:", placeholder="Enter your name") name_input = TextInput(50, 100, 300, label="Name:", placeholder="Enter your name")
name_input._focus_manager = focus_mgr name_input._focus_manager = focus_mgr
focus_mgr.register(name_input) focus_mgr.register(name_input)
name_input.add_to_scene(scene) name_input.add_to_scene(scene)
inputs.append(name_input) inputs.append(name_input)
# Email input # Email input
email_input = TextInput(50, 160, 300, label="Email:", placeholder="user@example.com") email_input = TextInput(50, 160, 300, label="Email:", placeholder="user@example.com")
email_input._focus_manager = focus_mgr email_input._focus_manager = focus_mgr
focus_mgr.register(email_input) focus_mgr.register(email_input)
email_input.add_to_scene(scene) email_input.add_to_scene(scene)
inputs.append(email_input) inputs.append(email_input)
# Tags input # Tags input
tags_input = TextInput(50, 220, 400, label="Tags:", placeholder="comma, separated, tags") tags_input = TextInput(50, 220, 400, label="Tags:", placeholder="comma, separated, tags")
tags_input._focus_manager = focus_mgr tags_input._focus_manager = focus_mgr
focus_mgr.register(tags_input) focus_mgr.register(tags_input)
tags_input.add_to_scene(scene) tags_input.add_to_scene(scene)
inputs.append(tags_input) inputs.append(tags_input)
# Comment input # Comment input
comment_input = TextInput(50, 280, 500, height=30, label="Comment:", placeholder="Add a comment...") comment_input = TextInput(50, 280, 500, height=30, label="Comment:", placeholder="Add a comment...")
comment_input._focus_manager = focus_mgr comment_input._focus_manager = focus_mgr
focus_mgr.register(comment_input) focus_mgr.register(comment_input)
comment_input.add_to_scene(scene) comment_input.add_to_scene(scene)
inputs.append(comment_input) inputs.append(comment_input)
# Status display # Status display
status = mcrfpy.Caption(pos=(50, 360), text="Ready for input...") status = mcrfpy.Caption(pos=(50, 360), text="Ready for input...")
status.fill_color = mcrfpy.Color(150, 255, 150, 255) status.fill_color = mcrfpy.Color(150, 255, 150, 255)
scene.append(status) scene.append(status)
# Update handler # Update handler
def update_status(text=None): def update_status(text=None):
values = [inp.get_text() for inp in inputs] values = [inp.get_text() for inp in inputs]
status.text = f"Data: {values[0]} | {values[1]} | {values[2]} | {values[3]}" status.text = f"Data: {values[0]} | {values[1]} | {values[2]} | {values[3]}"
# Set change handlers # Set change handlers
for inp in inputs: for inp in inputs:
inp.on_change = update_status inp.on_change = update_status
# Keyboard handler # Keyboard handler
def handle_keys(scene_name, key): def handle_keys(scene_name, key):
if not focus_mgr.handle_key(key): if not focus_mgr.handle_key(key):
@ -85,12 +85,12 @@ def create_demo():
for i, inp in enumerate(inputs): for i, inp in enumerate(inputs):
print(f" Field {i+1}: '{inp.get_text()}'") print(f" Field {i+1}: '{inp.get_text()}'")
sys.exit(0) sys.exit(0)
text_demo.on_key = "text_demo", handle_keys text_demo.on_key = "text_demo", handle_keys
text_demo.activate() text_demo.activate()
# Run demo test # Run demo test
def run_test(timer_name): def run_test(timer, runtime):
print("\n=== Text Input Widget Test ===") print("\n=== Text Input Widget Test ===")
print("Features:") print("Features:")
print("- Click to focus fields") print("- Click to focus fields")
@ -102,9 +102,9 @@ def create_demo():
print("- Visual focus indication") print("- Visual focus indication")
print("- Press Escape to exit") print("- Press Escape to exit")
print("\nTry it out!") print("\nTry it out!")
mcrfpy.setTimer("info", run_test, 100) info_timer = mcrfpy.Timer("info", run_test, 100, once=True)
if __name__ == "__main__": if __name__ == "__main__":
create_demo() create_demo()

View file

@ -1,34 +1,27 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Test timer callback arguments Test timer callback arguments with new Timer API (#173)
""" """
import mcrfpy import mcrfpy
import sys import sys
call_count = 0 call_count = 0
def old_style_callback(arg): def new_style_callback(timer, runtime):
"""Old style callback - should receive just runtime""" """New style callback - receives timer object and runtime"""
global call_count global call_count
call_count += 1 call_count += 1
print(f"Old style callback called with: {arg} (type: {type(arg)})") print(f"Callback called with: timer={timer} (type: {type(timer)}), runtime={runtime} (type: {type(runtime)})")
if hasattr(timer, 'once'):
print(f"Got Timer object! once={timer.once}")
if call_count >= 2: if call_count >= 2:
print("PASS")
sys.exit(0) sys.exit(0)
def new_style_callback(arg1, arg2=None):
"""New style callback - should receive timer object and runtime"""
print(f"New style callback called with: arg1={arg1} (type: {type(arg1)}), arg2={arg2} (type: {type(arg2) if arg2 else 'None'})")
if hasattr(arg1, 'once'):
print(f"Got Timer object! once={arg1.once}")
sys.exit(0)
# Set up the scene # Set up the scene
test_scene = mcrfpy.Scene("test_scene") test_scene = mcrfpy.Scene("test_scene")
test_scene.activate() test_scene.activate()
print("Testing old style timer with setTimer...") print("Testing new Timer callback signature (timer, runtime)...")
mcrfpy.setTimer("old_timer", old_style_callback, 100) timer = mcrfpy.Timer("test_timer", new_style_callback, 100)
print(f"Timer created: {timer}")
print("\nTesting new style timer with Timer object...")
timer = mcrfpy.Timer("new_timer", new_style_callback, 200)
print(f"Timer created: {timer}")

View file

@ -1,26 +1,28 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Test legacy timer API still works Test Timer API works correctly (#173)
Replaces old legacy setTimer test
""" """
import mcrfpy import mcrfpy
import sys import sys
count = 0 count = 0
def timer_callback(runtime): def timer_callback(timer, runtime):
global count global count
count += 1 count += 1
print(f"Timer fired! Count: {count}, Runtime: {runtime}") print(f"Timer fired! Count: {count}, Runtime: {runtime}")
if count >= 3: if count >= 3:
print("Test passed - timer fired 3 times") print("Test passed - timer fired 3 times")
print("PASS")
sys.exit(0) sys.exit(0)
# Set up the scene # Set up the scene
test_scene = mcrfpy.Scene("test_scene") test_scene = mcrfpy.Scene("test_scene")
test_scene.activate() test_scene.activate()
# Create a timer the old way # Create a timer with new API
mcrfpy.setTimer("test_timer", timer_callback, 100) timer = mcrfpy.Timer("test_timer", timer_callback, 100)
print("Legacy timer test starting...") print("Timer test starting...")

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Test the new mcrfpy.Timer object with pause/resume/cancel functionality Test the new mcrfpy.Timer object with pause/resume/stop functionality
Updated for new Timer API (#173)
""" """
import mcrfpy import mcrfpy
import sys import sys
@ -25,13 +26,13 @@ def cancel_test_callback(timer, runtime):
cancel_test_count += 1 cancel_test_count += 1
print(f"Cancel test timer: {cancel_test_count} - This should only print once!") print(f"Cancel test timer: {cancel_test_count} - This should only print once!")
def run_tests(runtime): def run_tests(timer, runtime):
"""Main test function that runs after game loop starts""" """Main test function that runs after game loop starts"""
# Delete the timer that called us to prevent re-running # Stop the timer that called us to prevent re-running
mcrfpy.delTimer("run_tests") timer.stop()
print("\n=== Testing mcrfpy.Timer object ===\n") print("\n=== Testing mcrfpy.Timer object ===\n")
# Test 1: Create a basic timer # Test 1: Create a basic timer
print("Test 1: Creating Timer object") print("Test 1: Creating Timer object")
timer1 = mcrfpy.Timer("test_timer", timer_callback, 500) timer1 = mcrfpy.Timer("test_timer", timer_callback, 500)
@ -39,103 +40,102 @@ def run_tests(runtime):
print(f" Interval: {timer1.interval}ms") print(f" Interval: {timer1.interval}ms")
print(f" Active: {timer1.active}") print(f" Active: {timer1.active}")
print(f" Paused: {timer1.paused}") print(f" Paused: {timer1.paused}")
# Test 2: Test pause/resume # Test 2: Test pause/resume
print("\nTest 2: Testing pause/resume functionality") print("\nTest 2: Testing pause/resume functionality")
timer2 = mcrfpy.Timer("pause_test", pause_test_callback, 200) timer2 = mcrfpy.Timer("pause_test", pause_test_callback, 200)
# Schedule pause after 250ms # Schedule pause after 250ms
def pause_timer2(runtime): def pause_timer2(t, rt):
print(" Pausing timer2...") print(" Pausing timer2...")
timer2.pause() timer2.pause()
print(f" Timer2 paused: {timer2.paused}") print(f" Timer2 paused: {timer2.paused}")
print(f" Timer2 active: {timer2.active}") print(f" Timer2 active: {timer2.active}")
# Schedule resume after another 400ms # Schedule resume after another 400ms
def resume_timer2(runtime): def resume_timer2(t2, rt2):
print(" Resuming timer2...") print(" Resuming timer2...")
timer2.resume() timer2.resume()
print(f" Timer2 paused: {timer2.paused}") print(f" Timer2 paused: {timer2.paused}")
print(f" Timer2 active: {timer2.active}") print(f" Timer2 active: {timer2.active}")
mcrfpy.setTimer("resume_timer2", resume_timer2, 400) mcrfpy.Timer("resume_timer2", resume_timer2, 400, once=True)
mcrfpy.setTimer("pause_timer2", pause_timer2, 250) mcrfpy.Timer("pause_timer2", pause_timer2, 250, once=True)
# Test 3: Test cancel # Test 3: Test cancel/stop
print("\nTest 3: Testing cancel functionality") print("\nTest 3: Testing stop functionality")
timer3 = mcrfpy.Timer("cancel_test", cancel_test_callback, 300) timer3 = mcrfpy.Timer("cancel_test", cancel_test_callback, 300)
# Cancel after 350ms (should fire once) # Cancel after 350ms (should fire once)
def cancel_timer3(runtime): def cancel_timer3(t, rt):
mcrfpy.delTimer("cancel_timer3") # Make this a one-shot timer print(" Stopping timer3...")
print(" Canceling timer3...") timer3.stop()
timer3.cancel() print(" Timer3 stopped")
print(" Timer3 canceled")
mcrfpy.Timer("cancel_timer3", cancel_timer3, 350, once=True)
mcrfpy.setTimer("cancel_timer3", cancel_timer3, 350)
# Test 4: Test interval modification # Test 4: Test interval modification
print("\nTest 4: Testing interval modification") print("\nTest 4: Testing interval modification")
def interval_test(timer, runtime): def interval_test(timer, runtime):
print(f" Interval test fired at {runtime}ms") print(f" Interval test fired at {runtime}ms")
timer4 = mcrfpy.Timer("interval_test", interval_test, 1000) timer4 = mcrfpy.Timer("interval_test", interval_test, 1000)
print(f" Original interval: {timer4.interval}ms") print(f" Original interval: {timer4.interval}ms")
timer4.interval = 500 timer4.interval = 500
print(f" Modified interval: {timer4.interval}ms") print(f" Modified interval: {timer4.interval}ms")
# Test 5: Test remaining time # Test 5: Test remaining time
print("\nTest 5: Testing remaining time") print("\nTest 5: Testing remaining time")
def check_remaining(runtime): def check_remaining(t, rt):
if timer1.active: if timer1.active:
print(f" Timer1 remaining: {timer1.remaining}ms") print(f" Timer1 remaining: {timer1.remaining}ms")
if timer2.active or timer2.paused: if timer2.active or timer2.paused:
print(f" Timer2 remaining: {timer2.remaining}ms (paused: {timer2.paused})") print(f" Timer2 remaining: {timer2.remaining}ms (paused: {timer2.paused})")
mcrfpy.setTimer("check_remaining", check_remaining, 150) remaining_timer = mcrfpy.Timer("check_remaining", check_remaining, 150)
# Test 6: Test restart # Test 6: Test restart
print("\nTest 6: Testing restart functionality") print("\nTest 6: Testing restart functionality")
restart_count = [0] restart_count = [0]
def restart_test(timer, runtime): def restart_test(timer, runtime):
restart_count[0] += 1 restart_count[0] += 1
print(f" Restart test: {restart_count[0]}") print(f" Restart test: {restart_count[0]}")
if restart_count[0] == 2: if restart_count[0] == 2:
print(" Restarting timer...") print(" Restarting timer...")
timer.restart() timer.restart()
timer5 = mcrfpy.Timer("restart_test", restart_test, 400) timer5 = mcrfpy.Timer("restart_test", restart_test, 400)
# Final verification after 2 seconds # Final verification after 2 seconds
def final_check(runtime): def final_check(t, rt):
print("\n=== Final Results ===") print("\n=== Final Results ===")
print(f"Timer1 call count: {call_count} (expected: ~4)") print(f"Timer1 call count: {call_count} (expected: ~4)")
print(f"Pause test count: {pause_test_count} (expected: ~6-7, with pause gap)") print(f"Pause test count: {pause_test_count} (expected: ~6-7, with pause gap)")
print(f"Cancel test count: {cancel_test_count} (expected: 1)") print(f"Cancel test count: {cancel_test_count} (expected: 1)")
print(f"Restart test count: {restart_count[0]} (expected: ~5 with restart)") print(f"Restart test count: {restart_count[0]} (expected: ~5 with restart)")
# Verify timer states # Verify timer states
try: try:
print(f"\nTimer1 active: {timer1.active}") print(f"\nTimer1 active: {timer1.active}")
print(f"Timer2 active: {timer2.active}") print(f"Timer2 active: {timer2.active}")
print(f"Timer3 active: {timer3.active} (should be False after cancel)") print(f"Timer3 active: {timer3.active} (should be False after stop)")
print(f"Timer4 active: {timer4.active}") print(f"Timer4 active: {timer4.active}")
print(f"Timer5 active: {timer5.active}") print(f"Timer5 active: {timer5.active}")
except: except:
print("Some timers may have been garbage collected") print("Some timers may have been garbage collected")
print("\n✓ All Timer object tests completed!") print("\n✓ All Timer object tests completed!")
sys.exit(0) sys.exit(0)
mcrfpy.setTimer("final_check", final_check, 2000) mcrfpy.Timer("final_check", final_check, 2000, once=True)
# Create a minimal scene # Create a minimal scene
timer_test = mcrfpy.Scene("timer_test") timer_test = mcrfpy.Scene("timer_test")
timer_test.activate() timer_test.activate()
# Start tests after game loop begins # Start tests after game loop begins
mcrfpy.setTimer("run_tests", run_tests, 100) mcrfpy.Timer("run_tests", run_tests, 100, once=True)
print("Timer object tests starting...") print("Timer object tests starting...")

View file

@ -4,18 +4,18 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
import sys import sys
def take_screenshot(runtime): def take_screenshot(timer, runtime):
"""Take screenshot after render completes""" """Take screenshot after render completes"""
mcrfpy.delTimer("screenshot") timer.stop()
automation.screenshot("test_uiarc_result.png") automation.screenshot("test_uiarc_result.png")
print("Screenshot saved to test_uiarc_result.png") print("Screenshot saved to test_uiarc_result.png")
print("PASS - UIArc test completed") print("PASS - UIArc test completed")
sys.exit(0) sys.exit(0)
def run_test(runtime): def run_test(timer, runtime):
"""Main test - runs after scene is set up""" """Main test - runs after scene is set up"""
mcrfpy.delTimer("test") timer.stop()
# Get the scene UI # Get the scene UI
ui = test.children ui = test.children
@ -127,11 +127,12 @@ def run_test(runtime):
print(f" Arc 10 (reverse): {a10}") print(f" Arc 10 (reverse): {a10}")
# Schedule screenshot for next frame # Schedule screenshot for next frame
mcrfpy.setTimer("screenshot", take_screenshot, 50) global screenshot_timer
screenshot_timer = mcrfpy.Timer("screenshot", take_screenshot, 50, once=True)
# Create a test scene # Create a test scene
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test to run after game loop starts # Schedule test to run after game loop starts
mcrfpy.setTimer("test", run_test, 50) test_timer = mcrfpy.Timer("test", run_test, 50, once=True)

View file

@ -6,7 +6,7 @@ from mcrfpy import automation
import sys import sys
import time import time
def run_visual_test(runtime): def run_visual_test(timer, runtime):
"""Timer callback to run visual tests and take screenshots.""" """Timer callback to run visual tests and take screenshots."""
print("\nRunning visual tests...") print("\nRunning visual tests...")
@ -89,9 +89,9 @@ def main():
ui.append(frame) ui.append(frame)
print("Scene setup complete. Scheduling visual tests...") print("Scene setup complete. Scheduling visual tests...")
# Schedule visual test to run after render loop starts # Schedule visual test to run after render loop starts
mcrfpy.setTimer("visual_test", run_visual_test, 100) visual_test_timer = mcrfpy.Timer("visual_test", run_visual_test, 100, once=True)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -4,18 +4,18 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
import sys import sys
def take_screenshot(runtime): def take_screenshot(timer, runtime):
"""Take screenshot after render completes""" """Take screenshot after render completes"""
mcrfpy.delTimer("screenshot") timer.stop()
automation.screenshot("test_uicircle_result.png") automation.screenshot("test_uicircle_result.png")
print("Screenshot saved to test_uicircle_result.png") print("Screenshot saved to test_uicircle_result.png")
print("PASS - UICircle test completed") print("PASS - UICircle test completed")
sys.exit(0) sys.exit(0)
def run_test(runtime): def run_test(timer, runtime):
"""Main test - runs after scene is set up""" """Main test - runs after scene is set up"""
mcrfpy.delTimer("test") timer.stop()
# Get the scene UI # Get the scene UI
ui = test.children ui = test.children
@ -118,11 +118,12 @@ def run_test(runtime):
print(f" c1 moved from {old_center} to {new_center}") print(f" c1 moved from {old_center} to {new_center}")
# Schedule screenshot for next frame # Schedule screenshot for next frame
mcrfpy.setTimer("screenshot", take_screenshot, 50) global screenshot_timer
screenshot_timer = mcrfpy.Timer("screenshot", take_screenshot, 50, once=True)
# Create a test scene # Create a test scene
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
test.activate() test.activate()
# Schedule test to run after game loop starts # Schedule test to run after game loop starts
mcrfpy.setTimer("test", run_test, 50) test_timer = mcrfpy.Timer("test", run_test, 50, once=True)

View file

@ -6,7 +6,7 @@ Test UTF-8 encoding support
import mcrfpy import mcrfpy
import sys import sys
def test_utf8(runtime): def test_utf8(timer, runtime):
"""Test UTF-8 encoding in print statements""" """Test UTF-8 encoding in print statements"""
# Test various unicode characters # Test various unicode characters
@ -32,4 +32,4 @@ def test_utf8(runtime):
# Run test # Run test
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
mcrfpy.setTimer("test", test_utf8, 100) test_timer = mcrfpy.Timer("test", test_utf8, 100, once=True)

View file

@ -7,7 +7,7 @@ import mcrfpy
import sys import sys
import math import math
def test_vector_arithmetic(runtime): def test_vector_arithmetic(timer, runtime):
"""Test vector arithmetic operations""" """Test vector arithmetic operations"""
all_pass = True all_pass = True
@ -244,4 +244,4 @@ def test_vector_arithmetic(runtime):
# Run test # Run test
test = mcrfpy.Scene("test") test = mcrfpy.Scene("test")
mcrfpy.setTimer("test", test_vector_arithmetic, 100) test_timer = mcrfpy.Timer("test", test_vector_arithmetic, 100, once=True)

View file

@ -5,9 +5,9 @@ import mcrfpy
from mcrfpy import Window, Frame, Caption, Color, Vector from mcrfpy import Window, Frame, Caption, Color, Vector
import sys import sys
def test_viewport_modes(runtime): def test_viewport_modes(timer, runtime):
"""Test all three viewport scaling modes""" """Test all three viewport scaling modes"""
mcrfpy.delTimer("test_viewport") timer.stop()
print("Testing viewport scaling modes...") print("Testing viewport scaling modes...")
@ -82,47 +82,47 @@ def test_viewport_modes(runtime):
scene.append(instructions) scene.append(instructions)
# Test changing modes # Test changing modes
def test_mode_changes(runtime): def test_mode_changes(t, r):
mcrfpy.delTimer("test_modes") t.stop()
from mcrfpy import automation from mcrfpy import automation
print("\nTesting scaling modes:") print("\nTesting scaling modes:")
# Test center mode # Test center mode
window.scaling_mode = "center" window.scaling_mode = "center"
print(f"Set to center mode: {window.scaling_mode}") print(f"Set to center mode: {window.scaling_mode}")
mode_text.text = f"Mode: center (1:1 pixels)" mode_text.text = f"Mode: center (1:1 pixels)"
automation.screenshot("viewport_center_mode.png") automation.screenshot("viewport_center_mode.png")
# Schedule next mode test # Schedule next mode test
mcrfpy.setTimer("test_stretch", test_stretch_mode, 1000) mcrfpy.Timer("test_stretch", test_stretch_mode, 1000, once=True)
def test_stretch_mode(runtime): def test_stretch_mode(t, r):
mcrfpy.delTimer("test_stretch") t.stop()
from mcrfpy import automation from mcrfpy import automation
window.scaling_mode = "stretch" window.scaling_mode = "stretch"
print(f"Set to stretch mode: {window.scaling_mode}") print(f"Set to stretch mode: {window.scaling_mode}")
mode_text.text = f"Mode: stretch (fill window)" mode_text.text = f"Mode: stretch (fill window)"
automation.screenshot("viewport_stretch_mode.png") automation.screenshot("viewport_stretch_mode.png")
# Schedule next mode test # Schedule next mode test
mcrfpy.setTimer("test_fit", test_fit_mode, 1000) mcrfpy.Timer("test_fit", test_fit_mode, 1000, once=True)
def test_fit_mode(runtime): def test_fit_mode(t, r):
mcrfpy.delTimer("test_fit") t.stop()
from mcrfpy import automation from mcrfpy import automation
window.scaling_mode = "fit" window.scaling_mode = "fit"
print(f"Set to fit mode: {window.scaling_mode}") print(f"Set to fit mode: {window.scaling_mode}")
mode_text.text = f"Mode: fit (aspect ratio maintained)" mode_text.text = f"Mode: fit (aspect ratio maintained)"
automation.screenshot("viewport_fit_mode.png") automation.screenshot("viewport_fit_mode.png")
# Test different window sizes # Test different window sizes
mcrfpy.setTimer("test_resize", test_window_resize, 1000) mcrfpy.Timer("test_resize", test_window_resize, 1000, once=True)
def test_window_resize(runtime): def test_window_resize(t, r):
mcrfpy.delTimer("test_resize") t.stop()
from mcrfpy import automation from mcrfpy import automation
print("\nTesting window resize with fit mode:") print("\nTesting window resize with fit mode:")
@ -133,13 +133,13 @@ def test_viewport_modes(runtime):
print(f"Window resized to: {window.resolution}") print(f"Window resized to: {window.resolution}")
automation.screenshot("viewport_fit_wide.png") automation.screenshot("viewport_fit_wide.png")
# Make window taller # Make window taller
mcrfpy.setTimer("test_tall", test_tall_window, 1000) mcrfpy.Timer("test_tall", test_tall_window, 1000, once=True)
except RuntimeError as e: except RuntimeError as e:
print(f" Skipping window resize tests (headless mode): {e}") print(f" Skipping window resize tests (headless mode): {e}")
mcrfpy.setTimer("test_game_res", test_game_resolution, 100) mcrfpy.Timer("test_game_res", test_game_resolution, 100, once=True)
def test_tall_window(runtime): def test_tall_window(t, r):
mcrfpy.delTimer("test_tall") t.stop()
from mcrfpy import automation from mcrfpy import automation
try: try:
@ -150,10 +150,10 @@ def test_viewport_modes(runtime):
print(f" Skipping tall window test (headless mode): {e}") print(f" Skipping tall window test (headless mode): {e}")
# Test game resolution change # Test game resolution change
mcrfpy.setTimer("test_game_res", test_game_resolution, 1000) mcrfpy.Timer("test_game_res", test_game_resolution, 1000, once=True)
def test_game_resolution(runtime): def test_game_resolution(t, r):
mcrfpy.delTimer("test_game_res") t.stop()
print("\nTesting game resolution change:") print("\nTesting game resolution change:")
window.game_resolution = (800, 600) window.game_resolution = (800, 600)
@ -178,9 +178,9 @@ def test_viewport_modes(runtime):
window.scaling_mode = "fit" window.scaling_mode = "fit"
sys.exit(0) sys.exit(0)
# Start test sequence # Start test sequence
mcrfpy.setTimer("test_modes", test_mode_changes, 500) mcrfpy.Timer("test_modes", test_mode_changes, 500, once=True)
# Set up keyboard handler for manual testing # Set up keyboard handler for manual testing
def handle_keypress(key, state): def handle_keypress(key, state):
@ -240,7 +240,7 @@ test.activate()
test.on_key = handle_keypress test.on_key = handle_keypress
# Schedule the test # Schedule the test
mcrfpy.setTimer("test_viewport", test_viewport_modes, 100) test_viewport_timer = mcrfpy.Timer("test_viewport", test_viewport_modes, 100, once=True)
print("Viewport test running...") print("Viewport test running...")
print("Use number keys to switch modes, R to resize window, G to change game resolution") print("Use number keys to switch modes, R to resize window, G to change game resolution")

View file

@ -75,7 +75,7 @@ print(f" Expected: {20 * 15}")
print("\nTest 2: Updating visibility for each entity") print("\nTest 2: Updating visibility for each entity")
for i, entity in enumerate(entities): for i, entity in enumerate(entities):
entity.update_visibility() entity.update_visibility()
# Count visible/discovered cells # Count visible/discovered cells
visible_count = sum(1 for state in entity.gridstate if state.visible) visible_count = sum(1 for state in entity.gridstate if state.visible)
discovered_count = sum(1 for state in entity.gridstate if state.discovered) discovered_count = sum(1 for state in entity.gridstate if state.discovered)
@ -95,9 +95,9 @@ except IndexError as e:
print(f" ✓ Correctly rejected invalid perspective: {e}") print(f" ✓ Correctly rejected invalid perspective: {e}")
# Test 4: Visual demonstration # Test 4: Visual demonstration
def visual_test(runtime): def visual_test(timer, runtime):
print(f"\nVisual test - cycling perspectives at {runtime}ms") print(f"\nVisual test - cycling perspectives at {runtime}ms")
# Cycle through perspectives # Cycle through perspectives
current = grid.perspective current = grid.perspective
if current == -1: if current == -1:
@ -112,7 +112,7 @@ def visual_test(runtime):
else: else:
grid.perspective = -1 grid.perspective = -1
print(" Switched to omniscient view") print(" Switched to omniscient view")
# Take screenshot # Take screenshot
from mcrfpy import automation from mcrfpy import automation
filename = f"visibility_perspective_{grid.perspective}.png" filename = f"visibility_perspective_{grid.perspective}.png"
@ -159,14 +159,14 @@ ui.append(legend)
visibility_test.activate() visibility_test.activate()
# Set timer to cycle perspectives # Set timer to cycle perspectives
mcrfpy.setTimer("cycle", visual_test, 2000) # Every 2 seconds cycle_timer = mcrfpy.Timer("cycle", visual_test, 2000) # Every 2 seconds
print("\nTest complete! Visual demo cycling through perspectives...") print("\nTest complete! Visual demo cycling through perspectives...")
print("Perspectives will cycle: Omniscient → Entity 0 → Entity 1 → Entity 2 → Omniscient") print("Perspectives will cycle: Omniscient → Entity 0 → Entity 1 → Entity 2 → Omniscient")
# Quick test to exit after screenshots # Quick test to exit after screenshots
def exit_timer(dt): def exit_timer_cb(timer, runtime):
print("\nExiting after demo...") print("\nExiting after demo...")
sys.exit(0) sys.exit(0)
mcrfpy.setTimer("exit", exit_timer, 10000) # Exit after 10 seconds exit_timer_obj = mcrfpy.Timer("exit", exit_timer_cb, 10000, once=True) # Exit after 10 seconds

View file

@ -19,9 +19,9 @@ grid.fill_color = mcrfpy.Color(0, 0, 0)
# Add color layer for cell coloring # Add color layer for cell coloring
color_layer = grid.add_layer("color", z_index=-1) color_layer = grid.add_layer("color", z_index=-1)
def check_render(dt): def check_render(timer, runtime):
"""Timer callback to verify rendering""" """Timer callback to verify rendering"""
print(f"\nTimer fired after {dt}ms") print(f"\nTimer fired after {runtime}ms")
# Take screenshot # Take screenshot
from mcrfpy import automation from mcrfpy import automation
@ -78,6 +78,6 @@ ui.append(title)
visual_test.activate() visual_test.activate()
# Set timer to check rendering # Set timer to check rendering
mcrfpy.setTimer("check", check_render, 500) check_timer = mcrfpy.Timer("check", check_render, 500, once=True)
print("\nScene ready. Path should be visible in green.") print("\nScene ready. Path should be visible in green.")

View file

@ -4,7 +4,7 @@ import mcrfpy
from mcrfpy import automation from mcrfpy import automation
import sys import sys
def test_grid_none_texture(runtime): def test_grid_none_texture(timer, runtime):
"""Test Grid functionality without texture""" """Test Grid functionality without texture"""
print("\n=== Testing Grid with None texture ===") print("\n=== Testing Grid with None texture ===")
@ -95,5 +95,5 @@ background = mcrfpy.Frame(pos=(0, 0), size=(800, 600),
ui.append(background) ui.append(background)
# Schedule test # Schedule test
mcrfpy.setTimer("test", test_grid_none_texture, 100) test_timer = mcrfpy.Timer("test", test_grid_none_texture, 100, once=True)
print("Test scheduled...") print("Test scheduled...")