EG/core/CustomMouseController.py

197 lines
9.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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:
watcher = getattr(self.showbase, "mouseWatcherNode", None)
if watcher and watcher.hasMouse():
mouse_pos = watcher.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():
watcher = getattr(self.showbase, "mouseWatcherNode", None)
if not watcher or not watcher.hasMouse():
return task.cont
mouse_pos = watcher.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窗口区域内
watcher = getattr(self.showbase, "mouseWatcherNode", None)
if not watcher or not watcher.hasMouse():
return True
mouse_pos = watcher.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