1100 lines
41 KiB
Python
1100 lines
41 KiB
Python
import warnings
|
||
|
||
from core.Command_System import CommandManager
|
||
from core.InfoPanelManager import InfoPanelManager
|
||
from core.patrol_system import PatrolSystem
|
||
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 QMeta3D.QMeta3DWidget import QMeta3DWidget
|
||
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 core.patrol_system import PatrolSystem
|
||
from core.Command_System import CommandManager
|
||
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 CustomMeta3DWidget, 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 time
|
||
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 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,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以获得更好的动画支持(不再弹窗询问)
|
||
# 如果你不想自动转换,可以将 auto_convert 改为 False
|
||
auto_convert = False
|
||
|
||
print(f"[模型导入] 文件: {filepath}, 自动转换GLB: {auto_convert}")
|
||
|
||
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 create2DSamplePanel(self):
|
||
"""创建2D示例面板"""
|
||
try:
|
||
from core.InfoPanelManager import createSampleInfoPanel
|
||
result = createSampleInfoPanel(self.render)
|
||
return result
|
||
except Exception as e:
|
||
print(f"创建2D示例面板失败: {e}")
|
||
return None
|
||
|
||
def create3DSamplePanel(self):
|
||
"""创建3D实例面板"""
|
||
try:
|
||
if hasattr(self, 'info_panel_manager') and self.info_panel_manager:
|
||
# 创建3D信息面板
|
||
panel_id = f"3d_sample_{int(time.time())}"
|
||
result = self.info_panel_manager.create3DInfoPanel(
|
||
panel_id=panel_id,
|
||
position=(0, 0, 2),
|
||
size=(1.0, 0.6),
|
||
bg_color=(0.15, 0.25, 0.35, 0.95),
|
||
border_color=(0.3, 0.5, 0.7, 1.0),
|
||
title_color=(0.7, 0.9, 1.0, 1.0),
|
||
content_color=(0.95, 0.95, 0.95, 1.0)
|
||
)
|
||
|
||
# 添加示例内容
|
||
if result:
|
||
sample_data = {
|
||
"标题": "3D信息面板",
|
||
"状态": "运行中",
|
||
"创建时间": time.strftime("%Y-%m-%d %H:%M:%S"),
|
||
"位置": f"X:0, Y:0, Z:2"
|
||
}
|
||
self.info_panel_manager.updatePanelContent(panel_id, content=sample_data)
|
||
|
||
return result
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建3D示例面板失败: {e}")
|
||
return None
|
||
|
||
def createWebPanel(self, url="https://www.example.com"):
|
||
"""创建Web面板"""
|
||
try:
|
||
if hasattr(self, 'info_panel_manager') and self.info_panel_manager:
|
||
panel_id = f"web_panel_{int(time.time())}"
|
||
result = self.info_panel_manager.createHTTPInfoPanel(
|
||
panel_id=panel_id,
|
||
url=url,
|
||
position=(0.8, 0.0),
|
||
size=(0.35, 0.4),
|
||
update_interval=5.0 # 每5秒更新一次
|
||
)
|
||
return result
|
||
return None
|
||
except Exception as e:
|
||
print(f"创建Web面板失败: {e}")
|
||
return None
|
||
|
||
# ==================== 3D对象和GUI创建功能代理 ====================
|
||
|
||
def createEmptyObject(self):
|
||
"""创建空对象"""
|
||
try:
|
||
from panda3d.core import NodePath
|
||
# 创建一个空节点
|
||
empty_node = NodePath("EmptyObject")
|
||
empty_node.reparentTo(self.render)
|
||
empty_node.setPos(0, 0, 0)
|
||
|
||
# 添加到场景管理器
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
self.scene_manager.models.append(empty_node)
|
||
|
||
# 更新场景树
|
||
if hasattr(self, 'updateSceneTree'):
|
||
self.updateSceneTree()
|
||
|
||
print("✓ 空对象创建成功")
|
||
return empty_node
|
||
except Exception as e:
|
||
print(f"✗ 创建空对象失败: {e}")
|
||
return None
|
||
|
||
def create3DText(self, pos=(0, 0, 0), text="3D Text", scale=1.0):
|
||
"""创建3D文本"""
|
||
try:
|
||
from panda3d.core import TextNode, NodePath
|
||
|
||
# 创建文本节点
|
||
text_node = TextNode("3DText")
|
||
text_node.setText(text)
|
||
text_node.setAlign(TextNode.ACenter)
|
||
text_node.setTextColor(1, 1, 1, 1) # 白色
|
||
|
||
# 创建节点路径并设置位置
|
||
text_np = NodePath(text_node)
|
||
text_np.reparentTo(self.render)
|
||
text_np.setPos(pos)
|
||
text_np.setScale(scale)
|
||
|
||
# 添加到场景管理器
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
self.scene_manager.models.append(text_np)
|
||
|
||
# 更新场景树
|
||
if hasattr(self, 'updateSceneTree'):
|
||
self.updateSceneTree()
|
||
|
||
print(f"✓ 3D文本创建成功: {text}")
|
||
return text_np
|
||
except Exception as e:
|
||
print(f"✗ 创建3D文本失败: {e}")
|
||
return None
|
||
|
||
def create3DImage(self, pos=(0, 0, 0), image_path="", size=(1, 1)):
|
||
"""创建3D图片"""
|
||
try:
|
||
from panda3d.core import CardMaker, NodePath
|
||
|
||
if not image_path or not os.path.exists(image_path):
|
||
print("✗ 图片文件不存在")
|
||
return None
|
||
|
||
# 创建卡片几何体
|
||
card_maker = CardMaker("3DImage")
|
||
card_maker.setFrame(-size[0]/2, size[0]/2, -size[1]/2, size[1]/2)
|
||
card = card_maker.generate()
|
||
|
||
# 创建节点路径
|
||
image_np = NodePath(card)
|
||
image_np.reparentTo(self.render)
|
||
image_np.setPos(pos)
|
||
|
||
# 加载纹理
|
||
from panda3d.core import Texture, Filename
|
||
tex = self.loader.loadTexture(Filename.fromOsSpecific(image_path))
|
||
if tex:
|
||
image_np.setTexture(tex, 1)
|
||
else:
|
||
print("✗ 加载纹理失败")
|
||
image_np.removeNode()
|
||
return None
|
||
|
||
# 添加到场景管理器
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
self.scene_manager.models.append(image_np)
|
||
|
||
# 更新场景树
|
||
if hasattr(self, 'updateSceneTree'):
|
||
self.updateSceneTree()
|
||
|
||
print(f"✓ 3D图片创建成功: {os.path.basename(image_path)}")
|
||
return image_np
|
||
except Exception as e:
|
||
print(f"✗ 创建3D图片失败: {e}")
|
||
return None
|
||
|
||
def createCube(self, pos=(0, 0, 0), size=1.0):
|
||
"""创建立方体"""
|
||
try:
|
||
from panda3d.core import NodePath
|
||
|
||
# 创建立方体模型
|
||
cube = self.loader.loadModel("models/environment")
|
||
if not cube:
|
||
# 如果没有默认模型,创建一个简单的立方体
|
||
from panda3d.core import CardMaker
|
||
card_maker = CardMaker("Cube")
|
||
card_maker.setFrame(-size/2, size/2, -size/2, size/2)
|
||
cube = NodePath(card_maker.generate())
|
||
|
||
cube.reparentTo(self.render)
|
||
cube.setPos(pos)
|
||
cube.setScale(size)
|
||
|
||
# 添加到场景管理器
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
self.scene_manager.models.append(cube)
|
||
|
||
# 更新场景树
|
||
if hasattr(self, 'updateSceneTree'):
|
||
self.updateSceneTree()
|
||
|
||
print("✓ 立方体创建成功")
|
||
return cube
|
||
except Exception as e:
|
||
print(f"✗ 创建立方体失败: {e}")
|
||
return None
|
||
|
||
def createSphere(self, pos=(0, 0, 0), radius=1.0):
|
||
"""创建球体"""
|
||
try:
|
||
from panda3d.core import NodePath
|
||
|
||
# 创建球体模型
|
||
sphere = self.loader.loadModel("models/environment")
|
||
if not sphere:
|
||
# 如果没有默认模型,创建一个简单的球体
|
||
from panda3d.core import CardMaker
|
||
card_maker = CardMaker("Sphere")
|
||
card_maker.setFrame(-radius, radius, -radius, radius)
|
||
sphere = NodePath(card_maker.generate())
|
||
|
||
sphere.reparentTo(self.render)
|
||
sphere.setPos(pos)
|
||
sphere.setScale(radius)
|
||
|
||
# 添加到场景管理器
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
self.scene_manager.models.append(sphere)
|
||
|
||
# 更新场景树
|
||
if hasattr(self, 'updateSceneTree'):
|
||
self.updateSceneTree()
|
||
|
||
print("✓ 球体创建成功")
|
||
return sphere
|
||
except Exception as e:
|
||
print(f"✗ 创建球体失败: {e}")
|
||
return None
|
||
|
||
def createCylinder(self, pos=(0, 0, 0), radius=1.0, height=2.0):
|
||
"""创建圆柱体"""
|
||
try:
|
||
from panda3d.core import NodePath
|
||
|
||
# 创建圆柱体模型
|
||
cylinder = self.loader.loadModel("models/environment")
|
||
if not cylinder:
|
||
# 如果没有默认模型,创建一个简单的圆柱体
|
||
from panda3d.core import CardMaker
|
||
card_maker = CardMaker("Cylinder")
|
||
card_maker.setFrame(-radius, radius, -height/2, height/2)
|
||
cylinder = NodePath(card_maker.generate())
|
||
|
||
cylinder.reparentTo(self.render)
|
||
cylinder.setPos(pos)
|
||
cylinder.setScale(radius, radius, height)
|
||
|
||
# 添加到场景管理器
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
self.scene_manager.models.append(cylinder)
|
||
|
||
# 更新场景树
|
||
if hasattr(self, 'updateSceneTree'):
|
||
self.updateSceneTree()
|
||
|
||
print("✓ 圆柱体创建成功")
|
||
return cylinder
|
||
except Exception as e:
|
||
print(f"✗ 创建圆柱体失败: {e}")
|
||
return None
|
||
|
||
def createPlane(self, pos=(0, 0, 0), size=(1, 1)):
|
||
"""创建平面"""
|
||
try:
|
||
from panda3d.core import CardMaker, NodePath
|
||
|
||
# 创建平面
|
||
card_maker = CardMaker("Plane")
|
||
card_maker.setFrame(-size[0]/2, size[0]/2, -size[1]/2, size[1]/2)
|
||
plane = NodePath(card_maker.generate())
|
||
|
||
plane.reparentTo(self.render)
|
||
plane.setPos(pos)
|
||
|
||
# 添加到场景管理器
|
||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
||
self.scene_manager.models.append(plane)
|
||
|
||
# 更新场景树
|
||
if hasattr(self, 'updateSceneTree'):
|
||
self.updateSceneTree()
|
||
|
||
print("✓ 平面创建成功")
|
||
return plane
|
||
except Exception as e:
|
||
print(f"✗ 创建平面失败: {e}")
|
||
return None
|
||
|
||
# 添加碰撞管理相关的代理方法
|
||
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):
|
||
print(f'Path is {args}')
|
||
print("引擎已启动(使用Panda3D原生窗口)")
|
||
|
||
# 创建世界实例并运行
|
||
world = MyWorld()
|
||
world.run()
|
||
|
||
if __name__ == "__main__":
|
||
run() |