184 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # core/input_handler.py
 | |
| """Handles all input events and camera controls."""
 | |
| 
 | |
| import pygame
 | |
| from config.constants import *
 | |
| 
 | |
| 
 | |
| class InputHandler:
 | |
|     def __init__(self, camera, world, sim_view_rect):
 | |
|         self.camera = camera
 | |
|         self.world = world
 | |
| 
 | |
|         # Selection state
 | |
|         self.selecting = False
 | |
|         self.select_start = None
 | |
|         self.select_end = None
 | |
|         self.selected_objects = []
 | |
| 
 | |
|         # UI state flags
 | |
|         self.show_grid = True
 | |
|         self.show_interaction_radius = False
 | |
|         self.show_legend = False
 | |
|         self.is_paused = False
 | |
| 
 | |
|         # Speed control
 | |
|         self.tps = DEFAULT_TPS
 | |
|         self.default_tps = DEFAULT_TPS
 | |
|         self.sprint_mode = False
 | |
| 
 | |
|         # sim-view rect for mouse position calculations
 | |
|         self.sim_view_rect = sim_view_rect
 | |
| 
 | |
|     def update_sim_view_rect(self, sim_view_rect):
 | |
|         """Update the sim_view rectangle."""
 | |
|         self.sim_view_rect = sim_view_rect
 | |
| 
 | |
|     def handle_events(self, events, ui_manager):
 | |
|         """Process all pygame events and return game state."""
 | |
|         running = True
 | |
| 
 | |
|         for event in events:
 | |
|             ui_manager.process_events(event)
 | |
| 
 | |
|             if event.type == pygame.QUIT:
 | |
|                 running = False
 | |
|             elif event.type == pygame.KEYDOWN:
 | |
|                 running = self._handle_keydown(event, running)
 | |
|             elif event.type == pygame.KEYUP:
 | |
|                 self._handle_keyup(event)
 | |
|             elif event.type == pygame.MOUSEWHEEL:
 | |
|                 self.camera.handle_zoom(event.y)
 | |
|             elif event.type == pygame.MOUSEBUTTONDOWN:
 | |
|                 self._handle_mouse_down(event)
 | |
|             elif event.type == pygame.MOUSEBUTTONUP:
 | |
|                 self._handle_mouse_up(event)
 | |
|             elif event.type == pygame.MOUSEMOTION:
 | |
|                 self._handle_mouse_motion(event)
 | |
| 
 | |
|         return running
 | |
| 
 | |
|     def _handle_keydown(self, event, running):
 | |
|         """Handle keydown events."""
 | |
|         if event.key == pygame.K_ESCAPE:
 | |
|             if len(self.selected_objects) == 0:
 | |
|                 running = False
 | |
|             else:
 | |
|                 self.selecting = False
 | |
|                 self.selected_objects = []
 | |
|         elif event.key == pygame.K_g:
 | |
|             self.show_grid = not self.show_grid
 | |
|         elif event.key == pygame.K_UP:
 | |
|             if self.camera.speed < MAX_CAMERA_SPEED:
 | |
|                 self.camera.speed += CAMERA_SPEED_INCREMENT
 | |
|         elif event.key == pygame.K_DOWN:
 | |
|             if self.camera.speed > MIN_CAMERA_SPEED:
 | |
|                 self.camera.speed -= CAMERA_SPEED_INCREMENT
 | |
|         elif event.key == pygame.K_i:
 | |
|             self.show_interaction_radius = not self.show_interaction_radius
 | |
|         elif event.key == pygame.K_l:
 | |
|             self.show_legend = not self.show_legend
 | |
|         elif event.key == pygame.K_SPACE:
 | |
|             self.is_paused = not self.is_paused
 | |
|         elif event.key == pygame.K_LSHIFT:
 | |
|             self.tps = self.default_tps * TURBO_MULTIPLIER
 | |
|         elif event.key == pygame.K_r:
 | |
|             self.camera.reset_position()
 | |
|         elif event.key == pygame.K_RSHIFT:
 | |
|             self.sprint_mode = not self.sprint_mode  # Enter sprint mode
 | |
| 
 | |
|         return running
 | |
| 
 | |
|     def _handle_keyup(self, event):
 | |
|         """Handle keyup events."""
 | |
|         if event.key == pygame.K_LSHIFT:
 | |
|             self.tps = self.default_tps
 | |
|         # if event.key == pygame.K_RSHIFT:
 | |
|         #     self.sprint_mode = False  # Exit sprint mode
 | |
| 
 | |
|     def _handle_mouse_down(self, event):
 | |
|         """Handle mouse button down events."""
 | |
|         if event.button == 2:  # Middle mouse button
 | |
|             self.camera.start_panning(event.pos)
 | |
|         elif event.button == 1:  # Left mouse button
 | |
|             self.selecting = True
 | |
|             self.select_start = event.pos
 | |
|             self.select_end = event.pos
 | |
| 
 | |
|     def _handle_mouse_up(self, event):
 | |
|         """Handle mouse button up events."""
 | |
|         if event.button == 2:
 | |
|             self.camera.stop_panning()
 | |
|         elif event.button == 1 and self.selecting:
 | |
|             self._handle_selection()
 | |
| 
 | |
|     def _handle_mouse_motion(self, event):
 | |
|         """Handle mouse motion events."""
 | |
|         self.camera.pan(event.pos)
 | |
|         if self.selecting:
 | |
|             self.select_end = event.pos
 | |
| 
 | |
|     def _handle_selection(self):
 | |
|         """Process object selection logic."""
 | |
|         self.selecting = False
 | |
| 
 | |
|         # Map screen to sim_view coordinates
 | |
|         sx1 = self.select_start[0] - self.sim_view_rect.left
 | |
|         sy1 = self.select_start[1] - self.sim_view_rect.top
 | |
|         sx2 = self.select_end[0] - self.sim_view_rect.left
 | |
|         sy2 = self.select_end[1] - self.sim_view_rect.top
 | |
| 
 | |
|         # Convert sim_view to world coordinates
 | |
|         x1, y1 = self.camera.get_real_coordinates(sx1, sy1)
 | |
|         x2, y2 = self.camera.get_real_coordinates(sx2, sy2)
 | |
| 
 | |
|         # Check if selection is a click or drag
 | |
|         if (abs(sx1 - sx2) < SELECTION_THRESHOLD and
 | |
|                 abs(sy1 - sy2) < SELECTION_THRESHOLD):
 | |
|             self._handle_click_selection()
 | |
|         else:
 | |
|             self._handle_drag_selection(x1, y1, x2, y2)
 | |
| 
 | |
|     def _handle_click_selection(self):
 | |
|         """Handle single click selection."""
 | |
|         sx, sy = self.select_start[0] - self.sim_view_rect.left, self.select_start[1] - self.sim_view_rect.top
 | |
|         mouse_world_x, mouse_world_y = self.camera.get_real_coordinates(sx, sy)
 | |
|         obj = self.world.query_closest_object(mouse_world_x, mouse_world_y)
 | |
|         self.selected_objects = []
 | |
| 
 | |
|         if obj:
 | |
|             obj_x, obj_y = obj.position.get_position()
 | |
|             dx = obj_x - mouse_world_x
 | |
|             dy = obj_y - mouse_world_y
 | |
|             dist = (dx ** 2 + dy ** 2) ** 0.5
 | |
|             if dist <= obj.max_visual_width / 2:
 | |
|                 self.selected_objects = [obj]
 | |
| 
 | |
|         print(f"Clicked: selected {len(self.selected_objects)} object(s)")
 | |
| 
 | |
|     def _handle_drag_selection(self, x1, y1, x2, y2):
 | |
|         """Handle drag selection."""
 | |
|         min_x, max_x = min(x1, x2), max(x1, x2)
 | |
|         min_y, max_y = min(y1, y2), max(y1, y2)
 | |
|         self.selected_objects = self.world.query_objects_in_range(min_x, min_y, max_x, max_y)
 | |
|         print(f"Selected {len(self.selected_objects)} objects in range: {min_x}, {min_y} to {max_x}, {max_y}")
 | |
| 
 | |
|     def update_camera(self, keys, deltatime):
 | |
|         """Update camera based on currently pressed keys."""
 | |
|         self.camera.update(keys, deltatime)
 | |
| 
 | |
|     def update_selected_objects(self):
 | |
|         """Ensure selected objects are still valid."""
 | |
|         self.selected_objects = [
 | |
|             obj for obj in self.selected_objects if obj in self.world.get_objects()
 | |
|         ]
 | |
| 
 | |
|     def get_selection_rect(self):
 | |
|         """Get current selection rectangle for rendering."""
 | |
|         if self.selecting and self.select_start and self.select_end:
 | |
|             left = min(self.select_start[0], self.select_end[0])
 | |
|             top = min(self.select_start[1], self.select_end[1])
 | |
|             width = abs(self.select_end[0] - self.select_start[0])
 | |
|             height = abs(self.select_end[1] - self.select_start[1])
 | |
|             return (left, top, width, height)
 | |
|         return None |