From 79b2547446bd4ac0b68e6f645b2e35d4961ae558 Mon Sep 17 00:00:00 2001 From: Hector <2055590199@qq.com> Date: Mon, 29 Sep 2025 11:25:19 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=89=93=E5=8C=85=E5=90=8E?= =?UTF-8?q?=E7=9B=B8=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- RenderPipelineFile/samples/06-Car/main.py | 6 +- project/project_manager.py | 60 ++--- templates/main_template.py | 283 +++++++++++++++++++++- 3 files changed, 289 insertions(+), 60 deletions(-) diff --git a/RenderPipelineFile/samples/06-Car/main.py b/RenderPipelineFile/samples/06-Car/main.py index adf99b1b..da6715f8 100644 --- a/RenderPipelineFile/samples/06-Car/main.py +++ b/RenderPipelineFile/samples/06-Car/main.py @@ -52,7 +52,11 @@ class MainApp(ShowBase): # Load the scene model = loader.loadModel("scene/scene.bam") # model = loader.loadModel("scene2/Scene.bam") - + model_0 = self.loader.loadModel("/home/tiger/下载/Benci/source/s65/s65/s65.fbx") + model_0.reparentTo(self.render) + model_0.setScale(0.01) + model_0.setPos(-8, 42, 0) + model_0.setHpr(0, 90, 0) model.reparent_to(render) self.render_pipeline.prepare_scene(model) diff --git a/project/project_manager.py b/project/project_manager.py index 75e83517..649beadd 100644 --- a/project/project_manager.py +++ b/project/project_manager.py @@ -403,8 +403,6 @@ class ProjectManager: self._copyScriptSystemToBuild(build_dir) - self._copyInfoPanelSystemToBuild(build_dir) - source_render_pipeline = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),"RenderPipelineFile") dest_render_pipeline = os.path.join(build_dir,"RenderPipelineFile") @@ -463,55 +461,25 @@ class ProjectManager: except Exception as e: print(f"⚠️ 复制脚本文件时出错: {str(e)}") - def _copyScriptSystemToBuild(self, build_dir): - """复制core/script_system.py文件到构建目录""" - try: - # 源文件路径 - source_script_system = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "core", - "script_system.py") + def _copyScriptSystemToBuild(self,build_dir): + core_files = [ + "script_system.py", + "InfoPanelManager.py", + "CustomMouseController.py" + ] - # 目标目录 - core_dest = os.path.join(build_dir, "core") + source_core_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),"core") - # 如果源文件存在 - if os.path.exists(source_script_system): - # 确保目标目录存在 - if not os.path.exists(core_dest): - os.makedirs(core_dest) + core_dest = os.path.join(build_dir,"core") - # 复制文件 - shutil.copy2(source_script_system, os.path.join(core_dest, "script_system.py")) - print("✓ core/script_system.py文件已复制到build目录") - else: - print("⚠️ core/script_system.py文件未找到") + if not os.path.exists(core_dest): + os.makedirs(core_dest) - except Exception as e: - print(f"⚠️ 复制core/script_system.py文件时出错: {str(e)}") + for file_name in core_files: + source_file = os.path.join(source_core_dir,file_name) - def _copyInfoPanelSystemToBuild(self, build_dir): - """复制core/script_system.py文件到构建目录""" - try: - # 源文件路径 - source_InfoPanel_system = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "core", - "InfoPanelManager.py") - - # 目标目录 - core_dest = os.path.join(build_dir, "core") - - # 如果源文件存在 - if os.path.exists(source_InfoPanel_system): - # 确保目标目录存在 - if not os.path.exists(core_dest): - os.makedirs(core_dest) - - # 复制文件 - shutil.copy2(source_InfoPanel_system, os.path.join(core_dest, "InfoPanelManager.py")) - print("✓ core/InfoPanelManager.py文件已复制到build目录") - else: - print("⚠️ core/InfoPanelManager.py文件未找到") - - except Exception as e: - print(f"⚠️ 复制core/InfoPanelManager.py文件时出错: {str(e)}") + if os.path.exists(source_file): + shutil.copy2(source_file,os.path.join(core_dest,file_name)) def _saveGUIElementsToJSON(self, build_dir, project_path): """保存GUI元素到JSON文件,内容与_collectGUIElementInfo保持一致""" diff --git a/templates/main_template.py b/templates/main_template.py index 2c6ce33b..51ededf4 100644 --- a/templates/main_template.py +++ b/templates/main_template.py @@ -11,7 +11,7 @@ from __future__ import print_function import json from direct.actor.Actor import Actor -from panda3d.core import TextNode, CardMaker, TextureStage, NodePath, Texture, TransparencyAttrib +from panda3d.core import TextNode, CardMaker, TextureStage, NodePath, Texture, TransparencyAttrib, CollisionTraverser from core.InfoPanelManager import InfoPanelManager # 获取渲染管线路径 # 在文件开头添加sys导入(如果还没有的话) @@ -52,6 +52,8 @@ from direct.task.TaskManagerGlobal import taskMgr # os.chdir(os.path.dirname(os.path.realpath(__file__))) from core.script_system import ScriptManager +from core.CustomMouseController import CustomMouseController +from panda3d.core import CollisionTraverser class MainApp(ShowBase): def __init__(self): @@ -109,10 +111,16 @@ class MainApp(ShowBase): print(f"导入MovementController失败: {e}") self.controller = None + self._last_click_time = 0 + self._last_clicked_node = None + self._double_click_threshold = 0.3 + self._loadFont() self.loadFullScene() self.loadGUIFromJSON() + self.setupMouseClickHandler() + self.cTrav = CollisionTraverser() if hasattr(self, 'accept'): base.accept("l", self.tour) @@ -758,35 +766,284 @@ class MainApp(ShowBase): print(f"正在为元素 {element.getName()} 挂载脚本") print(f"可用脚本列表: {self.script_manager.get_available_scripts()}") + if not hasattr(self,'script_manager'): + print("脚本管理器未初始化") + return + for script_info in script_info_list: script_name = script_info["name"] script_file = script_info.get("file", "") - # 从文件路径中提取脚本类名 - if script_file: - # 获取脚本文件名(不含路径和扩展名) - script_filename = os.path.basename(script_file) - script_class_name = os.path.splitext(script_filename)[0] - print(f"尝试挂载脚本: {script_class_name} (来自文件: {script_file})") - - # 使用脚本管理器为元素添加脚本 - script_component = self.script_manager.add_script_to_object(element, script_class_name) + if script_name: + script_component = self.script_manager.add_script_to_object(element,script_name) if script_component: - print(f"✓ 脚本 {script_class_name} 已挂载到元素 {element.getName()}") + print(f"✓ 脚本 {script_name} 已挂载到元素 {element.getName()}") else: - print(f"⚠️ 脚本 {script_class_name} 挂载失败") + print(f"⚠️ 脚本 {script_name} 挂载失败") # 列出可用脚本帮助调试 available_scripts = self.script_manager.get_available_scripts() print(f"当前可用脚本: {available_scripts}") else: - print(f"⚠️ 脚本信息不完整: {script_name}") + print(f"⚠️ 脚本信息不完整: {script_info}") + + # # 从文件路径中提取脚本类名 + # if script_file: + # # 获取脚本文件名(不含路径和扩展名) + # script_filename = os.path.basename(script_file) + # script_class_name = os.path.splitext(script_filename)[0] + # print(f"尝试挂载脚本: {script_class_name} (来自文件: {script_file})") + # + # # 使用脚本管理器为元素添加脚本 + # script_component = self.script_manager.add_script_to_object(element, script_class_name) + # + # if script_component: + # print(f"✓ 脚本 {script_class_name} 已挂载到元素 {element.getName()}") + # else: + # print(f"⚠️ 脚本 {script_class_name} 挂载失败") + # # 列出可用脚本帮助调试 + # available_scripts = self.script_manager.get_available_scripts() + # print(f"当前可用脚本: {available_scripts}") + # else: + # print(f"⚠️ 脚本信息不完整: {script_name}") except Exception as e: print(f"挂载脚本到元素 {element.getName()} 失败: {str(e)}") import traceback traceback.print_exc() + def checkDoubleClick(self,nodePath): + try: + import time + current_time = time.time() + + is_double_click = (self._last_clicked_node == nodePath and + nodePath is not None and + current_time - self._last_click_time180: + angle -= 360 + while angle < -180: + angle += 360 + return angle + + def _cameraFocusTask(self,task): + try: + if not hasattr(self,'_camera_focus_data'): + return task.done + + data = self._camera_focus_data + from direct.showbase.ShowBaseGlobal import globalClock + data.elapsed_time += globalClock.getDt() + + t = min(1.0,data.elapsed_time/data.duration) + + smooth_t = t*t*(3-2*t) + + current_pos = data.start_pos + (data.end_pos - data.start_pos) * smooth_t + self.cam.setPos(current_pos) + + start_h = self._normalizeAngle(data.start_hpr.x) + end_h = self._normalizeAngle(data.end_hpr.x) + start_p = self._normalizeAngle(data.start_hpr.y) + end_p = self._normalizeAngle(data.end_hpr.y) + start_r = self._normalizeAngle(data.start_hpr.z) + end_r = self._normalizeAngle(data.end_hpr.z) + + if abs(end_h - start_h)>180: + if end_h > start_h: + start_h += 360 + else: + end_h += 360 + + if abs(end_p - start_p) > 180: + if end_p > start_p: + start_p += 360 + else: + end_p += 360 + + if abs(end_r - start_r)>180: + if end_r > start_r: + start_r += 360 + else: + end_r += 360 + + current_hpr = Vec3( + start_h + (end_h - start_h)*smooth_t, + start_p + (end_p - start_p)*smooth_t, + start_r + (end_r - start_r)*smooth_t + ) + + current_hpr.x = self._normalizeAngle(current_hpr.x) + current_hpr.y = self._normalizeAngle(current_hpr.y) + current_hpr.z = self._normalizeAngle(current_hpr.z) + + self.cam.setHpr(current_hpr) + + if t>=1.0: + return task.done + + return task.cont + except Exception as e: + print(f"摄像机聚焦动画失败{e}") + return task.done + + def setupMouseClickHandler(self): + try: + self.accept("mouse1", self.onMouseClick) + + if not hasattr(self,'mouseWatcherNode'): + from panda3d.core import MouseWatcher + self.mouseWatcherNode = MouseWatcher() + except Exception as e: + print(f"设置鼠标点击处理器失败: {e}") + + def onMouseClick(self): + try: + if not hasattr(self, 'mouseWatcherNode') or not self.mouseWatcherNode.hasMouse(): + return + + mouse_pos = self.mouseWatcherNode.getMouse() + + from panda3d.core import CollisionRay, CollisionNode, CollisionHandlerQueue, BitMask32 + from panda3d.core import GeomNode + + # 创建射线 + ray = CollisionRay() + ray.setFromLens(self.camNode, mouse_pos.x, mouse_pos.y) + + # 创建碰撞节点 + ray_node = CollisionNode('mouseRay') + ray_node.addSolid(ray) + ray_node.setFromCollideMask(BitMask32.bit(0)) + + # 附加到相机 + ray_np = self.camera.attachNewNode(ray_node) + + # 创建碰撞队列 + handler = CollisionHandlerQueue() + + # 修复语法错误:正确初始化碰撞遍历器 + if not hasattr(self, 'cTrav') or self.cTrav is None: + self.cTrav = CollisionTraverser() + + self.cTrav.addCollider(ray_np, handler) + self.cTrav.traverse(self.render) + + # 检查碰撞结果 + if handler.getNumEntries() > 0: + # 按距离排序 + handler.sortEntries() + + # 获取最近的碰撞节点 + entry = handler.getEntry(0) + clicked_node = entry.getIntoNodePath() + + # 向上遍历找到可选择的父节点 + current_node = clicked_node + while current_node and not current_node.isEmpty(): + # 检查节点是否应该被选择 + if (current_node.hasTag("is_scene_element") or + current_node.hasTag("element_type") or + current_node.getName() not in ["render", "camera", "ambient_light", "directional_light"]): + + # 检查是否为双击 + if self.checkDoubleClick(current_node): + print(f"双击节点: {current_node.getName()}") + self.focusCameraOnNode(current_node) + break + else: + print(f"单击节点: {current_node.getName()}") + + current_node = current_node.getParent() + # 避免无限循环 + if current_node.getName() == "render": + break + + # 清理碰撞器 + ray_np.removeNode() + + except Exception as e: + print(f"处理鼠标点击失败: {e}") + import traceback + traceback.print_exc() + # 在 main.py 的最后部分,修改为: if __name__ == "__main__":