#!/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()