EG/demo.py
2026-01-08 16:30:59 +08:00

680 lines
27 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from panda3d.core import loadPrcFileData, WindowProperties, Point3
from math import pi, sin, cos
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import Sequence
import p3dimgui
from imgui_bundle import imgui, imgui_ctx
import sys
import warnings
# 导入MyWorld类和必要的模块
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 core.InfoPanelManager import InfoPanelManager
from core.collision_manager import CollisionManager
try:
# 尝试导入视频管理器,避免循环导入
import importlib.util
spec = importlib.util.spec_from_file_location("video_integration", "demo/video_integration.py")
video_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(video_module)
VideoManager = video_module.VideoManager
except:
# 如果video_integration模块不存在则跳过
VideoManager = None
print("⚠ 视频管理器模块未找到,视频功能将不可用")
warnings.filterwarnings("ignore", category=DeprecationWarning)
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)
# 初始化视频管理
if VideoManager is not None:
self.video_manager = VideoManager(self)
else:
self.video_manager = None
# 初始化场景管理系统
self.scene_manager = SceneManager(self)
# 初始化项目管理系统
self.project_manager = ProjectManager(self)
self.info_panel_manager = InfoPanelManager(self)
self.command_manager = CommandManager()
# 初始化碰撞管理器
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)
# 启动脚本系统
self.script_manager.start_system()
self.terrain_manager = TerrainManager(self)
self.terrain_edit_radius = 3.0
self.terrain_edit_strength=0.3
self.terrain_edit_operation = "add"
# Install Dear ImGui
p3dimgui.init()
# 初始化样式管理器
from core.imgui_style_manager import ImGuiStyleManager
self.style_manager = ImGuiStyleManager(self.imgui)
# 尝试直接设置中文字体
try:
import platform
from pathlib import Path
# 获取中文字体路径
system = platform.system().lower()
if system == "linux":
font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
elif system == "windows":
font_path = "C:/Windows/Fonts/msyh.ttc"
elif system == "darwin":
font_path = "/System/Library/Fonts/PingFang.ttc"
else:
font_path = None
if font_path and Path(font_path).exists():
# 先清除默认字体
self.imgui.io.fonts.clear()
# 创建中文字符范围(基本中文字符)
# 这个范围包含了常用中文字符的Unicode范围
chinese_ranges = []
# 基本拉丁字母
for i in range(0x0020, 0x00FF):
chinese_ranges.append(i)
# 中文字符范围
for i in range(0x4E00, 0x9FFF): # CJK统一汉字
chinese_ranges.append(i)
for i in range(0x3400, 0x4DBF): # CJK扩展A
chinese_ranges.append(i)
for i in range(0x20000, 0x2A6DF): # CJK扩展B
chinese_ranges.append(i)
for i in range(0x2A700, 0x2B73F): # CJK扩展C
chinese_ranges.append(i)
for i in range(0x2B740, 0x2B81F): # CJK扩展D
chinese_ranges.append(i)
for i in range(0x2B820, 0x2CEAF): # CJK扩展E
chinese_ranges.append(i)
for i in range(0x2CEB0, 0x2EBEF): # CJK扩展F
chinese_ranges.append(i)
for i in range(0x3000, 0x303F): # CJK符号和标点
chinese_ranges.append(i)
for i in range(0xFF00, 0xFFEF): # 全角字符
chinese_ranges.append(i)
# 添加中文字体不指定字符范围让ImGui自动处理
font = self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
print(f"✓ 直接设置中文字体成功: {font_path}")
print(f" 使用自动字符范围")
else:
print("⚠ 中文字体文件不存在")
except Exception as e:
print(f"⚠ 直接设置中文字体失败: {e}")
# 备用方案:使用默认字体
try:
self.imgui.io.fonts.add_font_default()
print("✓ 使用默认字体")
except:
pass
# Disable the camera trackball controls.
self.disableMouse()
self.showDemoWindow = True
# UI状态管理
self.showSceneTree = True
self.showPropertyPanel = True
self.showConsole = True
self.showScriptPanel = True
self.showToolbar = True
self.accept('imgui-new-frame', self.__newFrame)
self.accept('`', self.__toggleImgui)
self.testTexture = None
self.icons = {} # 初始化图标字典
print("✓ MyWorld 初始化完成")
# ==================== 兼容性属性 ====================
# 保留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
# 保留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
# 保留terrains属性以兼容现有代码
@property
def terrains(self):
"""地形列表的兼容性属性"""
return self.terrain_manager.terrains
@terrains.setter
def terrains(self,value):
"""地形列表的兼容性设置器"""
self.terrain_manager.terrains = value
def onFocusKeyPressed(self):
"""处理 F 键按下事件"""
try:
if hasattr(self, 'selection') and self.selection.selectedNode:
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()
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)
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 enableModelCollisionDetection(self, enable=True, frequency=0.1, threshold=0.5):
"""启用模型间碰撞检测"""
return self.collision_manager.enableModelCollisionDetection(enable, frequency, threshold)
def __toggleImgui(self):
if not self.imgui.isKeyboardCaptured():
self.imgui.toggle()
def __newFrame(self):
# Dear ImGui commands can be placed here.
# 在第一帧应用样式
if imgui.get_frame_count() == 0:
self.style_manager.apply_style()
# 加载图标
self.icons = {
'select': self.style_manager.load_icon('select_tool'),
'move': self.style_manager.load_icon('move_tool'),
'rotate': self.style_manager.load_icon('rotate_tool'),
'scale': self.style_manager.load_icon('scale_tool'),
'success': self.style_manager.load_icon('success_icon'),
'warning': self.style_manager.load_icon('warning_icon'),
}
# 确保中文字体被正确应用
try:
# 强制刷新字体
self.imgui.io.fonts.clear()
# 重新添加中文字体
import platform
from pathlib import Path
system = platform.system().lower()
if system == "linux":
font_path = "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
elif system == "windows":
font_path = "C:/Windows/Fonts/msyh.ttc"
elif system == "darwin":
font_path = "/System/Library/Fonts/PingFang.ttc"
if font_path and Path(font_path).exists():
# 添加中文字体,明确指定中文字符集
try:
# 获取中文字符集
chinese_ranges = imgui.get_io().fonts.get_glyph_ranges_chinese_full()
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0, None, chinese_ranges)
print("✓ 第一帧重新设置中文字体(包含中文字符集)")
except:
# 如果获取字符集失败,使用简单方式
self.imgui.io.fonts.add_font_from_file_ttf(font_path, 14.0)
print("✓ 第一帧重新设置中文字体(简单方式)")
except Exception as e:
print(f"⚠ 第一帧设置中文字体失败: {e}")
# 绘制菜单栏
self._draw_menu_bar()
# 绘制工具栏
if self.showToolbar:
self._draw_toolbar()
# 绘制场景树面板
if self.showSceneTree:
self._draw_scene_tree()
# 绘制属性面板
if self.showPropertyPanel:
self._draw_property_panel()
# 绘制控制台面板
if self.showConsole:
self._draw_console()
# 绘制脚本面板
if self.showScriptPanel:
self._draw_script_panel()
# 绘制纹理测试窗口
if self.testTexture:
with self.style_manager.begin_styled_window("Texture Test", True,
imgui.WINDOW_ALWAYS_AUTO_RESIZE) as (_, windowOpen):
if not windowOpen:
self.imgui.removeTexture(self.testTexture)
self.testTexture = None
return
imgui.image(self.testTexture, (256, 256))
# 绘制ImGui演示窗口
if self.showDemoWindow:
imgui.show_demo_window()
def _draw_menu_bar(self):
"""绘制菜单栏"""
with imgui_ctx.begin_main_menu_bar() as main_menu:
if main_menu:
# 文件菜单
with imgui_ctx.begin_menu("文件") as file_menu:
if file_menu:
imgui.menu_item("新建项目", "Ctrl+N", False, True)
imgui.menu_item("打开项目", "Ctrl+O", False, True)
imgui.separator()
imgui.menu_item("保存", "Ctrl+S", False, True)
imgui.menu_item("另存为", "", False, True)
imgui.separator()
imgui.menu_item("退出", "Alt+F4", False, True)
# 编辑菜单
with imgui_ctx.begin_menu("编辑") as edit_menu:
if edit_menu:
imgui.menu_item("撤销", "Ctrl+Z", False, True)
imgui.menu_item("重做", "Ctrl+Y", False, True)
imgui.separator()
imgui.menu_item("复制", "Ctrl+C", False, True)
imgui.menu_item("粘贴", "Ctrl+V", False, True)
imgui.menu_item("删除", "Del", False, True)
# 视图菜单
with imgui_ctx.begin_menu("视图") as view_menu:
if view_menu:
_, self.showToolbar = imgui.menu_item("工具栏", "", self.showToolbar, True)
_, self.showSceneTree = imgui.menu_item("场景树", "", self.showSceneTree, True)
_, self.showPropertyPanel = imgui.menu_item("属性面板", "", self.showPropertyPanel, True)
_, self.showConsole = imgui.menu_item("控制台", "", self.showConsole, True)
_, self.showScriptPanel = imgui.menu_item("脚本管理", "", self.showScriptPanel, True)
# 工具菜单
with imgui_ctx.begin_menu("工具") as tools_menu:
if tools_menu:
imgui.menu_item("导入模型", "", False, True)
imgui.menu_item("地形编辑器", "", False, True)
imgui.menu_item("材质编辑器", "", False, True)
imgui.menu_item("脚本编辑器", "", False, True)
# 窗口菜单
with imgui_ctx.begin_menu("窗口") as window_menu:
if window_menu:
_, self.showDemoWindow = imgui.menu_item("ImGui演示", "", self.showDemoWindow, True)
if self.testTexture:
imgui.menu_item("关闭纹理测试", "", False, True)
else:
imgui.menu_item("显示纹理测试", "", False, True)
# 帮助菜单
with imgui_ctx.begin_menu("帮助") as help_menu:
if help_menu:
imgui.menu_item("关于", "", False, True)
imgui.menu_item("文档", "", False, True)
# 右侧显示FPS
imgui.set_cursor_pos_x(imgui.get_window_size().x - 140)
imgui.text("%.2f FPS (%.2f ms)" % (imgui.get_io().framerate, 1000.0 / imgui.get_io().framerate))
def _draw_toolbar(self):
"""绘制工具栏"""
# 设置工具栏位置
imgui.set_next_window_pos((10, 30), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((300, 40), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("工具栏", self.showToolbar,
self.style_manager.get_window_flags("toolbar")):
self.showToolbar = True # 确保窗口保持打开
# 工具按钮组
if self.icons.get('select'):
if self.style_manager.image_button(self.icons['select'], (24, 24)):
print("选择工具")
if imgui.is_item_hovered():
imgui.set_tooltip("选择工具 (Q)")
imgui.same_line()
else:
if imgui.button("选择"):
print("选择工具")
imgui.same_line()
if self.icons.get('move'):
if self.style_manager.image_button(self.icons['move'], (24, 24)):
print("移动工具")
if imgui.is_item_hovered():
imgui.set_tooltip("移动工具 (W)")
imgui.same_line()
else:
if imgui.button("移动"):
print("移动工具")
imgui.same_line()
if self.icons.get('rotate'):
if self.style_manager.image_button(self.icons['rotate'], (24, 24)):
print("旋转工具")
if imgui.is_item_hovered():
imgui.set_tooltip("旋转工具 (E)")
imgui.same_line()
else:
if imgui.button("旋转"):
print("旋转工具")
imgui.same_line()
if self.icons.get('scale'):
if self.style_manager.image_button(self.icons['scale'], (24, 24)):
print("缩放工具")
if imgui.is_item_hovered():
imgui.set_tooltip("缩放工具 (R)")
else:
if imgui.button("缩放"):
print("缩放工具")
imgui.same_line()
imgui.separator()
imgui.same_line()
# 其他工具按钮
if imgui.button("导入"):
print("导入模型")
imgui.same_line()
if imgui.button("保存"):
print("保存场景")
imgui.same_line()
if imgui.button("播放"):
print("播放动画")
def _draw_scene_tree(self):
"""绘制场景树面板"""
# 设置场景树位置
imgui.set_next_window_pos((10, 80), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("场景树", self.showSceneTree,
self.style_manager.get_window_flags("panel")):
self.showSceneTree = True # 确保窗口保持打开
imgui.text("场景层级")
imgui.separator()
# 模拟场景树结构
if imgui.tree_node("渲染"):
if imgui.tree_node("环境光"):
imgui.text("环境光 #1")
imgui.tree_pop()
if imgui.tree_node("定向光"):
imgui.text("定向光 #1")
imgui.tree_pop()
if imgui.tree_node("地板"):
imgui.text("地板节点")
imgui.tree_pop()
imgui.tree_pop()
if imgui.tree_node("相机"):
imgui.text("主相机")
imgui.tree_pop()
if imgui.tree_node("模型"):
imgui.text("(空)")
imgui.tree_pop()
def _draw_property_panel(self):
"""绘制属性面板"""
# 设置属性面板位置
imgui.set_next_window_pos((270, 80), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("属性面板", self.showPropertyPanel,
self.style_manager.get_window_flags("panel")):
self.showPropertyPanel = True # 确保窗口保持打开
imgui.text("对象属性")
imgui.separator()
# 模拟属性设置
changed, pos_x = imgui.drag_float("位置 X", 0.0, 0.1)
changed, pos_y = imgui.drag_float("位置 Y", 0.0, 0.1)
changed, pos_z = imgui.drag_float("位置 Z", 0.0, 0.1)
imgui.separator()
changed, rot_x = imgui.drag_float("旋转 X", 0.0, 1.0)
changed, rot_y = imgui.drag_float("旋转 Y", 0.0, 1.0)
changed, rot_z = imgui.drag_float("旋转 Z", 0.0, 1.0)
imgui.separator()
changed, scale = imgui.drag_float("缩放", 1.0, 0.1)
imgui.separator()
if imgui.button("重置变换"):
print("重置变换")
def _draw_console(self):
"""绘制控制台面板"""
# 设置控制台位置
imgui.set_next_window_pos((10, 390), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((770, 150), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("控制台", self.showConsole,
self.style_manager.get_window_flags("panel")):
self.showConsole = True # 确保窗口保持打开
imgui.text("控制台输出")
imgui.separator()
# 模拟控制台输出
if self.icons.get('success'):
imgui.image(self.icons['success'], (12, 12))
imgui.same_line()
imgui.text_colored((0.176, 1.0, 0.769, 1.0), "[INFO]") # 成功颜色
imgui.same_line()
imgui.text("引擎初始化完成")
imgui.text_colored((0.157, 0.620, 1.0, 1.0), "[INFO]") # 信息颜色
imgui.same_line()
imgui.text("渲染管线已加载")
if self.icons.get('warning'):
imgui.image(self.icons['warning'], (12, 12))
imgui.same_line()
imgui.text_colored((0.953, 0.616, 0.471, 1.0), "[WARN]") # 警告颜色
imgui.same_line()
imgui.text("视频管理器模块未找到")
if self.icons.get('success'):
imgui.image(self.icons['success'], (12, 12))
imgui.same_line()
imgui.text_colored((0.176, 1.0, 0.769, 1.0), "[INFO]") # 成功颜色
imgui.same_line()
imgui.text("VR管理器初始化完成")
# 输入框
imgui.separator()
changed, command = imgui.input_text(">", "", 256)
if changed and command:
print(f"执行命令: {command}")
def _draw_script_panel(self):
"""绘制脚本管理面板"""
# 设置脚本面板位置
imgui.set_next_window_pos((530, 80), imgui.Cond_.first_use_ever.value)
imgui.set_next_window_size((250, 300), imgui.Cond_.first_use_ever.value)
with self.style_manager.begin_styled_window("脚本管理", self.showScriptPanel,
self.style_manager.get_window_flags("panel")):
self.showScriptPanel = True # 确保窗口保持打开
imgui.text("脚本列表")
imgui.separator()
# 模拟脚本列表
selected, _ = imgui.selectable("main.py", False)
if selected:
print("选择脚本: main.py")
selected, _ = imgui.selectable("player_controller.py", False)
if selected:
print("选择脚本: player_controller.py")
selected, _ = imgui.selectable("ui_manager.py", False)
if selected:
print("选择脚本: ui_manager.py")
imgui.separator()
# 脚本操作按钮
if imgui.button("新建脚本"):
print("新建脚本")
imgui.same_line()
if imgui.button("编辑"):
print("编辑脚本")
imgui.same_line()
if imgui.button("重载"):
print("重载脚本")
imgui.separator()
imgui.text("脚本输出:")
imgui.text("脚本引擎已启动")
imgui.text("热重载监控已启动")
demo = MyWorld()
demo.run()