DynamicAbstractionSystem/core/input_handler.py
Sam deee83edb3
Some checks failed
Build Simulation and Test / Run All Tests (push) Failing after 30s
Enhance simulation performance and add sprint mode functionality
2025-06-16 16:57:03 -05:00

168 lines
6.3 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):
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
def handle_events(self, events):
"""Process all pygame events and return game state."""
running = True
for event in events:
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 = True # 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
# Convert screen to world coordinates
x1, y1 = self.camera.get_real_coordinates(*self.select_start)
x2, y2 = self.camera.get_real_coordinates(*self.select_end)
# Check if selection is a click or drag
if (abs(self.select_start[0] - self.select_end[0]) < SELECTION_THRESHOLD and
abs(self.select_start[1] - self.select_end[1]) < SELECTION_THRESHOLD):
self._handle_click_selection()
else:
self._handle_drag_selection(x1, y1, x2, y2)
def _handle_click_selection(self):
"""Handle single click selection."""
mouse_world_x, mouse_world_y = self.camera.get_real_coordinates(*self.select_start)
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