addRender #7
@ -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)
|
||||
|
||||
@ -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保持一致"""
|
||||
|
||||
@ -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_time<self._double_click_threshold)
|
||||
|
||||
if is_double_click:
|
||||
self._last_click_time = 0
|
||||
self._last_clicked_node = None
|
||||
return True
|
||||
else:
|
||||
self._last_click_time = current_time
|
||||
self._last_clicked_node = nodePath
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"双击检测失败:{e}")
|
||||
return False
|
||||
|
||||
def focusCameraOnNode(self,nodePath):
|
||||
try:
|
||||
if not nodePath or nodePath.isEmpty():
|
||||
print("无效的节点")
|
||||
return
|
||||
bounds = nodePath.getBounds()
|
||||
|
||||
if bounds.isEmpty():
|
||||
center = nodePath.getPos()
|
||||
size = 1.0
|
||||
else:
|
||||
center = bounds.getCenter()
|
||||
size = bounds.getRadius()
|
||||
|
||||
current_cam_pos = self.cam.getPos()
|
||||
current_cam_hpr = self.cam.getHpr()
|
||||
|
||||
view_direction = current_cam_pos - center
|
||||
if view_direction.length()<0.001:
|
||||
view_direction = Vec3(5,-5,2)
|
||||
|
||||
view_direction.normalize()
|
||||
|
||||
optimal_distance = max(size*2,3.0)
|
||||
|
||||
target_cam_pos = center + (view_direction * optimal_distance)
|
||||
|
||||
temp_node = self.render.attachNewNode("temp_lookat_target")
|
||||
temp_node.setPos(center)
|
||||
|
||||
dummy_cam = self.render.attachNewNode("dummy_camera")
|
||||
dummy_cam.setPos(target_cam_pos)
|
||||
dummy_cam.lookAt(temp_node)
|
||||
target_cam_hpr = Vec3(dummy_cam.getHpr())
|
||||
|
||||
temp_node.removeNode()
|
||||
dummy_cam.removeNode()
|
||||
|
||||
self._startCameraFocusAnimation(current_cam_pos,target_cam_pos,current_cam_hpr,target_cam_hpr)
|
||||
|
||||
except Exception as e:
|
||||
print(f"聚焦到节点失败{e}")
|
||||
|
||||
def _startCameraFocusAnimation(self,start_pos,end_pos,start_hpr,end_hpr):
|
||||
try:
|
||||
class CameraFocusData:
|
||||
def __init__(self,start_pos,end_pos,start_hpr,end_hpr):
|
||||
self.start_pos = start_pos
|
||||
self.end_pos = end_pos
|
||||
self.start_hpr = start_hpr
|
||||
self.end_hpr = end_hpr
|
||||
self.elapsed_time = 0
|
||||
self.duration = 0.5
|
||||
|
||||
self._camera_focus_data = CameraFocusData(start_pos,end_pos,start_hpr,end_hpr)
|
||||
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
taskMgr.remove("cameraFocusTask")
|
||||
|
||||
taskMgr.add(self._cameraFocusTask, "cameraFocusTask")
|
||||
except Exception as e:
|
||||
print(f"启动摄像机聚焦动画失败{e}")
|
||||
|
||||
def _normalizeAngle(self,angle):
|
||||
while angle >180:
|
||||
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__":
|
||||
|
||||
Loading…
Reference in New Issue
Block a user