# Conflicts: # RenderPipelineFile/samples/06-Car/main.py # main.py # ui/main_window.py
829 lines
31 KiB
Python
829 lines
31 KiB
Python
import warnings
|
||
|
||
from core.InfoPanelManager import InfoPanelManager
|
||
from demo.video_integration import VideoManager
|
||
|
||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||
|
||
import sys
|
||
import builtins
|
||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction,
|
||
QDockWidget, QTreeWidget, QListWidget, QWidget, QVBoxLayout, QTreeWidgetItem,
|
||
QLabel, QLineEdit, QFormLayout, QDoubleSpinBox, QScrollArea, QTreeView, QInputDialog, QFileDialog, QMessageBox, QDialog, QGroupBox, QHBoxLayout, QPushButton, QDialogButtonBox)
|
||
from PyQt5.QtCore import Qt, QDir, QUrl
|
||
from PyQt5.QtGui import QDrag, QPainter, QPixmap
|
||
from PyQt5.QtWidgets import QFileSystemModel
|
||
from QPanda3D.QPanda3DWidget import QPanda3DWidget
|
||
from panda3d.core import loadPrcFileData
|
||
loadPrcFileData("", "assertions 0")
|
||
from core.world import CoreWorld
|
||
from core.selection import SelectionSystem
|
||
from core.event_handler import EventHandler
|
||
from core.tool_manager import ToolManager
|
||
from core.script_system import ScriptManager
|
||
from gui.gui_manager import GUIManager
|
||
from core.terrain_manager import TerrainManager
|
||
from scene.scene_manager import SceneManager
|
||
from project.project_manager import ProjectManager
|
||
from ui.widgets import CustomPanda3DWidget, CustomFileView, CustomTreeWidget
|
||
from ui.property_panel import PropertyPanelManager
|
||
from ui.interface_manager import InterfaceManager
|
||
from panda3d.core import (CardMaker, Vec4, Vec3, ColorAttrib, MaterialAttrib,
|
||
GeomNode, NodePath, Material, CollisionTraverser,
|
||
CollisionHandlerQueue, CollisionNode, CollisionRay,
|
||
Plane, Point3, Point2, BitMask32, CollisionSphere,
|
||
CollisionPlane, ModelPool, Filename, ModelRoot,
|
||
AmbientLight, DirectionalLight, TextureAttrib, DriveInterface, WindowProperties)
|
||
from panda3d.egg import EggData, EggVertexPool, EggPolygon
|
||
from direct.task import Task
|
||
from direct.task.TaskManagerGlobal import taskMgr
|
||
from direct.showbase.ShowBase import ShowBase
|
||
from direct.showbase.DirectObject import DirectObject
|
||
from direct.showbase.ShowBaseGlobal import globalClock, aspect2d
|
||
import os
|
||
import json
|
||
import datetime
|
||
from direct.actor.Actor import Actor
|
||
from PyQt5.sip import wrapinstance
|
||
#from RenderPipelineFile.toolkit.material_editor.main import MaterialEditor
|
||
|
||
|
||
class MyWorld(CoreWorld):
|
||
def __init__(self):
|
||
super().__init__()
|
||
|
||
# 初始化选择和变换系统
|
||
self.selection = SelectionSystem(self)
|
||
|
||
# 绑定F键用于聚焦选中节点
|
||
self.accept("f", self.onFocusKeyPressed)
|
||
self.accept("F", self.onFocusKeyPressed) # 大写F
|
||
|
||
#初始化巡检系统
|
||
self.patrol_system = PatrolSystem(self)
|
||
self.accept("p",self.onPatrolKeyPressed)
|
||
self.accept("P",self.onPatrolKeyPressed)
|
||
|
||
# 初始化事件处理系统
|
||
self.event_handler = EventHandler(self)
|
||
|
||
# 初始化工具管理系统
|
||
self.tool_manager = ToolManager(self)
|
||
|
||
# 初始化脚本管理系统
|
||
self.script_manager = ScriptManager(self)
|
||
|
||
# 初始化GUI管理系统
|
||
self.gui_manager = GUIManager(self)
|
||
|
||
# 初始化视频管理
|
||
self.video_manager = VideoManager(self)
|
||
|
||
# 初始化场景管理系统
|
||
self.scene_manager = SceneManager(self)
|
||
|
||
# 初始化项目管理系统
|
||
self.project_manager = ProjectManager(self)
|
||
|
||
# 初始化属性面板管理系统
|
||
self.property_panel = PropertyPanelManager(self)
|
||
|
||
# 初始化界面管理系统
|
||
self.interface_manager = InterfaceManager(self)
|
||
|
||
|
||
# 启动脚本系统
|
||
self.script_manager.start_system()
|
||
|
||
#self.material_editor = None
|
||
self.terrain_manager = TerrainManager(self)
|
||
|
||
self.terrain_edit_radius = 3.0
|
||
self.terrain_edit_strength=0.3
|
||
self.terrain_edit_operation = "add"
|
||
|
||
self.info_panel_manager = InfoPanelManager(self)
|
||
|
||
self.command_manager = CommandManager()
|
||
|
||
# 初始化碰撞管理器
|
||
from core.collision_manager import CollisionManager
|
||
self.collision_manager = CollisionManager(self)
|
||
|
||
# 初始化VR管理器
|
||
try:
|
||
from core.vr_manager import VRManager
|
||
self.vr_manager = VRManager(self)
|
||
print("✓ VR管理器初始化完成")
|
||
except Exception as e:
|
||
print(f"⚠ VR管理器初始化失败: {e}")
|
||
self.vr_manager = None
|
||
|
||
# 调试选项
|
||
self.debug_collision = True # 是否显示碰撞体
|
||
|
||
# 默认启用模型间碰撞检测(可选)
|
||
self.enableModelCollisionDetection(enable=True, frequency=0.1, threshold=0.5)
|
||
|
||
try:
|
||
self.property_panel = PropertyPanelManager(self)
|
||
print("✓ 属性面板管理器初始化完成")
|
||
except Exception as e:
|
||
print(f"⚠ 属性面板管理器初始化失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
self.property_panel = None
|
||
|
||
print("✓ MyWorld 初始化完成")
|
||
print("✅ 碰撞管理器已初始化")
|
||
|
||
# ==================== 兼容性属性 ====================
|
||
|
||
# 保留models属性以兼容现有代码
|
||
@property
|
||
def models(self):
|
||
"""模型列表的兼容性属性"""
|
||
return self.scene_manager.models
|
||
|
||
@models.setter
|
||
def models(self, value):
|
||
"""模型列表的兼容性设置器"""
|
||
self.scene_manager.models = value
|
||
|
||
# 保留gui_elements属性以兼容现有代码
|
||
@property
|
||
def gui_elements(self):
|
||
"""GUI元素列表的兼容性属性"""
|
||
return self.gui_manager.gui_elements
|
||
|
||
@gui_elements.setter
|
||
def gui_elements(self, value):
|
||
"""GUI元素列表的兼容性设置器"""
|
||
self.gui_manager.gui_elements = value
|
||
|
||
# 保留gui_elements属性以兼容现有代码
|
||
@property
|
||
def Spotlight(self):
|
||
"""GUI元素列表的兼容性属性"""
|
||
return self.scene_manager.Spotlight
|
||
|
||
@Spotlight.setter
|
||
def Spotlight(self, value):
|
||
"""GUI元素列表的兼容性设置器"""
|
||
self.scene_manager.Spotlight = value
|
||
|
||
@property
|
||
def Pointlight(self):
|
||
return self.scene_manager.Pointlight
|
||
|
||
@Pointlight.setter
|
||
def Pointlight(self,value):
|
||
self.scene_manager.Pointlight = value
|
||
|
||
|
||
# 保留guiEditMode属性以兼容现有代码
|
||
@property
|
||
def guiEditMode(self):
|
||
"""GUI编辑模式的兼容性属性"""
|
||
return self.gui_manager.guiEditMode
|
||
|
||
@guiEditMode.setter
|
||
def guiEditMode(self, value):
|
||
"""GUI编辑模式的兼容性设置器"""
|
||
self.gui_manager.guiEditMode = value
|
||
|
||
# 保留currentTool属性以兼容现有代码
|
||
@property
|
||
def currentTool(self):
|
||
"""当前工具的兼容性属性"""
|
||
return self.tool_manager.currentTool
|
||
|
||
@currentTool.setter
|
||
def currentTool(self, value):
|
||
"""当前工具的兼容性设置器"""
|
||
self.tool_manager.currentTool = value
|
||
|
||
# 保留treeWidget属性以兼容现有代码
|
||
@property
|
||
def treeWidget(self):
|
||
"""树形控件的兼容性属性"""
|
||
return self.interface_manager.treeWidget
|
||
|
||
@treeWidget.setter
|
||
def treeWidget(self, value):
|
||
"""树形控件的兼容性设置器"""
|
||
self.interface_manager.treeWidget = value
|
||
|
||
#保留terrains属性以兼容现有代码
|
||
@property
|
||
def terrains(self):
|
||
"""地形列表的兼容性属性"""
|
||
return self.terrain_manager.terrains
|
||
|
||
@terrains.setter
|
||
def terrains(self,value):
|
||
"""地形列表的兼容性设置器"""
|
||
self.terrain_manager.terrains = value
|
||
|
||
# ==================== GUI管理功能代理 ====================
|
||
|
||
# GUI元素创建方法 - 代理到gui_manager
|
||
def createGUIButton(self, pos=(0, 0, 0), text="按钮", size=0.1):
|
||
"""创建2D GUI按钮"""
|
||
return self.gui_manager.createGUIButton(pos, text, size)
|
||
|
||
def createGUILabel(self, pos=(0, 0, 0), text="标签", size=0.08):
|
||
"""创建2D GUI标签"""
|
||
return self.gui_manager.createGUILabel(pos, text, size)
|
||
|
||
def createGUIEntry(self, pos=(0, 0, 0), placeholder="输入文本...", size=0.08):
|
||
"""创建2D GUI文本输入框"""
|
||
return self.gui_manager.createGUIEntry(pos, placeholder, size)
|
||
|
||
def createGUI3DText(self, pos=(0, 0, 0), text="3D文本", size=1):
|
||
"""创建3D空间文本"""
|
||
return self.gui_manager.createGUI3DText(pos, text, size)
|
||
|
||
def createGUI3DImage(self,pos=(0,0,0),text="3D图片",size=(1,1)):
|
||
"""创建3D图片"""
|
||
return self.gui_manager.createGUI3DImage(pos,text,size)
|
||
|
||
def createGUI2DImage(self, pos=(0, 0, 0), image_path=None, size=2):
|
||
"""创建2D GUI图片"""
|
||
return self.gui_manager.createGUI2DImage(pos, image_path, size)
|
||
|
||
def createVideoScreen(self,pos=(0,0,0),size=1,video_path=None):
|
||
"""创建视频屏幕"""
|
||
return self.gui_manager.createVideoScreen(pos,size,video_path)
|
||
|
||
def create2DVideoScreen(self,pos=(0,0,0),size=0.2,video_path=None):
|
||
"""创建2D视频屏幕"""
|
||
return self.gui_manager.createGUI2DVideoScreen(pos,size,video_path)
|
||
|
||
def createSphericalVideo(self,pos=(0,0,0),radius=5.0,video_path=None):
|
||
"""创建360度视频"""
|
||
return self.gui_manager.createSphericalVideo(pos,radius,video_path)
|
||
|
||
def playSphericalVideo(self,spherical_video_node):
|
||
return self.gui_manager.playSphericalVideo(spherical_video_node)
|
||
|
||
def pauseSphericalVideo(self,spherical_video_node):
|
||
return self.gui_manager.pauseSphericalVideo(spherical_video_node)
|
||
|
||
def setSphericalVideoTime(self,spherical_video_node,time_seconds):
|
||
return self.gui_manager.setSphericalVideoTime(spherical_video_node,time_seconds)
|
||
|
||
def createSpotLight(self,pos=(0,0,5)):
|
||
"""创建聚光灯"""
|
||
return self.scene_manager.createSpotLight(pos)
|
||
|
||
def createPointLight(self,pos=(0,0,5)):
|
||
"""创建点光源"""
|
||
return self.scene_manager.createPointLight(pos)
|
||
|
||
def createGUIVirtualScreen(self, pos=(0, 0, 0), size=(2, 1), text="虚拟屏幕"):
|
||
"""创建3D虚拟屏幕"""
|
||
return self.gui_manager.createGUIVirtualScreen(pos, size, text)
|
||
|
||
def createGUISlider(self, pos=(0, 0, 0), text="滑块", scale=0.3):
|
||
"""创建2D GUI滑块"""
|
||
return self.gui_manager.createGUISlider(pos, text, scale)
|
||
|
||
# GUI元素管理方法 - 代理到gui_manager
|
||
def deleteGUIElement(self, gui_element):
|
||
"""删除GUI元素"""
|
||
return self.gui_manager.deleteGUIElement(gui_element)
|
||
|
||
def editGUIElement(self, gui_element, property_name, value):
|
||
"""编辑GUI元素属性"""
|
||
return self.gui_manager.editGUIElement(gui_element, property_name, value)
|
||
|
||
def duplicateGUIElement(self, gui_element):
|
||
"""复制GUI元素"""
|
||
return self.gui_manager.duplicateGUIElement(gui_element)
|
||
|
||
def editGUIElementDialog(self, gui_element):
|
||
"""显示GUI元素编辑对话框"""
|
||
return self.gui_manager.editGUIElementDialog(gui_element)
|
||
|
||
# GUI事件处理方法 - 代理到gui_manager
|
||
def onGUIButtonClick(self, button_id):
|
||
"""GUI按钮点击事件处理"""
|
||
return self.gui_manager.onGUIButtonClick(button_id)
|
||
|
||
def onGUIEntrySubmit(self, text, entry_id):
|
||
"""GUI输入框提交事件处理"""
|
||
return self.gui_manager.onGUIEntrySubmit(text, entry_id)
|
||
|
||
# GUI编辑模式方法 - 代理到gui_manager
|
||
def toggleGUIEditMode(self):
|
||
"""切换GUI编辑模式"""
|
||
return self.gui_manager.toggleGUIEditMode()
|
||
|
||
def enterGUIEditMode(self):
|
||
"""进入GUI编辑模式"""
|
||
return self.gui_manager.enterGUIEditMode()
|
||
|
||
def exitGUIEditMode(self):
|
||
"""退出GUI编辑模式"""
|
||
return self.gui_manager.exitGUIEditMode()
|
||
|
||
def createGUIEditPanel(self):
|
||
"""创建GUI编辑面板"""
|
||
return self.gui_manager.createGUIEditPanel()
|
||
|
||
def openGUIPreviewWindow(self):
|
||
"""打开独立的GUI预览窗口"""
|
||
return self.gui_manager.openGUIPreviewWindow()
|
||
|
||
def closeGUIPreviewWindow(self):
|
||
"""关闭GUI预览窗口"""
|
||
return self.gui_manager.closeGUIPreviewWindow()
|
||
|
||
# GUI工具和选择方法 - 代理到gui_manager
|
||
def setGUICreateTool(self, tool_type):
|
||
"""设置GUI创建工具"""
|
||
return self.gui_manager.setGUICreateTool(tool_type)
|
||
|
||
def deleteSelectedGUI(self):
|
||
"""删除选中的GUI元素"""
|
||
return self.gui_manager.deleteSelectedGUI()
|
||
|
||
def copySelectedGUI(self):
|
||
"""复制选中的GUI元素"""
|
||
return self.gui_manager.copySelectedGUI()
|
||
|
||
def handleGUIEditClick(self, hitPos):
|
||
"""处理GUI编辑模式下的点击"""
|
||
return self.gui_manager.handleGUIEditClick(hitPos)
|
||
|
||
def createGUIAtPosition(self, world_pos, gui_type):
|
||
"""在指定位置创建GUI元素"""
|
||
return self.gui_manager.createGUIAtPosition(world_pos, gui_type)
|
||
|
||
def findClickedGUI(self, hitNode):
|
||
"""查找被点击的GUI元素"""
|
||
return self.gui_manager.findClickedGUI(hitNode)
|
||
|
||
def selectGUIInTree(self, gui_element):
|
||
"""在树形控件中选中GUI元素"""
|
||
return self.gui_manager.selectGUIInTree(gui_element)
|
||
|
||
def updateGUISelection(self, gui_element):
|
||
"""更新GUI元素选择状态"""
|
||
return self.gui_manager.updateGUISelection(gui_element)
|
||
|
||
# GUI属性面板方法 - 代理到gui_manager
|
||
def selectGUIColor(self, gui_element):
|
||
"""选择GUI元素颜色"""
|
||
return self.gui_manager.selectGUIColor(gui_element)
|
||
|
||
def editGUI2DPosition(self, gui_element, axis, value):
|
||
"""编辑2D GUI元素位置"""
|
||
return self.gui_manager.editGUI2DPosition(gui_element, axis, value)
|
||
|
||
# ==================== 事件处理代理 ====================
|
||
|
||
def onTreeItemClicked(self, item, column):
|
||
"""处理树形控件项目点击事件 - 代理到interface_manager"""
|
||
return self.interface_manager.onTreeItemClicked(item, column)
|
||
|
||
def setTreeWidget(self, treeWidget):
|
||
"""设置树形控件引用 - 代理到interface_manager"""
|
||
return self.interface_manager.setTreeWidget(treeWidget)
|
||
|
||
def mousePressEventLeft(self, evt):
|
||
"""处理鼠标左键按下事件 - 代理到event_handler"""
|
||
return self.event_handler.mousePressEventLeft(evt)
|
||
|
||
def mouseReleaseEventLeft(self, evt):
|
||
"""处理鼠标左键释放事件 - 代理到event_handler"""
|
||
return self.event_handler.mouseReleaseEventLeft(evt)
|
||
|
||
def wheelForward(self, data=None):
|
||
"""处理滚轮向前滚动(前进) - 代理到event_handler"""
|
||
return self.event_handler.wheelForward(data)
|
||
|
||
def wheelBackward(self, data=None):
|
||
"""处理滚轮向后滚动(后退) - 代理到event_handler"""
|
||
return self.event_handler.wheelBackward(data)
|
||
|
||
def mousePressEventMiddle(self, evt):
|
||
"""处理鼠标中键按下事件 - 代理到event_handler"""
|
||
return self.event_handler.mousePressEventMiddle(evt)
|
||
|
||
def mouseReleaseEventMiddle(self, evt):
|
||
"""处理鼠标中键释放事件 - 代理到event_handler"""
|
||
return self.event_handler.mouseReleaseEventMiddle(evt)
|
||
|
||
def mouseMoveEvent(self, evt):
|
||
"""处理鼠标移动事件 - 代理到event_handler"""
|
||
return self.event_handler.mouseMoveEvent(evt)
|
||
|
||
# ==================== 射线显示控制 ====================
|
||
|
||
def toggleRayDisplay(self):
|
||
"""切换射线显示状态 - 代理到event_handler"""
|
||
return self.event_handler.toggleRayDisplay()
|
||
|
||
def setRayDisplay(self, show=True):
|
||
"""设置射线显示状态 - 代理到event_handler"""
|
||
self.event_handler.showRay = show
|
||
if not show:
|
||
self.event_handler.clearRay()
|
||
return show
|
||
|
||
def getRayDisplay(self):
|
||
"""获取射线显示状态 - 代理到event_handler"""
|
||
return self.event_handler.showRay
|
||
|
||
def setRayLifetime(self, seconds):
|
||
"""设置射线显示时长(秒) - 代理到event_handler"""
|
||
self.event_handler.rayLifetime = seconds
|
||
print(f"射线显示时长设置为: {seconds}秒")
|
||
|
||
def getRayLifetime(self):
|
||
"""获取射线显示时长 - 代理到event_handler"""
|
||
return self.event_handler.rayLifetime
|
||
|
||
# ==================== 属性面板代理 ====================
|
||
|
||
def setPropertyLayout(self, layout):
|
||
"""设置属性面板布局引用 - 代理到property_panel"""
|
||
return self.property_panel.setPropertyLayout(layout)
|
||
|
||
def clearPropertyPanel(self):
|
||
"""清空属性面板 - 代理到property_panel"""
|
||
return self.property_panel.clearPropertyPanel()
|
||
|
||
def updatePropertyPanel(self, item):
|
||
"""更新属性面板显示 - 代理到property_panel"""
|
||
return self.property_panel.updatePropertyPanel(item)
|
||
|
||
def updateGUIPropertyPanel(self, gui_element):
|
||
"""更新GUI元素属性面板 - 代理到property_panel"""
|
||
return self.property_panel.updateGUIPropertyPanel(gui_element)
|
||
|
||
def removeActorForModel(self,model):
|
||
return self.property_panel.removeActorForModel( model)
|
||
|
||
def updateNodeVisibilityAfterDrag(self,item):
|
||
return self.property_panel.updateNodeVisibilityAfterDrag(item)
|
||
|
||
# ==================== 工具管理代理 ====================
|
||
|
||
def setCurrentTool(self, tool):
|
||
"""设置当前工具 - 代理到tool_manager"""
|
||
return self.tool_manager.setCurrentTool(tool)
|
||
|
||
# ==================== 场景管理功能代理 ====================
|
||
|
||
# 模型导入和处理方法 - 代理到scene_manager
|
||
def importModel(self, filepath):
|
||
"""导入模型到场景"""
|
||
# 检查是否是FBX文件,如果是则询问用户是否要转换为GLB
|
||
if filepath.lower().endswith('.fbx'):
|
||
try:
|
||
from PyQt5.QtWidgets import QMessageBox
|
||
reply = QMessageBox.question(
|
||
None,
|
||
'格式转换选择',
|
||
'FBX文件检测到!\n\n是否要尝试转换为GLB格式以获得更好的动画支持?\n\n点击"是":尝试转换为GLB格式(需要安装转换工具)\n点击"否":直接使用原始FBX格式导入',
|
||
QMessageBox.Yes | QMessageBox.No,
|
||
QMessageBox.Yes
|
||
)
|
||
auto_convert = (reply == QMessageBox.Yes)
|
||
except ImportError:
|
||
# 如果没有PyQt5,默认不转换
|
||
print("检测到FBX文件,由于GUI不可用,将直接使用原始格式导入")
|
||
auto_convert = False
|
||
else:
|
||
# 非FBX文件,保持原有逻辑
|
||
auto_convert = True
|
||
|
||
return self.scene_manager.importModel(filepath, auto_convert_to_glb=auto_convert)
|
||
|
||
def importModelAsync(self, filepath):
|
||
"""异步导入模型"""
|
||
return self.scene_manager.importModelAsync(filepath)
|
||
|
||
# 材质和几何体处理方法 - 代理到scene_manager
|
||
def processMaterials(self, model):
|
||
"""处理模型材质"""
|
||
return self.scene_manager.processMaterials(model)
|
||
|
||
def processModelGeometry(self, model):
|
||
"""处理模型几何体"""
|
||
return self.scene_manager.processModelGeometry(model)
|
||
|
||
# 碰撞系统方法 - 代理到scene_manager
|
||
def setupCollision(self, model):
|
||
"""为模型设置碰撞检测"""
|
||
return self.scene_manager.setupCollision(model)
|
||
|
||
# 场景树管理方法 - 代理到scene_manager
|
||
def updateSceneTree(self):
|
||
"""更新场景树显示"""
|
||
return self.scene_manager.updateSceneTree()
|
||
|
||
# 场景保存和加载方法 - 代理到scene_manager
|
||
def saveScene(self, filename):
|
||
"""保存场景到BAM文件"""
|
||
return self.scene_manager.saveScene(filename)
|
||
|
||
def loadScene(self, filename):
|
||
"""从BAM文件加载场景"""
|
||
return self.scene_manager.loadScene(filename)
|
||
|
||
# 模型管理方法 - 代理到scene_manager
|
||
def deleteModel(self, model):
|
||
"""删除模型"""
|
||
return self.scene_manager.deleteModel(model)
|
||
|
||
def clearAllModels(self):
|
||
"""清除所有模型"""
|
||
return self.scene_manager.clearAllModels()
|
||
|
||
def getModels(self):
|
||
"""获取模型列表"""
|
||
return self.scene_manager.getModels()
|
||
|
||
def getModelCount(self):
|
||
"""获取模型数量"""
|
||
return self.scene_manager.getModelCount()
|
||
|
||
def findModelByName(self, name):
|
||
"""根据名称查找模型"""
|
||
return self.scene_manager.findModelByName(name)
|
||
|
||
# ==================== 脚本系统功能代理 ====================
|
||
|
||
# 脚本系统控制方法 - 代理到script_manager
|
||
def startScriptSystem(self):
|
||
"""启动脚本系统"""
|
||
return self.script_manager.start_system()
|
||
|
||
def stopScriptSystem(self):
|
||
"""停止脚本系统"""
|
||
return self.script_manager.stop_system()
|
||
|
||
def enableHotReload(self, enabled=True):
|
||
"""启用/禁用热重载"""
|
||
self.script_manager.hot_reload_enabled = enabled
|
||
if enabled:
|
||
self.script_manager.start_hot_reload()
|
||
else:
|
||
self.script_manager.stop_hot_reload()
|
||
|
||
# 脚本创建和加载方法 - 代理到script_manager
|
||
def createScript(self, script_name, template="basic"):
|
||
"""创建新脚本文件"""
|
||
return self.script_manager.create_script_file(script_name, template)
|
||
|
||
def loadScript(self, script_path):
|
||
"""从文件加载脚本"""
|
||
return self.script_manager.load_script_from_file(script_path)
|
||
|
||
def loadAllScripts(self, directory=None):
|
||
"""从目录加载所有脚本"""
|
||
return self.script_manager.load_all_scripts_from_directory(directory)
|
||
|
||
def reloadScript(self, script_name):
|
||
"""重新加载脚本"""
|
||
return self.script_manager.reload_script(script_name)
|
||
|
||
# 脚本挂载和管理方法 - 代理到script_manager
|
||
def addScript(self, game_object, script_name):
|
||
"""为游戏对象添加脚本"""
|
||
return self.script_manager.add_script_to_object(game_object, script_name)
|
||
|
||
def removeScript(self, game_object, script_name):
|
||
"""从游戏对象移除脚本"""
|
||
return self.script_manager.remove_script_from_object(game_object, script_name)
|
||
|
||
def getScripts(self, game_object):
|
||
"""获取对象上的所有脚本"""
|
||
return self.script_manager.get_scripts_on_object(game_object)
|
||
|
||
def getScript(self, game_object, script_name):
|
||
"""获取对象上的特定脚本"""
|
||
return self.script_manager.get_script_on_object(game_object, script_name)
|
||
|
||
# 脚本信息查询方法 - 代理到script_manager
|
||
def getAvailableScripts(self):
|
||
"""获取所有可用的脚本名称"""
|
||
return self.script_manager.get_available_scripts()
|
||
|
||
def getScriptInfo(self, script_name):
|
||
"""获取脚本信息"""
|
||
return self.script_manager.get_script_info(script_name)
|
||
|
||
def listAllScripts(self):
|
||
"""列出所有脚本信息"""
|
||
return self.script_manager.list_all_scripts()
|
||
|
||
def loadCesiumTileset(self,tileset_url,position=(0,0,0)):
|
||
return self.scene_manager.load_cesium_tileset(tileset_url,position)
|
||
|
||
def addCesiumTileset(self,name,url,position=(0,0,0)):
|
||
if hasattr(self,'gui_manager') and self.gui_manager:
|
||
return self.gui_manager.addCesiumTilesetToScene(name,url,position)
|
||
else:
|
||
return self.scene_manager.load_cesium_tileset(url,position)
|
||
|
||
# ==================== 地形管理功能代理 ====================
|
||
# 地形创建方法 - 代理到terrain_manager
|
||
def createTerrainFromHeightMap(self, heightmap_path, scale=(1, 1, 1)):
|
||
"""从高度图创建地形"""
|
||
return self.terrain_manager.createTerrainFromHeightMap(heightmap_path, scale)
|
||
|
||
def createFlatTerrain(self, size=(0.3, 0.3), resolution=256):
|
||
"""创建平面地形"""
|
||
return self.terrain_manager.createFlatTerrain(size, resolution)
|
||
|
||
def updateTerrain(self):
|
||
"""更新所有地形的LOD"""
|
||
return self.terrain_manager.updateTerrain()
|
||
|
||
def getTerrainHeight(self, terrain_info, x, y):
|
||
"""获取地形上指定点的高度"""
|
||
return self.terrain_manager.getTerrainHeight(terrain_info, x, y)
|
||
|
||
def setTerrainEditParameters(self,radius=None,strength=None,operation=None):
|
||
if radius is not None:
|
||
self.terrain_edit_radius = float(radius)
|
||
if strength is not None:
|
||
self.terrain_edit_strenght = float(strength)
|
||
if operation is not None:
|
||
self.terrain_edit_operation = operation
|
||
print(f"地形编辑参数已更新: 半径={self.terrain_edit_radius}, 强度={self.terrain_edit_strength}, 操作={self.terrain_edit_operation}")
|
||
def getTerrainEditParameters(self):
|
||
"""获取当前地形编辑参数"""
|
||
return {
|
||
'radius': self.terrain_edit_radius,
|
||
'strength': self.terrain_edit_strength,
|
||
'operation': self.terrain_edit_operation
|
||
}
|
||
|
||
def modifyTerrainHeight(self, terrain_info, x, y, radius, strength, operation="add"):
|
||
"""修改地形高度的便捷方法"""
|
||
if hasattr(self, 'terrain_manager'):
|
||
return self.terrain_manager.modifyTerrainHeight(terrain_info, x, y, radius, strength, operation)
|
||
return False
|
||
|
||
# 添加碰撞管理相关的代理方法
|
||
def enableModelCollisionDetection(self, enable=True, frequency=0.1, threshold=0.5):
|
||
"""启用模型间碰撞检测"""
|
||
return self.collision_manager.enableModelCollisionDetection(enable, frequency, threshold)
|
||
|
||
def detectModelCollisions(self, specific_models=None, log_results=True):
|
||
"""检测模型间碰撞"""
|
||
return self.collision_manager.detectModelCollisions(specific_models, log_results)
|
||
|
||
def getCollisionHistory(self, limit=None):
|
||
"""获取碰撞历史"""
|
||
return self.collision_manager.getCollisionHistory(limit)
|
||
|
||
def getCollisionStatistics(self):
|
||
"""获取碰撞统计"""
|
||
return self.collision_manager.getCollisionStatistics()
|
||
|
||
def setupKeyboardEvents(self):
|
||
"""设置键盘事件"""
|
||
try:
|
||
# 绑定 F 键用于聚焦选中节点
|
||
self.accept("f", self.onFocusKeyPressed)
|
||
self.accept("F", self.onFocusKeyPressed) # 大写F
|
||
|
||
print("✓ 键盘事件绑定完成")
|
||
|
||
except Exception as e:
|
||
print(f"设置键盘事件失败: {e}")
|
||
|
||
def onFocusKeyPressed(self):
|
||
"""处理 F 键按下事件"""
|
||
try:
|
||
#print("检测到 F 键按下")
|
||
|
||
# 检查是否有选中的节点
|
||
if hasattr(self, 'selection') and self.selection.selectedNode:
|
||
#print(f"当前选中节点: {self.selection.selectedNode.getName()}")
|
||
# 调用选择系统的聚焦功能(可以选择带动画或不带动画的版本)
|
||
# self.selection.focusCameraOnSelectedNode() # 无动画版本
|
||
self.selection.focusCameraOnSelectedNodeAdvanced() # 带动画版本
|
||
else:
|
||
print("当前没有选中任何节点")
|
||
|
||
except Exception as e:
|
||
print(f"处理 F 键事件失败: {e}")
|
||
|
||
def onPatrolKeyPressed(self):
|
||
"""处理 P 键按下事件 - 控制巡检系统"""
|
||
try:
|
||
print("检测到 P 键按下")
|
||
|
||
if not self.patrol_system.is_patrolling:
|
||
# 如果巡检系统没有点,创建默认巡检路线
|
||
if not self.patrol_system.patrol_points:
|
||
self.createDefaultPatrolRoute()
|
||
|
||
# 开始巡检
|
||
if self.patrol_system.start_patrol():
|
||
print("✓ 巡检已开始")
|
||
else:
|
||
print("✗ 巡检启动失败")
|
||
else:
|
||
# 停止巡检
|
||
if self.patrol_system.stop_patrol():
|
||
print("✓ 巡检已停止")
|
||
else:
|
||
print("✗ 巡检停止失败")
|
||
|
||
except Exception as e:
|
||
print(f"处理 P 键事件失败: {e}")
|
||
|
||
def createDefaultPatrolRoute(self):
|
||
"""创建默认巡检路线(使用自动朝向)"""
|
||
try:
|
||
# 清空现有巡检点
|
||
self.patrol_system.clear_patrol_points()
|
||
|
||
# 添加巡检点,使用None表示朝向下一个点
|
||
self.patrol_system.add_patrol_point((0, -10, 2), (0,0,0), 1.5)
|
||
self.patrol_system.add_patrol_point((10, -10, 2), (0,0,0), 1.5)
|
||
self.patrol_system.add_patrol_point((10, 5, 2), (0,0,0), 1.5)
|
||
self.patrol_system.add_patrol_point((10, 0, 5), (0,0,0), 1.5)
|
||
|
||
# 最后一个点可以指定特定的朝向,或者也设为None继续循环
|
||
self.patrol_system.add_patrol_point((0, -10, 2), None, 2.5)
|
||
|
||
print("✓ 默认自动朝向巡检路线已创建")
|
||
self.patrol_system.list_patrol_points()
|
||
|
||
except Exception as e:
|
||
print(f"创建默认自动朝向巡检路线失败: {e}")
|
||
|
||
def _serializeNode(self, node):
|
||
"""序列化节点数据"""
|
||
try:
|
||
return self.world.scene_manager.serializeNode(node)
|
||
except Exception as e:
|
||
print(f"序列化节点失败: {e}")
|
||
return None
|
||
|
||
def _deserializeNode(self, node_data, parent_node):
|
||
"""反序列化节点数据"""
|
||
try:
|
||
return self.world.scene_manager.deserializeNode(node_data, parent_node)
|
||
except Exception as e:
|
||
print(f"反序列化节点失败: {e}")
|
||
return None
|
||
|
||
|
||
# ==================== 项目管理功能代理 ====================
|
||
# 以下函数代理到project_manager模块的对应功能
|
||
|
||
def updateWindowTitle(window, project_name=None):
|
||
"""更新窗口标题 - 代理到project_manager"""
|
||
from project.project_manager import updateWindowTitle as pm_updateWindowTitle
|
||
return pm_updateWindowTitle(window, project_name)
|
||
|
||
def createNewProject(parent_window):
|
||
"""创建新项目 - 代理到project_manager"""
|
||
world = parent_window.centralWidget().world
|
||
return world.project_manager.createNewProject(parent_window)
|
||
|
||
def saveProject(appw):
|
||
"""保存项目 - 代理到project_manager"""
|
||
|
||
world = appw.centralWidget().world
|
||
return world.project_manager.saveProject(appw)
|
||
|
||
def openProject(appw):
|
||
"""打开项目 - 代理到project_manager"""
|
||
world = appw.centralWidget().world
|
||
return world.project_manager.openProject(appw)
|
||
|
||
def openProjectForPath(project_path, appw):
|
||
"""打开项目 - 代理到project_manager"""
|
||
world = appw.centralWidget().world
|
||
return world.project_manager.openProjectForPath(project_path, appw)
|
||
|
||
def buildPackage(appw):
|
||
"""打包项目 - 代理到project_manager"""
|
||
world = appw.centralWidget().world
|
||
return world.project_manager.buildPackage(appw)
|
||
|
||
def run(args = None):
|
||
world = MyWorld()
|
||
|
||
# 使用新的UI模块创建主窗口
|
||
from ui.main_window import setup_main_window
|
||
print(f'Path is {args}')
|
||
app, main_window = setup_main_window(world, args)
|
||
|
||
# 启动应用程序
|
||
sys.exit(app.exec_())
|
||
|
||
if __name__ == "__main__":
|
||
run() |