diff --git a/core/simulation_engine.py b/core/simulation_engine.py index dd60b43..3ed0a80 100644 --- a/core/simulation_engine.py +++ b/core/simulation_engine.py @@ -27,6 +27,16 @@ class SimulationEngine: self._init_ui() self.running = True + # HUD action handlers registry for extensibility + self._hud_action_handlers = { + 'toggle_pause': self.simulation_core.toggle_pause, + 'step_forward': self.simulation_core.step, + 'toggle_sprint': self.simulation_core.toggle_sprint_mode, + 'viewport_resized': self._update_simulation_view, + 'set_speed': self.simulation_core.set_speed_multiplier, + 'set_custom_tps': self.simulation_core.set_tps, + } + def _profile_single_tick(self): """Profile a single tick for performance analysis.""" profiler = cProfile.Profile() @@ -83,11 +93,7 @@ class SimulationEngine: self.input_handler.default_tps = DEFAULT_TPS # Set up action callbacks for input handler - self.input_handler.set_action_callback('toggle_pause', self.simulation_core.toggle_pause) - self.input_handler.set_action_callback('step_forward', self.simulation_core.step) - self.input_handler.set_action_callback('set_speed', self.simulation_core.set_speed_multiplier) - self.input_handler.set_action_callback('set_custom_tps', self.simulation_core.set_tps) - self.input_handler.set_action_callback('toggle_sprint', self.simulation_core.toggle_sprint_mode) + self._setup_input_handler_callbacks() # Setup renderer self.renderer = Renderer(self.sim_view) @@ -112,6 +118,19 @@ class SimulationEngine: # Update input handler simulation view rect self.input_handler.update_sim_view_rect(self.sim_view_rect) + def _setup_input_handler_callbacks(self): + """Set up action callbacks for input handler.""" + callbacks = { + 'toggle_pause': self.simulation_core.toggle_pause, + 'step_forward': self.simulation_core.step, + 'set_speed': self.simulation_core.set_speed_multiplier, + 'set_custom_tps': self.simulation_core.set_tps, + 'toggle_sprint': self.simulation_core.toggle_sprint_mode, + } + + for action, callback in callbacks.items(): + self.input_handler.set_action_callback(action, callback) + def _count_cells(self): """Count cells in the simulation.""" # Import locally to avoid circular import @@ -142,7 +161,7 @@ class SimulationEngine: # Process HUD events and window events for event in events: hud_action = self.hud.process_event(event) - self._handle_hud_actions(hud_action) + self._process_hud_action(hud_action) if event.type == pygame.VIDEORESIZE: self._handle_window_resize(event) @@ -170,8 +189,8 @@ class SimulationEngine: self.input_handler.update_selected_objects() # Render frame - self._update(deltatime) - self._render() + self._update_frame(deltatime) + self._render_frame() def _sync_input_and_timing(self): """Synchronize input handler state with simulation core timing.""" @@ -189,6 +208,73 @@ class SimulationEngine: # Sync speed multiplier self.input_handler.speed_multiplier = timing_state.speed_multiplier + def _update_frame(self, deltatime): + """Update camera and input state.""" + keys = pygame.key.get_pressed() + self.input_handler.update_camera(keys, deltatime) + + def _render_frame(self): + """Render the complete frame.""" + self.screen.fill(BLACK) + self.renderer.clear_screen() + + # Render simulation world + self._render_simulation_world() + + # Update and render UI + self._update_and_render_ui() + + # Render HUD overlays + self._render_hud_overlays() + + pygame.display.flip() + self.clock.tick(MAX_FPS) + + def _render_simulation_world(self): + """Render the simulation world if not dragging splitter.""" + if not self.hud.dragging_splitter: + self.renderer.draw_grid(self.simulation_core.camera, self.input_handler.show_grid) + self.renderer.render_world(self.simulation_core.world, self.simulation_core.camera) + self.renderer.render_interaction_radius( + self.simulation_core.world, + self.simulation_core.camera, + self.input_handler.selected_objects, + self.input_handler.show_interaction_radius + ) + self.renderer.render_selection_rectangle( + self.input_handler.get_selection_rect(), + self.sim_view_rect + ) + self.renderer.render_selected_objects_outline( + self.input_handler.selected_objects, + self.simulation_core.camera + ) + self.screen.blit(self.sim_view, (self.sim_view_rect.left, self.sim_view_rect.top)) + + def _update_and_render_ui(self): + """Update UI elements and render them.""" + # Update HUD displays with simulation core state + self.hud.update_simulation_controls(self.simulation_core) + + # Draw UI elements + self.hud.manager.draw_ui(self.screen) + self.hud.draw_splitters(self.screen) + + def _render_hud_overlays(self): + """Render HUD overlay elements.""" + self.hud.render_fps(self.screen, self.clock) + self.hud.render_tps(self.screen, self.simulation_core.state.actual_tps) + self.hud.render_selected_objects_info(self.screen, self.input_handler.selected_objects) + self.hud.render_legend(self.screen, self.input_handler.show_legend) + self.hud.render_pause_indicator(self.screen, self.simulation_core.timing.state.is_paused) + + # Render neural network visualization for selected object + if self.input_handler.selected_objects: + self.hud.render_neural_network_visualization( + self.screen, + self.input_handler.selected_objects[0] + ) + def _handle_window_resize(self, event): """Handle window resize event.""" self.window_width, self.window_height = event.w, event.h @@ -199,26 +285,41 @@ class SimulationEngine: self._update_simulation_view() self.hud.update_layout(self.window_width, self.window_height) - - def _handle_hud_actions(self, action): - """Handle actions from HUD simulation controls by forwarding to simulation core.""" - if action == 'toggle_pause': - self.simulation_core.toggle_pause() - elif action == 'step_forward': - self.simulation_core.step() - elif action == 'toggle_sprint': - self.simulation_core.toggle_sprint_mode() - elif isinstance(action, tuple) and action[0] == 'set_speed': - self.simulation_core.set_speed_multiplier(action[1]) - elif isinstance(action, tuple) and action[0] == 'set_custom_tps': - self.simulation_core.set_tps(action[1]) - elif isinstance(action, tuple) and action[0] == 'reset_tps_display': - # Reset TPS display to current value - if self.hud.custom_tps_entry: - self.hud.custom_tps_entry.set_text(str(int(self.simulation_core.timing.state.tps))) - elif action == 'viewport_resized': - # Update simulation viewport when panels are resized - self._update_simulation_view() + def _process_hud_action(self, action): + """Process a single HUD action using the handler registry.""" + if not action: + return + + # Handle simple actions directly + if action in self._hud_action_handlers: + self._hud_action_handlers[action]() + return + + # Handle parameterized actions + if isinstance(action, tuple) and len(action) >= 2: + action_type, param = action[0], action[1] + + if action_type == 'set_speed': + self.simulation_core.set_speed_multiplier(param) + elif action_type == 'set_custom_tps': + self.simulation_core.set_tps(param) + elif action_type == 'reset_tps_display': + self._reset_tps_display() + + def _reset_tps_display(self): + """Reset TPS display to current simulation value.""" + if self.hud.custom_tps_entry: + current_tps = int(self.simulation_core.timing.state.tps) + self.hud.custom_tps_entry.set_text(str(current_tps)) + + def register_hud_action(self, action_name: str, handler): + """Register a new HUD action handler for extensibility. + + Args: + action_name: Name of the HUD action + handler: Callable that handles the action + """ + self._hud_action_handlers[action_name] = handler def _handle_sprint_mode(self): """Handle sprint mode by running multiple simulation ticks quickly.""" @@ -241,56 +342,4 @@ class SimulationEngine: pygame.display.flip() self.clock.tick(MAX_FPS) - def _update(self, deltatime): - """Update camera based on input.""" - keys = pygame.key.get_pressed() - self.input_handler.update_camera(keys, deltatime) - - def _render(self): - """Render the simulation frame.""" - self.screen.fill(BLACK) - self.renderer.clear_screen() - - if not self.hud.dragging_splitter: - # Render world - self.renderer.draw_grid(self.simulation_core.camera, self.input_handler.show_grid) - self.renderer.render_world(self.simulation_core.world, self.simulation_core.camera) - self.renderer.render_interaction_radius( - self.simulation_core.world, - self.simulation_core.camera, - self.input_handler.selected_objects, - self.input_handler.show_interaction_radius - ) - self.renderer.render_selection_rectangle( - self.input_handler.get_selection_rect(), - self.sim_view_rect - ) - self.renderer.render_selected_objects_outline( - self.input_handler.selected_objects, - self.simulation_core.camera - ) - self.screen.blit(self.sim_view, (self.sim_view_rect.left, self.sim_view_rect.top)) - - # Update HUD displays with simulation core state - self.hud.update_simulation_controls(self.simulation_core) - - # Draw UI elements - self.hud.manager.draw_ui(self.screen) - self.hud.draw_splitters(self.screen) - - # Render HUD overlays - self.hud.render_fps(self.screen, self.clock) - self.hud.render_tps(self.screen, self.simulation_core.state.actual_tps) - self.hud.render_selected_objects_info(self.screen, self.input_handler.selected_objects) - self.hud.render_legend(self.screen, self.input_handler.show_legend) - self.hud.render_pause_indicator(self.screen, self.simulation_core.timing.state.is_paused) - - # Render neural network visualization for selected object - if self.input_handler.selected_objects: - self.hud.render_neural_network_visualization( - self.screen, - self.input_handler.selected_objects[0] - ) - - pygame.display.flip() - self.clock.tick(MAX_FPS) \ No newline at end of file + \ No newline at end of file