#!/usr/bin/env python3 """ Perspective Patrol Demo ======================= Demonstrates the FOV/perspective system with an animated patrolling entity. Features: - 20x20 grid with 10x10 opaque obstacle in center - Entity patrols around the obstacle in a square pattern - ColorLayer shows fog of war (visible/discovered/unknown) - Press 'R' to reset vision (shows unknown vs discovered difference) - Press 'Space' to pause/resume patrol """ import mcrfpy # Patrol waypoints (clockwise around the center obstacle) WAYPOINTS = [ (3, 3), # Top-left (16, 3), # Top-right (16, 16), # Bottom-right (3, 16), # Bottom-left ] # State current_waypoint = 0 patrol_paused = False move_timer_ms = 150 # Time between moves # Global references g_grid = None g_patrol = None g_fov_layer = None def setup_scene(): """Create the demo scene""" global g_grid, g_patrol, g_fov_layer mcrfpy.createScene("patrol_demo") mcrfpy.setScene("patrol_demo") ui = mcrfpy.sceneUI("patrol_demo") # Title title = mcrfpy.Caption(text="Perspective Patrol Demo", pos=(10, 10)) title.fill_color = mcrfpy.Color(255, 255, 255) ui.append(title) # Instructions instructions = mcrfpy.Caption(text="[R] Reset vision [Space] Pause/Resume [Q] Quit", pos=(10, 35)) instructions.fill_color = mcrfpy.Color(180, 180, 180) ui.append(instructions) # Create grid (20x20, each cell 24px) - centered in 1024x768 window grid_size_px = 480 grid = mcrfpy.Grid( pos=((1024 - grid_size_px) // 2, (768 - grid_size_px) // 2), size=(grid_size_px, grid_size_px), grid_size=(20, 20), texture=None ) grid.center = (10*16, 10*16) grid.fill_color = mcrfpy.Color(40, 40, 50) # Dark floor background ui.append(grid) # Set FOV settings grid.fov = mcrfpy.FOV.SHADOW grid.fov_radius = 8 # Initialize all cells as walkable/transparent (floor) for y in range(20): for x in range(20): point = grid.at(x, y) point.walkable = True point.transparent = True # Create 10x10 obstacle box in center (cells 5-14 in both dimensions) for y in range(5, 15): for x in range(5, 15): point = grid.at(x, y) point.walkable = False point.transparent = False # Create a color layer for the walls (so we can see them) wall_layer = grid.add_layer('color', z_index=-2) wall_layer.fill((40, 40, 50, 255)) # Match floor color # Draw walls on the wall layer for y in range(5, 15): for x in range(5, 15): wall_layer.set(x, y, mcrfpy.Color(100, 70, 50, 255)) # Brown walls # Create FOV layer (above walls, below entities) fov_layer = grid.add_layer('color', z_index=-1) fov_layer.fill((0, 0, 0, 255)) # Start completely black (unknown) # Create patrolling entity patrol = mcrfpy.Entity(WAYPOINTS[0]) patrol.sprite_index = 64 # '@' character typically grid.entities.append(patrol) # Bind FOV layer to entity fov_layer.apply_perspective( entity=patrol, visible=(0, 0, 0, 0), # Fully transparent when visible discovered=(20, 20, 40, 180), # Dark blue-gray when discovered unknown=(0, 0, 0, 255) # Black when never seen ) # Initial visibility update patrol.update_visibility() # Store references for timer callbacks g_grid = grid g_patrol = patrol g_fov_layer = fov_layer # Status caption (below centered grid) status = mcrfpy.Caption(text="Status: Patrolling", pos=(10, 720)) status.fill_color = mcrfpy.Color(100, 255, 100) status.name = "status" ui.append(status) # Set up keyboard handler mcrfpy.keypressScene(on_keypress) # Start patrol timer mcrfpy.setTimer("patrol", patrol_step, move_timer_ms) def patrol_step(runtime): """Move entity one step toward current waypoint""" global current_waypoint, patrol_paused if patrol_paused: return # Get current position and target px, py = int(g_patrol.x), int(g_patrol.y) tx, ty = WAYPOINTS[current_waypoint] # Calculate direction dx = 0 if tx == px else (1 if tx > px else -1) dy = 0 if ty == py else (1 if ty > py else -1) # Move one step (prefer horizontal, then vertical) if dx != 0: g_patrol.x = px + dx elif dy != 0: g_patrol.y = py + dy # Update visibility after move g_patrol.update_visibility() # Check if reached waypoint if int(g_patrol.x) == tx and int(g_patrol.y) == ty: current_waypoint = (current_waypoint + 1) % len(WAYPOINTS) update_status(f"Reached waypoint, heading to {WAYPOINTS[current_waypoint]}") def on_keypress(key, state): """Handle keyboard input""" global patrol_paused if state != "start": return if key == "R": reset_vision() elif key == "Space": patrol_paused = not patrol_paused if patrol_paused: update_status("Status: PAUSED") else: update_status("Status: Patrolling") elif key == "Q": mcrfpy.setScene(None) def reset_vision(): """Reset entity's discovered state to demonstrate unknown vs discovered""" global g_patrol, g_fov_layer # Clear entity's gridstate (forget everything) for state in g_patrol.gridstate: state.visible = False state.discovered = False # Re-fill the layer with unknown color g_fov_layer.fill((0, 0, 0, 255)) # Update visibility from current position (will mark current FOV as visible) g_patrol.update_visibility() update_status("Vision RESET - watch discovered vs unknown!") def update_status(text): """Update status caption""" ui = mcrfpy.sceneUI("patrol_demo") for element in ui: if hasattr(element, 'name') and element.name == "status": element.text = text break # Run the demo setup_scene()