from direct.task.TaskManagerGlobal import taskMgr from panda3d.core import KeyboardButton class CustomMouseController: def __init__(self, showbase): self.showbase = showbase # This is used to store which keys are currently pressed. self.keyMap = { # "mouse1": 0, # 移除左键,用于选择功能 "mouse3": 0, # 右键 "cam-forward": 0, "cam-backward": 0, "cam-left": 0, "cam-right": 0, "cam-up": 0, "cam-down": 0 } # 添加鼠标控制 - 只保留右键控制,左键用于选择 # self.showbase.accept("mouse1", self.setKey, ["mouse1", True]) # 移除左键绑定 # self.showbase.accept("mouse1-up", self.setKey, ["mouse1", False]) # 移除左键绑定 self.showbase.accept("mouse3", self.setKey, ["mouse3", True]) # 右键 self.showbase.accept("mouse3-up", self.setKey, ["mouse3", False]) # 右键释放 self.showbase.accept("w", self.setKey, ["cam-forward", True]) self.showbase.accept("W", self.setKey, ["cam-forward", True]) self.showbase.accept("a", self.setKey, ["cam-left", True]) self.showbase.accept("A", self.setKey, ["cam-left", True]) self.showbase.accept("s", self.setKey, ["cam-backward", True]) self.showbase.accept("S", self.setKey, ["cam-backward", True]) self.showbase.accept("d", self.setKey, ["cam-right", True]) self.showbase.accept("D", self.setKey, ["cam-right", True]) self.showbase.accept("e", self.setKey, ["cam-up", True]) self.showbase.accept("E", self.setKey, ["cam-up", True]) self.showbase.accept("q", self.setKey, ["cam-down", True]) self.showbase.accept("Q", self.setKey, ["cam-down", True]) self.showbase.accept("w-up", self.setKey, ["cam-forward", False]) self.showbase.accept("W-up", self.setKey, ["cam-forward", False]) self.showbase.accept("a-up", self.setKey, ["cam-left", False]) self.showbase.accept("A-up", self.setKey, ["cam-left", False]) self.showbase.accept("s-up", self.setKey, ["cam-backward", False]) self.showbase.accept("S-up", self.setKey, ["cam-backward", False]) self.showbase.accept("d-up", self.setKey, ["cam-right", False]) self.showbase.accept("D-up", self.setKey, ["cam-right", False]) self.showbase.accept("e-up", self.setKey, ["cam-up", False]) self.showbase.accept("E-up", self.setKey, ["cam-up", False]) self.showbase.accept("q-up", self.setKey, ["cam-down", False]) self.showbase.accept("Q-up", self.setKey, ["cam-down", False]) self.last_mouse_x = 0 self.last_mouse_y = 0 self.camera_speed = 25 self.move_speed = 20 def setUp(self, mouse_speed: float = 25, move_speed: float = 20): taskMgr.add(self.move, "moveTask") self.camera_speed = mouse_speed self.move_speed = move_speed def setKey(self, key, value, arg: str = None): self.keyMap[key] = value # 只在右键按下时记录鼠标位置 if key == "mouse3" and value == True: mouse_pos = self.showbase.mouseWatcherNode.getMouse() if mouse_pos: self.last_mouse_x = mouse_pos.get_x() self.last_mouse_y = mouse_pos.get_y() def move(self, task): dt = self.showbase.clock.dt # 检查ImGui是否捕获了键盘输入 if self._should_handle_keyboard(): watcher = self.showbase.mouseWatcherNode left_down = self.keyMap["cam-left"] or watcher.is_button_down(KeyboardButton.ascii_key("a")) right_down = self.keyMap["cam-right"] or watcher.is_button_down(KeyboardButton.ascii_key("d")) backward_down = self.keyMap["cam-backward"] or watcher.is_button_down(KeyboardButton.ascii_key("s")) forward_down = self.keyMap["cam-forward"] or watcher.is_button_down(KeyboardButton.ascii_key("w")) up_down = self.keyMap["cam-up"] or watcher.is_button_down(KeyboardButton.ascii_key("e")) down_down = self.keyMap["cam-down"] or watcher.is_button_down(KeyboardButton.ascii_key("q")) if left_down: self.showbase.camera.setX(self.showbase.camera, -self.move_speed * dt) if right_down: self.showbase.camera.setX(self.showbase.camera, +self.move_speed * dt) if backward_down: self.showbase.camera.setY(self.showbase.camera, -self.move_speed * dt) if forward_down: self.showbase.camera.setY(self.showbase.camera, +self.move_speed * dt) if up_down: self.showbase.camera.setZ(self.showbase.camera, +self.move_speed * dt) if down_down: self.showbase.camera.setZ(self.showbase.camera, -self.move_speed * dt) if self.keyMap["mouse3"]: # 只使用右键控制视角旋转 try: # 检查是否应该处理鼠标事件(避免与ImGui冲突) if self._should_handle_mouse(): mouse_pos = self.showbase.mouseWatcherNode.getMouse() if mouse_pos: current_x = mouse_pos.get_x() current_y = mouse_pos.get_y() # 计算鼠标移动差值 dx = current_x - self.last_mouse_x dy = current_y - self.last_mouse_y dy *= -1 # 根据鼠标移动调整摄像机 if abs(dx) > 0.01 or abs(dy) > 0.01: cam_hpr = self.showbase.camera.get_hpr() self.showbase.camera.set_hpr( cam_hpr.x - dx * self.camera_speed, max(-90, min(90, cam_hpr.y - dy * self.camera_speed)), 0 ) # 更新鼠标位置 self.last_mouse_x = current_x self.last_mouse_y = current_y except Exception as e: print(f"旋转相机失败:{e}") return task.cont def _should_handle_keyboard(self): """检查是否应该处理键盘事件(避免与ImGui冲突)""" try: # 检查ImGui是否想要捕获键盘 try: from imgui_bundle import imgui if hasattr(imgui, 'get_io') and imgui.get_io().want_capture_keyboard: return False except ImportError: pass # 如果右键按下,优先处理视角控制(即使ImGui有焦点) if self.keyMap["mouse3"]: return True return True except: return True def _should_handle_mouse(self): """检查是否应该处理鼠标事件(避免与ImGui冲突)""" try: # 如果是右键,优先处理视角控制 if self.keyMap["mouse3"]: return True # 检查ImGui是否想要捕获鼠标 try: from imgui_bundle import imgui if hasattr(imgui, 'get_io') and imgui.get_io().want_capture_mouse: return False except ImportError: pass # 检查鼠标位置是否在ImGui窗口区域内 mouse_pos = self.showbase.mouseWatcherNode.getMouse() if not mouse_pos: return True # 获取显示尺寸 try: from imgui_bundle import imgui display_size = imgui.get_io().display_size mouse_x = mouse_pos.get_x() * display_size.x / 2 + display_size.x / 2 mouse_y = display_size.y - (mouse_pos.get_y() * display_size.y / 2 + display_size.y / 2) # 检查是否在常见的ImGui界面区域内 # 这里可以根据实际的ImGui窗口位置进行更精确的检测 if mouse_x < 300 and mouse_y < 200: # 左上角区域(菜单栏) return False if mouse_x < 300 and mouse_y > display_size.y - 200: # 左下角区域(工具栏) return False if mouse_x > display_size.x - 300 and mouse_y < 200: # 右上角区域 return False except: pass return True except Exception as e: print(f"鼠标事件检测失败: {e}") return True