EG/demo/selection_test.py
2025-07-10 09:19:51 +08:00

249 lines
7.8 KiB
Python
Raw Permalink 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.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
选择功能测试 - 验证模型选择功能是否正常工作
测试内容:
1. 验证模型碰撞检测设置
2. 测试射线检测和选择功能
3. 验证选择框和坐标轴显示
控制说明:
- 鼠标左键:点击选择模型
- I键显示当前选择信息
- C键显示碰撞检测信息
- S键切换碰撞体显示调试用
- R键切换射线显示
- Q键退出
"""
import sys
import os
sys.path.append('..') # 添加父目录到路径
from direct.showbase.ShowBase import ShowBase
from panda3d.core import (CardMaker, Vec3, Point3, Material,
ModelRoot, PandaNode, CollisionNode, CollisionSphere,
BitMask32)
from PyQt5.QtWidgets import QApplication
def create_test_models(world):
"""创建测试模型"""
print("\n=== 创建测试模型 ===")
# 创建几个简单的测试模型
test_models = []
positions = [
(0, 0, 1), # 中心
(5, 0, 1), # 右侧
(-5, 0, 1), # 左侧
(0, 5, 1), # 后方
]
colors = [
(1, 0, 0, 1), # 红色
(0, 1, 0, 1), # 绿色
(0, 0, 1, 1), # 蓝色
(1, 1, 0, 1), # 黄色
]
for i, (pos, color) in enumerate(zip(positions, colors)):
# 创建立方体
cm = CardMaker(f'test_cube_{i}')
cm.setFrame(-1, 1, -1, 1)
# 创建模型根节点
model_root = world.render.attachNewNode(ModelRoot(f"TestCube_{i}"))
# 创建6个面简单立方体
faces = [
# 前面和后面
(0, 0, 1, 0, 0, 1), # 前面 Z+
(0, 0, -1, 0, 0, -1), # 后面 Z-
# 左面和右面
(-1, 0, 0, 1, 0, 0), # 左面 X-
(1, 0, 0, -1, 0, 0), # 右面 X+
# 顶面和底面
(0, 1, 0, 0, -1, 0), # 顶面 Y+
(0, -1, 0, 0, 1, 0), # 底面 Y-
]
for j, (x, y, z, nx, ny, nz) in enumerate(faces):
face = model_root.attachNewNode(cm.generate())
face.setPos(x, y, z)
if nx != 0: # X面
face.setH(90 if nx > 0 else -90)
elif ny != 0: # Y面
face.setP(90 if ny > 0 else -90)
# Z面保持默认朝向
# 设置位置和颜色
model_root.setPos(*pos)
model_root.setColor(*color)
# 创建材质
material = Material()
material.setDiffuse(color)
material.setAmbient((0.2, 0.2, 0.2, 1.0))
material.setSpecular((0.5, 0.5, 0.5, 1.0))
material.setShininess(32.0)
model_root.setMaterial(material)
# 设置标签
model_root.setTag("file", f"TestCube_{i}")
model_root.setTag("is_model_root", "1")
# 添加到场景管理器
world.scene_manager.models.append(model_root)
test_models.append(model_root)
print(f"✓ 创建测试立方体 {i}: 位置{pos}, 颜色{color[:3]}")
# 为所有模型设置碰撞检测
print("\n=== 设置碰撞检测 ===")
for model in test_models:
world.scene_manager.setupCollision(model)
print(f"✓ 为 {model.getName()} 设置碰撞检测")
# 更新场景树
world.scene_manager.updateSceneTree()
print("✓ 测试模型创建完成")
return test_models
def show_collision_info(world):
"""显示碰撞检测信息"""
print("\n=== 碰撞检测信息 ===")
for i, model in enumerate(world.scene_manager.models):
print(f"\n模型 {i+1}: {model.getName()}")
print(f"位置: {model.getPos()}")
print(f"边界: {model.getBounds()}")
# 查找碰撞节点
collision_nodes = []
for child in model.getChildren():
if isinstance(child.node(), CollisionNode):
collision_nodes.append(child)
if collision_nodes:
print(f"碰撞节点数量: {len(collision_nodes)}")
for j, cnode in enumerate(collision_nodes):
cn = cnode.node()
print(f" 碰撞节点 {j+1}: {cn.getName()}")
print(f" 碰撞掩码: {cn.getIntoCollideMask()}")
print(f" 碰撞体数量: {cn.getNumSolids()}")
for k in range(cn.getNumSolids()):
solid = cn.getSolid(k)
print(f" 碰撞体 {k+1}: {solid.__class__.__name__}")
else:
print("❌ 没有碰撞节点")
print("==================")
def show_selection_info(world):
"""显示当前选择信息"""
print("\n=== 当前选择信息 ===")
selected = world.selection.getSelectedNode()
if selected:
print(f"选中节点: {selected.getName()}")
print(f"位置: {selected.getPos()}")
print(f"缩放: {selected.getScale()}")
print(f"有选择框: {bool(world.selection.selectionBox)}")
print(f"有坐标轴: {bool(world.selection.gizmo)}")
else:
print("当前没有选中任何节点")
print(f"当前工具: {world.currentTool}")
print("=================")
def toggle_collision_display(world):
"""切换碰撞体显示"""
print("\n=== 切换碰撞体显示 ===")
count = 0
for model in world.scene_manager.models:
for child in model.getChildren():
if isinstance(child.node(), CollisionNode):
if child.isHidden():
child.show()
count += 1
else:
child.hide()
if count > 0:
print(f"显示了 {count} 个碰撞体")
else:
print("隐藏了所有碰撞体")
class SelectionTest(ShowBase):
def __init__(self):
ShowBase.__init__(self)
# 导入我们的模块
from main import MyWorld
# 创建世界实例
self.world = MyWorld()
# 设置相机
self.cam.setPos(0, -20, 10)
self.cam.lookAt(0, 0, 0)
# 创建测试模型
self.test_models = create_test_models(self.world)
# 设置键盘事件
self.setupKeyEvents()
print("\n=== 选择功能测试程序启动 ===")
print("控制说明:")
print("鼠标左键:点击选择模型")
print("I键显示当前选择信息")
print("C键显示碰撞检测信息")
print("S键切换碰撞体显示调试用")
print("R键切换射线显示")
print("Q键退出程序")
print("================================")
# 显示初始信息
show_collision_info(self.world)
def setupKeyEvents(self):
"""设置键盘事件"""
self.accept('i', self.showSelectionInfo)
self.accept('c', self.showCollisionInfo)
self.accept('s', self.toggleCollisionDisplay)
self.accept('r', self.toggleRayDisplay)
self.accept('q', self.quit)
self.accept('escape', self.quit)
def showSelectionInfo(self):
"""显示选择信息"""
show_selection_info(self.world)
def showCollisionInfo(self):
"""显示碰撞信息"""
show_collision_info(self.world)
def toggleCollisionDisplay(self):
"""切换碰撞体显示"""
toggle_collision_display(self.world)
def toggleRayDisplay(self):
"""切换射线显示"""
self.world.toggleRayDisplay()
print(f"射线显示: {'开启' if self.world.getRayDisplay() else '关闭'}")
def quit(self):
"""退出程序"""
print("\n退出选择功能测试程序")
sys.exit()
if __name__ == "__main__":
app = QApplication(sys.argv)
test = SelectionTest()
test.run()