diff --git a/core/selection.py b/core/selection.py index 9c3e78ee..53ccbb7b 100644 --- a/core/selection.py +++ b/core/selection.py @@ -1855,12 +1855,70 @@ class SelectionSystem: return False def stopGizmoDrag(self): - """停止坐标轴拖拽""" + """停止坐标轴拖拽并创建撤销命令""" print(f"停止坐标轴拖拽 - 轴: {self.dragGizmoAxis}") # 移除拖拽更新任务 if hasattr(self.world, 'taskMgr') and self.world.taskMgr: self.world.taskMgr.remove("gizmoDragUpdate") + + # 创建撤销命令 + if hasattr(self.world,'command_manager') and self.world.command_manager and self.gizmoTarget: + try: + # 检查是否是移动操作 + if (hasattr(self,'gizmoTargetStartPos') and self.gizmoTargetStartPos): + current_pos = self.gizmoTarget.getPos() + if (abs(current_pos.x-self.gizmoTargetStartPos.x)>0.001 or + abs(current_pos.y-self.gizmoTargetStartPos.y)>0.001 or + abs(current_pos.z-self.gizmoTargetStartPos.z)>0.001): + from core.Command_System import MoveNodeCommand, MoveLightCommand + + light_object = self.gizmoTarget.getPythonTag("rp_light_object") + if light_object: + command = MoveLightCommand(self.gizmoTarget,self.gizmoTargetStartPos,current_pos,light_object) + else: + command = MoveNodeCommand(self.gizmoTarget,self.gizmoTargetStartPos,current_pos) + self.world.command_manager.execute_command(command) + print(f"创建移动命令: {self.gizmoTargetStartPos} -> {current_pos}") + + # 检查是否是缩放操作 + if (hasattr(self, 'gizmoTargetStartScale') and self.gizmoTargetStartScale): + current_scale = self.gizmoTarget.getScale() + if (abs(current_scale.x - self.gizmoTargetStartScale.x) > 0.001 or + abs(current_scale.y - self.gizmoTargetStartScale.y) > 0.001 or + abs(current_scale.z - self.gizmoTargetStartScale.z) > 0.001): + from core.Command_System import ScaleNodeCommand + command = ScaleNodeCommand(self.gizmoTarget, self.gizmoTargetStartScale, current_scale) + self.world.command_manager.execute_command(command) + print(f"创建缩放命令: {self.gizmoTargetStartScale} -> {current_scale}") + + # 检查是否是旋转操作 + if (hasattr(self, 'gizmoTargetStartHpr') and self.gizmoTargetStartHpr): + current_hpr = self.gizmoTarget.getHpr() + if (abs(current_hpr.x - self.gizmoTargetStartHpr.x) > 0.001 or + abs(current_hpr.y - self.gizmoTargetStartHpr.y) > 0.001 or + abs(current_hpr.z - self.gizmoTargetStartHpr.z) > 0.001): + from core.Command_System import RotateNodeCommand + command = RotateNodeCommand(self.gizmoTarget, self.gizmoTargetStartHpr, current_hpr) + self.world.command_manager.execute_command(command) + print(f"创建旋转命令: {self.gizmoTargetStartHpr} -> {current_hpr}") + + except Exception as e: + print(f"创建撤销命令时出错: {e}") + + # 恢复所有轴的颜色 + for axis_name in ["x", "y", "z"]: + self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name]) + + # 重置拖拽状态 + self.isDraggingGizmo = False + self.dragGizmoAxis = None + self.dragStartMousePos = None + # 清理拖拽状态,下次拖拽开始时重新设置 + self.gizmoTargetStartPos = None + self.gizmoTargetStartScale = None + self.gizmoTargetStartHpr = None + self.gizmoStartPos = None def _dragUpdateTask(self, task): """拖拽更新任务 - 持续更新拖拽状态""" @@ -1889,55 +1947,6 @@ class SelectionSystem: except Exception as e: print(f"拖拽更新任务错误: {e}") return task.done - - if hasattr(self.world,'command_manager') and self.world.command_manager and self.gizmoTarget: - current_pos = self.gizmoTarget.getPos() - - if (hasattr(self,'gizmoTargetStartPos') and self.gizmoTargetStartPos and - (abs(current_pos.x-self.gizmoTargetStartPos.x)>0.001 or - abs(current_pos.y-self.gizmoTargetStartPos.y)>0.001 or - abs(current_pos.z-self.gizmoTargetStartPos.z)>0.001)): - from core.Command_System import MoveNodeCommand - from core.Command_System import MoveLightCommand - - light_object = self.gizmoTarget.getPythonTag("rp_light_object") - if light_object: - command = MoveLightCommand(self.gizmoTarget,self.gizmoTargetStartPos,current_pos,light_object) - else: - command = MoveNodeCommand(self.gizmoTarget,self.gizmoTargetStartPos,current_pos) - self.world.command_manager.execute_command(command) - # 如果是缩放操作且缩放发生了变化,则创建缩放命令 - elif (hasattr(self, 'gizmoTargetStartScale') and hasattr(self, 'gizmoTargetStartScale') and - self.gizmoTargetStartScale): - current_scale = self.gizmoTarget.getScale() - if (abs(current_scale.x - self.gizmoTargetStartScale.x) > 0.001 or - abs(current_scale.y - self.gizmoTargetStartScale.y) > 0.001 or - abs(current_scale.z - self.gizmoTargetStartScale.z) > 0.001): - from core.Command_System import ScaleNodeCommand - command = ScaleNodeCommand(self.gizmoTarget, self.gizmoTargetStartScale, current_scale) - self.world.command_manager.execute_command(command) - # 如果是旋转操作且旋转发生了变化,则创建旋转命令 - elif (hasattr(self, 'gizmoTargetStartHpr') and hasattr(self, 'gizmoTargetStartHpr') and - self.gizmoTargetStartHpr): - current_hpr = self.gizmoTarget.getHpr() - if (abs(current_hpr.x - self.gizmoTargetStartHpr.x) > 0.001 or - abs(current_hpr.y - self.gizmoTargetStartHpr.y) > 0.001 or - abs(current_hpr.z - self.gizmoTargetStartHpr.z) > 0.001): - from core.Command_System import RotateNodeCommand - command = RotateNodeCommand(self.gizmoTarget, self.gizmoTargetStartHpr, current_hpr) - self.world.command_manager.execute_command(command) - - # 恢复所有轴的颜色 - for axis_name in ["x", "y", "z"]: - self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name]) - - self.isDraggingGizmo = False - self.dragGizmoAxis = None - self.dragStartMousePos = None - # 清理拖拽状态,下次拖拽开始时重新设置 - self.gizmoTargetStartPos = None - self.gizmoStartPos = None - if hasattr(self, 'gizmoTargetStartScale'): delattr(self, 'gizmoTargetStartScale') if hasattr(self, 'gizmoTargetStartHpr'): diff --git a/demo.py b/demo.py index c864eacb..6ac9671f 100644 --- a/demo.py +++ b/demo.py @@ -180,6 +180,11 @@ class MyWorld(CoreWorld): except Exception as e: print(f"⚠ VR管理器初始化失败: {e}") self.vr_manager = None + + # VR调试相关变量 + self.vr_debug_enabled = False + self.vr_detailed_mode = True + self.vr_performance_monitor = False # 调试选项 self.debug_collision = True # 是否显示碰撞体 @@ -395,11 +400,11 @@ class MyWorld(CoreWorld): self.accept('f4', self._on_f4_pressed) # 编辑功能快捷键 - self.accept('z', self._on_z_pressed) - self.accept('y', self._on_y_pressed) - self.accept('x', self._on_x_pressed) - self.accept('c', self._on_c_pressed) - self.accept('v', self._on_v_pressed) + self.accept('control-z', self._on_undo) + self.accept('control-y', self._on_redo) + self.accept('control-x', self._on_cut) + self.accept('control-c', self._on_copy) + self.accept('control-v', self._on_paste) self.accept('delete', self._on_delete_pressed) # 滚轮事件 @@ -831,6 +836,11 @@ class MyWorld(CoreWorld): # 创建菜单 with imgui_ctx.begin_menu("创建") as create_menu: if create_menu: + if imgui.menu_item("导入模型", "", False, True)[1]: + self._on_import_model() + + imgui.separator() + if imgui.menu_item("空对象", "", False, True)[1]: self._on_create_empty_object() @@ -928,11 +938,64 @@ class MyWorld(CoreWorld): # 工具菜单 with imgui_ctx.begin_menu("工具") as tools_menu: if tools_menu: - if imgui.menu_item("导入模型", "", False, True)[1]: - self._on_import_model() - imgui.menu_item("地形编辑器", "", False, True) - imgui.menu_item("材质编辑器", "", False, True) - imgui.menu_item("脚本编辑器", "", False, True) + # 工具切换选项 + if imgui.menu_item("选择工具", "", False, True)[1]: + self.tool_manager.setCurrentTool("选择") + if imgui.menu_item("移动工具", "", False, True)[1]: + self.tool_manager.setCurrentTool("移动") + if imgui.menu_item("旋转工具", "", False, True)[1]: + self.tool_manager.setCurrentTool("旋转") + if imgui.menu_item("缩放工具", "", False, True)[1]: + self.tool_manager.setCurrentTool("缩放") + + imgui.separator() + + # 编辑工具 + if imgui.menu_item("光照编辑", "", False, True)[1]: + self.tool_manager.setCurrentTool("光照编辑") + if imgui.menu_item("图形编辑", "", False, True)[1]: + self.tool_manager.setCurrentTool("图形编辑") + + imgui.separator() + + # VR子菜单 + with imgui_ctx.begin_menu("VR") as vr_menu: + if vr_menu: + if imgui.menu_item("进入VR模式", "", False, True)[1]: + self._toggle_vr_mode() + if imgui.menu_item("退出VR模式", "", False, True)[1]: + self._exit_vr_mode() + + imgui.separator() + + if imgui.menu_item("VR状态", "", False, True)[1]: + self._show_vr_status() + if imgui.menu_item("VR设置", "", False, True)[1]: + self._show_vr_settings() + + imgui.separator() + + # VR调试子菜单 + with imgui_ctx.begin_menu("VR调试") as vr_debug_menu: + if vr_debug_menu: + _, self.vr_debug_enabled = imgui.menu_item("启用调试输出", "", self.vr_debug_enabled, True) + + if imgui.menu_item("立即显示性能报告", "", False, True)[1]: + self._show_vr_performance_report() + + imgui.separator() + + # 输出模式 + with imgui_ctx.begin_menu("输出模式") as output_menu: + if output_menu: + if imgui.menu_item("简短模式", "", not self.vr_detailed_mode, True)[1]: + self.vr_detailed_mode = False + if imgui.menu_item("详细模式", "", self.vr_detailed_mode, True)[1]: + self.vr_detailed_mode = True + + imgui.separator() + + _, self.vr_performance_monitor = imgui.menu_item("启用性能监控", "", self.vr_performance_monitor, True) # 窗口菜单 - 已隐藏 # with imgui_ctx.begin_menu("窗口") as window_menu: @@ -4978,30 +5041,7 @@ class MyWorld(CoreWorld): if self.alt_pressed: self._on_exit() - def _on_z_pressed(self): - """Z键按下 - 检查Ctrl+Z组合键(撤销)""" - if self.ctrl_pressed: - self._on_undo() - - def _on_y_pressed(self): - """Y键按下 - 检查Ctrl+Y组合键(重做)""" - if self.ctrl_pressed: - self._on_redo() - - def _on_x_pressed(self): - """X键按下 - 检查Ctrl+X组合键(剪切)""" - if self.ctrl_pressed: - self._on_cut() - - def _on_c_pressed(self): - """C键按下 - 检查Ctrl+C组合键(复制)""" - if self.ctrl_pressed: - self._on_copy() - - def _on_v_pressed(self): - """V键按下 - 检查Ctrl+V组合键(粘贴)""" - if self.ctrl_pressed: - self._on_paste() + # 移除了单独的按键处理方法,现在直接使用组合键事件 def _on_delete_pressed(self): """Delete键按下 - 删除选中节点""" @@ -5309,12 +5349,37 @@ class MyWorld(CoreWorld): self.add_error_message(f"删除操作失败: {e}") def _delete_node(self, node): - """删除节点的通用方法""" + """删除节点的通用方法 - 使用命令系统""" try: if not node or node.isEmpty(): return False node_name = node.getName() or "未命名节点" + parent = node.getParent() + + # 创建删除命令 + if hasattr(self, 'command_manager') and self.command_manager: + from core.Command_System import DeleteNodeCommand + command = DeleteNodeCommand(node, parent, self) + self.command_manager.execute_command(command) + print(f"[命令系统] 创建删除命令: {node_name}") + else: + # 备用方案:直接删除并执行清理 + print(f"[删除] 命令管理器不可用,直接删除节点: {node_name}") + self._perform_node_cleanup(node) + node.removeNode() + + print(f"[删除] 成功删除节点: {node_name}") + return True + + except Exception as e: + print(f"[删除] 删除节点失败: {e}") + return False + + def _perform_node_cleanup(self, node): + """执行节点清理逻辑""" + try: + node_name = node.getName() or "未命名节点" # 从场景管理器的模型列表中移除(如果是模型) if hasattr(self, 'scene_manager') and self.scene_manager: @@ -5355,16 +5420,9 @@ class MyWorld(CoreWorld): print(f"[动画系统] 清理Actor缓存失败: {e}") finally: del self._actor_cache[node] - - # 从父节点中移除 - node.removeNode() - - print(f"[删除] 成功删除节点: {node_name}") - return True - + except Exception as e: - print(f"[删除] 删除节点失败: {e}") - return False + print(f"[清理] 节点清理失败: {e}") # ==================== 对话框绘制函数 ==================== @@ -7302,8 +7360,8 @@ class MyWorld(CoreWorld): imgui.end_popup() - def _delete_node(self, node): - """删除节点""" + def _delete_node_simple(self, node): + """删除节点 - 简化版本""" if not node or node.isEmpty(): return @@ -7321,6 +7379,9 @@ class MyWorld(CoreWorld): if gui_element in self.gui_manager.gui_elements: self.gui_manager.gui_elements.remove(gui_element) + # 使用主删除方法 + self._delete_node(node) + # 获取节点名称(在删除之前) node_name = node.getName() if not node.isEmpty() else '未命名节点' @@ -7958,7 +8019,55 @@ class MyWorld(CoreWorld): """GUI按钮点击事件处理""" print("GUI按钮被点击了") - def _get_chinese_font(self): + def _toggle_vr_mode(self): + """切换VR模式""" + if self.vr_manager: + if self.vr_manager.is_enabled(): + self._exit_vr_mode() + else: + self.vr_manager.enable() + self.add_info_message("已进入VR模式") + else: + self.add_error_message("VR管理器未初始化") + + def _exit_vr_mode(self): + """退出VR模式""" + if self.vr_manager: + self.vr_manager.disable() + self.add_info_message("已退出VR模式") + + def _show_vr_status(self): + """显示VR状态""" + if self.vr_manager: + status = "已启用" if self.vr_manager.is_enabled() else "未启用" + self.add_info_message(f"VR状态: {status}") + + # 显示设备信息 + if self.vr_manager.is_enabled(): + devices = self.vr_manager.get_connected_devices() + if devices: + self.add_info_message(f"连接的设备: {', '.join(devices)}") + else: + self.add_info_message("未检测到VR设备") + else: + self.add_error_message("VR管理器未初始化") + + def _show_vr_settings(self): + """显示VR设置""" + if self.vr_manager: + self.add_info_message("VR设置对话框待实现") + else: + self.add_error_message("VR管理器未初始化") + + def _show_vr_performance_report(self): + """显示VR性能报告""" + if self.vr_manager and self.vr_manager.is_enabled(): + report = self.vr_manager.get_performance_report() + self.add_info_message(f"VR性能报告: {report}") + else: + self.add_info_message("VR未启用或管理器未初始化") + +def _get_chinese_font(self): """获取中文字体""" try: from panda3d.core import TextNode @@ -7995,284 +8104,284 @@ class MyWorld(CoreWorld): from panda3d.core import TextNode return TextNode.getDefaultFont() - def createGUILabel(self, pos=(0, 0, 0), text="标签", size=0.08): - """创建2D GUI标签""" - try: - if hasattr(self, 'gui_manager') and self.gui_manager: - # 使用简化的创建方法,不依赖QT树形控件 - return self._create_simple_gui_label(pos, text, size) - return None - except Exception as e: - print(f"创建GUI标签失败: {e}") - return None - - def _create_simple_gui_label(self, pos=(0, 0, 0), text="标签", size=0.08): - """创建简单的GUI标签,不依赖QT树形控件""" - try: - from direct.gui.DirectGui import DirectLabel - - # 转换坐标系统 - gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1) - - # 设置中文字体 - font = self._get_chinese_font() - - # 处理scale参数 - if isinstance(size, (list, tuple)) and len(size) >= 2: - scale_value = size[0] # 使用宽度作为缩放值 - else: - scale_value = size - - # 创建标签 - label = DirectLabel( - text=text, - pos=gui_pos, - scale=scale_value, - text_font=font, - text_fg=(1, 1, 1, 1) # 白色文字 - ) - - # 创建包装对象 - label_wrapper = type('GUIElement', (), {})() - label_wrapper.node = label - label_wrapper.name = text - label_wrapper.gui_type = "GUI_LABEL" - label_wrapper.position = pos - label_wrapper.size = size - - # 添加到GUI管理器 - self.gui_manager.gui_elements.append(label_wrapper) - - print(f"✓ GUI标签创建成功: {text}") - return label_wrapper - except Exception as e: - print(f"✗ 创建简单GUI标签失败: {e}") - return None - - def createGUIEntry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08): - """创建2D GUI文本输入框""" - try: - if hasattr(self, 'gui_manager') and self.gui_manager: - # 使用简化的创建方法,不依赖QT树形控件 - return self._create_simple_gui_entry(pos, placeholder, size) - return None - except Exception as e: - print(f"创建GUI输入框失败: {e}") - return None - - def _create_simple_gui_entry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08): - """创建简单的GUI输入框,不依赖QT树形控件""" - try: - from direct.gui.DirectGui import DirectEntry - - # 转换坐标系统 - gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1) - - # 设置中文字体 - font = self._get_chinese_font() - - # 处理scale参数 - if isinstance(size, (list, tuple)) and len(size) >= 2: - scale_value = size[0] # 使用宽度作为缩放值 - else: - scale_value = size - - # 创建输入框 - entry = DirectEntry( - text=placeholder, - pos=gui_pos, - scale=scale_value, - text_font=font, - width=20, # 字符宽度 - numLines=1, # 行数 - focus=1 # 自动获取焦点 - ) - - # 创建包装对象 - entry_wrapper = type('GUIElement', (), {})() - entry_wrapper.node = entry - entry_wrapper.name = placeholder - entry_wrapper.gui_type = "GUI_ENTRY" - entry_wrapper.position = pos - entry_wrapper.size = size - - # 添加到GUI管理器 - self.gui_manager.gui_elements.append(entry_wrapper) - - print(f"✓ GUI输入框创建成功: {placeholder}") - return entry_wrapper - except Exception as e: - print(f"✗ 创建简单GUI输入框失败: {e}") - return None - - def createGUIImage(self, pos=(0, 0, 0), image_path=None, size=2): - """创建2D GUI图片""" - try: - if hasattr(self, 'gui_manager') and self.gui_manager: - # 使用简化的创建方法,不依赖QT树形控件 - return self._create_simple_gui_image(pos, image_path, size) - return None - except Exception as e: - print(f"创建GUI图片失败: {e}") - return None - - def _create_simple_gui_image(self, pos=(0, 0, 0), image_path=None, size=2): - """创建简单的GUI图片,不依赖QT树形控件""" - try: - from direct.gui.DirectGui import DirectFrame - from panda3d.core import Filename - - # 转换坐标系统 - gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1) - - # 处理scale参数 - if isinstance(size, (list, tuple)) and len(size) >= 2: - scale_value = size[0] # 使用宽度作为缩放值 - else: - scale_value = size - - # 创建图片框架 - if image_path and os.path.exists(image_path): - # 加载纹理 - tex = self.loader.loadTexture(Filename.fromOsSpecific(image_path)) - image = DirectFrame( - image=tex, + def createGUILabel(self, pos=(0, 0, 0), text="标签", size=0.08): + """创建2D GUI标签""" + try: + if hasattr(self, 'gui_manager') and self.gui_manager: + # 使用简化的创建方法,不依赖QT树形控件 + return self._create_simple_gui_label(pos, text, size) + return None + except Exception as e: + print(f"创建GUI标签失败: {e}") + return None + + def _create_simple_gui_label(self, pos=(0, 0, 0), text="标签", size=0.08): + """创建简单的GUI标签,不依赖QT树形控件""" + try: + from direct.gui.DirectGui import DirectLabel + + # 转换坐标系统 + gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1) + + # 设置中文字体 + font = self._get_chinese_font() + + # 处理scale参数 + if isinstance(size, (list, tuple)) and len(size) >= 2: + scale_value = size[0] # 使用宽度作为缩放值 + else: + scale_value = size + + # 创建标签 + label = DirectLabel( + text=text, pos=gui_pos, - scale=scale_value + scale=scale_value, + text_font=font, + text_fg=(1, 1, 1, 1) # 白色文字 ) - image_name = os.path.basename(image_path) - else: - # 创建一个彩色框架作为占位符 - image = DirectFrame( - frameColor=(0.5, 0.5, 0.5, 1.0), # 灰色 - frameSize=(-scale_value, scale_value, -scale_value, scale_value), - pos=gui_pos + + # 创建包装对象 + label_wrapper = type('GUIElement', (), {})() + label_wrapper.node = label + label_wrapper.name = text + label_wrapper.gui_type = "GUI_LABEL" + label_wrapper.position = pos + label_wrapper.size = size + + # 添加到GUI管理器 + self.gui_manager.gui_elements.append(label_wrapper) + + print(f"✓ GUI标签创建成功: {text}") + return label_wrapper + except Exception as e: + print(f"✗ 创建简单GUI标签失败: {e}") + return None + + def createGUIEntry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08): + """创建2D GUI文本输入框""" + try: + if hasattr(self, 'gui_manager') and self.gui_manager: + # 使用简化的创建方法,不依赖QT树形控件 + return self._create_simple_gui_entry(pos, placeholder, size) + return None + except Exception as e: + print(f"创建GUI输入框失败: {e}") + return None + + def _create_simple_gui_entry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08): + """创建简单的GUI输入框,不依赖QT树形控件""" + try: + from direct.gui.DirectGui import DirectEntry + + # 转换坐标系统 + gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1) + + # 设置中文字体 + font = self._get_chinese_font() + + # 处理scale参数 + if isinstance(size, (list, tuple)) and len(size) >= 2: + scale_value = size[0] # 使用宽度作为缩放值 + else: + scale_value = size + + # 创建输入框 + entry = DirectEntry( + text=placeholder, + pos=gui_pos, + scale=scale_value, + text_font=font, + width=20, # 字符宽度 + numLines=1, # 行数 + focus=1 # 自动获取焦点 ) - image_name = "占位符图片" - - # 创建包装对象 - image_wrapper = type('GUIElement', (), {})() - image_wrapper.node = image - image_wrapper.name = image_name - image_wrapper.gui_type = "GUI_IMAGE" - image_wrapper.position = pos - image_wrapper.size = size - image_wrapper.image_path = image_path - - # 添加到GUI管理器 - self.gui_manager.gui_elements.append(image_wrapper) - - print(f"✓ GUI图片创建成功: {image_name}") - return image_wrapper - except Exception as e: - print(f"✗ 创建简单GUI图片失败: {e}") - return None - - def createVideoScreen(self, pos=(0, 0, 0), size=1, video_path=None): - """创建视频屏幕""" - try: - if hasattr(self, 'gui_manager') and self.gui_manager: - return self.gui_manager.createVideoScreen(pos, size, video_path) - return None - except Exception as e: - print(f"创建视频屏幕失败: {e}") - return None - - def create2DVideoScreen(self, pos=(0, 0, 0), size=0.2, video_path=None): - """创建2D视频屏幕""" - try: - if hasattr(self, 'gui_manager') and self.gui_manager: - return self.gui_manager.createGUI2DVideoScreen(pos, size, video_path) - return None - except Exception as e: - print(f"创建2D视频屏幕失败: {e}") - return None - - def createSphericalVideo(self, pos=(0, 0, 0), radius=5.0, video_path=None): - """创建360度视频""" - try: - if hasattr(self, 'gui_manager') and self.gui_manager: - return self.gui_manager.createSphericalVideo(pos, radius, video_path) - return None - except Exception as e: - print(f"创建球形视频失败: {e}") - return None - - def createVirtualScreen(self, pos=(0, 0, 0), size=(2, 1), text="虚拟屏幕"): - """创建虚拟屏幕""" - try: - if hasattr(self, 'gui_manager') and self.gui_manager: - return self.gui_manager.createGUIVirtualScreen(pos, size, text) - return None - except Exception as e: - print(f"创建虚拟屏幕失败: {e}") - return None - - # ==================== 光源创建方法 ==================== - - def createSpotLight(self, pos=(0, 0, 5)): - """创建聚光灯""" - try: - if hasattr(self, 'scene_manager') and self.scene_manager: - return self.scene_manager.createSpotLight(pos) - return None - except Exception as e: - print(f"创建聚光灯失败: {e}") - return None - - def createPointLight(self, pos=(0, 0, 5)): - """创建点光源""" - try: - if hasattr(self, 'scene_manager') and self.scene_manager: - return self.scene_manager.createPointLight(pos) - return None - except Exception as e: - print(f"创建点光源失败: {e}") - return None - - # ==================== 地形创建方法 ==================== - - def createFlatTerrain(self, size=(10, 10), resolution=129): - """创建平面地形""" - try: - if hasattr(self, 'terrain_manager') and self.terrain_manager: - return self.terrain_manager.createFlatTerrain(size, resolution) - return None - except Exception as e: - print(f"创建平面地形失败: {e}") - return None - - def createTerrainFromHeightMap(self, heightmap_path, scale=(1.0, 1.0, 10.0)): - """从高度图创建地形""" - try: - if hasattr(self, 'terrain_manager') and self.terrain_manager: - return self.terrain_manager.createTerrainFromHeightMap(heightmap_path, scale) - return None - except Exception as e: - print(f"创建高度图地形失败: {e}") - return None - - # ==================== 脚本创建方法 ==================== - - def createScript(self, script_name, template="basic"): - """创建脚本""" - try: - if hasattr(self, 'script_manager') and self.script_manager: - return self.script_manager.createScript(script_name, template) - return None - except Exception as e: - print(f"创建脚本失败: {e}") - return None - - def loadScript(self, script_path): - """加载脚本""" - try: - if hasattr(self, 'script_manager') and self.script_manager: - return self.script_manager.loadScript(script_path) - return None - except Exception as e: - print(f"加载脚本失败: {e}") - return None + + # 创建包装对象 + entry_wrapper = type('GUIElement', (), {})() + entry_wrapper.node = entry + entry_wrapper.name = placeholder + entry_wrapper.gui_type = "GUI_ENTRY" + entry_wrapper.position = pos + entry_wrapper.size = size + + # 添加到GUI管理器 + self.gui_manager.gui_elements.append(entry_wrapper) + + print(f"✓ GUI输入框创建成功: {placeholder}") + return entry_wrapper + except Exception as e: + print(f"✗ 创建简单GUI输入框失败: {e}") + return None + + def createGUIImage(self, pos=(0, 0, 0), image_path=None, size=2): + """创建2D GUI图片""" + try: + if hasattr(self, 'gui_manager') and self.gui_manager: + # 使用简化的创建方法,不依赖QT树形控件 + return self._create_simple_gui_image(pos, image_path, size) + return None + except Exception as e: + print(f"创建GUI图片失败: {e}") + return None + + def _create_simple_gui_image(self, pos=(0, 0, 0), image_path=None, size=2): + """创建简单的GUI图片,不依赖QT树形控件""" + try: + from direct.gui.DirectGui import DirectFrame + from panda3d.core import Filename + + # 转换坐标系统 + gui_pos = (pos[0] * 0.1, 0, pos[2] * 0.1) + + # 处理scale参数 + if isinstance(size, (list, tuple)) and len(size) >= 2: + scale_value = size[0] # 使用宽度作为缩放值 + else: + scale_value = size + + # 创建图片框架 + if image_path and os.path.exists(image_path): + # 加载纹理 + tex = self.loader.loadTexture(Filename.fromOsSpecific(image_path)) + image = DirectFrame( + image=tex, + pos=gui_pos, + scale=scale_value + ) + image_name = os.path.basename(image_path) + else: + # 创建一个彩色框架作为占位符 + image = DirectFrame( + frameColor=(0.5, 0.5, 0.5, 1.0), # 灰色 + frameSize=(-scale_value, scale_value, -scale_value, scale_value), + pos=gui_pos + ) + image_name = "占位符图片" + + # 创建包装对象 + image_wrapper = type('GUIElement', (), {})() + image_wrapper.node = image + image_wrapper.name = image_name + image_wrapper.gui_type = "GUI_IMAGE" + image_wrapper.position = pos + image_wrapper.size = size + image_wrapper.image_path = image_path + + # 添加到GUI管理器 + self.gui_manager.gui_elements.append(image_wrapper) + + print(f"✓ GUI图片创建成功: {image_name}") + return image_wrapper + except Exception as e: + print(f"✗ 创建简单GUI图片失败: {e}") + return None + + def createVideoScreen(self, pos=(0, 0, 0), size=1, video_path=None): + """创建视频屏幕""" + try: + if hasattr(self, 'gui_manager') and self.gui_manager: + return self.gui_manager.createVideoScreen(pos, size, video_path) + return None + except Exception as e: + print(f"创建视频屏幕失败: {e}") + return None + + def create2DVideoScreen(self, pos=(0, 0, 0), size=0.2, video_path=None): + """创建2D视频屏幕""" + try: + if hasattr(self, 'gui_manager') and self.gui_manager: + return self.gui_manager.createGUI2DVideoScreen(pos, size, video_path) + return None + except Exception as e: + print(f"创建2D视频屏幕失败: {e}") + return None + + def createSphericalVideo(self, pos=(0, 0, 0), radius=5.0, video_path=None): + """创建360度视频""" + try: + if hasattr(self, 'gui_manager') and self.gui_manager: + return self.gui_manager.createSphericalVideo(pos, radius, video_path) + return None + except Exception as e: + print(f"创建球形视频失败: {e}") + return None + + def createVirtualScreen(self, pos=(0, 0, 0), size=(2, 1), text="虚拟屏幕"): + """创建虚拟屏幕""" + try: + if hasattr(self, 'gui_manager') and self.gui_manager: + return self.gui_manager.createGUIVirtualScreen(pos, size, text) + return None + except Exception as e: + print(f"创建虚拟屏幕失败: {e}") + return None + + # ==================== 光源创建方法 ==================== + + def createSpotLight(self, pos=(0, 0, 5)): + """创建聚光灯""" + try: + if hasattr(self, 'scene_manager') and self.scene_manager: + return self.scene_manager.createSpotLight(pos) + return None + except Exception as e: + print(f"创建聚光灯失败: {e}") + return None + + def createPointLight(self, pos=(0, 0, 5)): + """创建点光源""" + try: + if hasattr(self, 'scene_manager') and self.scene_manager: + return self.scene_manager.createPointLight(pos) + return None + except Exception as e: + print(f"创建点光源失败: {e}") + return None + + # ==================== 地形创建方法 ==================== + + def createFlatTerrain(self, size=(10, 10), resolution=129): + """创建平面地形""" + try: + if hasattr(self, 'terrain_manager') and self.terrain_manager: + return self.terrain_manager.createFlatTerrain(size, resolution) + return None + except Exception as e: + print(f"创建平面地形失败: {e}") + return None + + def createTerrainFromHeightMap(self, heightmap_path, scale=(1.0, 1.0, 10.0)): + """从高度图创建地形""" + try: + if hasattr(self, 'terrain_manager') and self.terrain_manager: + return self.terrain_manager.createTerrainFromHeightMap(heightmap_path, scale) + return None + except Exception as e: + print(f"创建高度图地形失败: {e}") + return None + + # ==================== 脚本创建方法 ==================== + + def createScript(self, script_name, template="basic"): + """创建脚本""" + try: + if hasattr(self, 'script_manager') and self.script_manager: + return self.script_manager.createScript(script_name, template) + return None + except Exception as e: + print(f"创建脚本失败: {e}") + return None + + def loadScript(self, script_path): + """加载脚本""" + try: + if hasattr(self, 'script_manager') and self.script_manager: + return self.script_manager.loadScript(script_path) + return None + except Exception as e: + print(f"加载脚本失败: {e}") + return None demo = MyWorld() demo.run()