#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys from direct.showbase.ShowBase import ShowBase from panda3d.core import ( Point3, Point2, Vec3, CollisionTraverser, CollisionHandlerQueue, CollisionNode, CollisionRay, CollisionSphere, BitMask32, CardMaker ) class CollisionDebugTest(ShowBase): def __init__(self): ShowBase.__init__(self) # 设置相机位置 self.cam.setPos(-3.87655, -188.38084, 82.602684) self.cam.lookAt(0, 0, 0) print(f"相机位置: {self.cam.getPos()}") # 创建测试立方体 self.createTestCube() # 设置射线检测 self.setupRayPicking() # 调试碰撞系统 self.debugCollisionSystem() # 测试不同类型的碰撞体 self.testDifferentCollisionTypes() def createTestCube(self): """创建测试立方体""" cm = CardMaker("TestCube") cm.setFrame(-1, 1, -1, 1) self.cube = self.render.attachNewNode(cm.generate()) self.cube.setPos(0, 10, 3) self.cube.setScale(3, 3, 3) self.cube.setColor(1, 0, 0, 1) self.cube.setTwoSided(True) print(f"立方体世界位置: {self.cube.getPos(self.render)}") # 添加碰撞检测 cNode = CollisionNode('TestCubeCollision') cSphere = CollisionSphere(Point3(0, 0, 0), 4.0) cNode.addSolid(cSphere) cNode.setIntoCollideMask(BitMask32.bit(0)) cNode.setFromCollideMask(BitMask32.allOff()) self.cNodePath = self.cube.attachNewNode(cNode) # 强制显示碰撞体 self.cNodePath.show() print(f"碰撞体已强制显示") def setupRayPicking(self): """设置射线检测""" self.picker = CollisionTraverser() self.pickerQueue = CollisionHandlerQueue() self.pickerNode = CollisionNode('mouseRay') self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) # 设置掩码 fromMask = BitMask32.bit(0) self.pickerNode.setFromCollideMask(fromMask) self.pickerNode.setIntoCollideMask(BitMask32.allOff()) self.pickerNP = self.cam.attachNewNode(self.pickerNode) self.picker.addCollider(self.pickerNP, self.pickerQueue) print(f"射线检测器 From 掩码: {fromMask}") print(f"立方体 Into 掩码: {self.cNodePath.node().getIntoCollideMask()}") def debugCollisionSystem(self): """调试碰撞系统""" print(f"\n=== 碰撞系统调试 ===") # 检查碰撞遍历器 print(f"碰撞遍历器中的碰撞器数量: {self.picker.getNumColliders()}") for i in range(self.picker.getNumColliders()): collider = self.picker.getCollider(i) print(f" 碰撞器 {i}: {collider}") # 检查render下的所有碰撞节点 print(f"\nrender下的所有节点:") self.printNodeHierarchy(self.render, 0) def printNodeHierarchy(self, node, depth): """打印节点层次结构""" indent = " " * depth print(f"{indent}{node.getName()}: {type(node.node()).__name__}") if isinstance(node.node(), CollisionNode): cnode = node.node() print(f"{indent} CollisionNode:") print(f"{indent} IntoMask: {cnode.getIntoCollideMask()}") print(f"{indent} FromMask: {cnode.getFromCollideMask()}") print(f"{indent} Solids: {cnode.getNumSolids()}") for i in range(cnode.getNumSolids()): solid = cnode.getSolid(i) print(f"{indent} Solid {i}: {type(solid).__name__}") # 递归处理子节点,但限制深度 if depth < 3: for child in node.getChildren(): self.printNodeHierarchy(child, depth + 1) def testDifferentCollisionTypes(self): """测试不同类型的碰撞体""" print(f"\n=== 测试不同碰撞体类型 ===") camera_pos = self.cam.getPos(self.render) cube_pos = self.cube.getPos(self.render) # 计算直接射线 direct_direction = cube_pos - camera_pos direct_direction.normalize() print(f"使用直接射线: 起点={camera_pos}, 方向={direct_direction}") # 测试1: 当前设置 print(f"\n1. 测试当前碰撞球体设置:") self.testRayHit(camera_pos, direct_direction) # 测试2: 更大的碰撞球体 print(f"\n2. 测试更大的碰撞球体:") # 移除当前碰撞体 self.cNodePath.removeNode() # 创建更大的碰撞球体 cNode2 = CollisionNode('LargeSphere') cSphere2 = CollisionSphere(Point3(0, 0, 0), 20.0) # 更大的半径 cNode2.addSolid(cSphere2) cNode2.setIntoCollideMask(BitMask32.bit(0)) cNode2.setFromCollideMask(BitMask32.allOff()) self.cNodePath2 = self.cube.attachNewNode(cNode2) self.cNodePath2.show() self.testRayHit(camera_pos, direct_direction) # 测试3: 在render根下创建独立碰撞体 print(f"\n3. 测试独立碰撞体:") cNode3 = CollisionNode('IndependentSphere') cSphere3 = CollisionSphere(cube_pos, 15.0) # 直接使用世界坐标 cNode3.addSolid(cSphere3) cNode3.setIntoCollideMask(BitMask32.bit(0)) cNode3.setFromCollideMask(BitMask32.allOff()) self.cNodePath3 = self.render.attachNewNode(cNode3) self.cNodePath3.show() self.testRayHit(camera_pos, direct_direction) def testRayHit(self, origin, direction): """测试射线碰撞""" # 设置射线 self.pickerRay.setOrigin(origin) self.pickerRay.setDirection(direction) # 清除之前的结果 self.pickerQueue.clearEntries() # 执行碰撞检测 self.picker.traverse(self.render) numEntries = self.pickerQueue.getNumEntries() print(f" 检测到 {numEntries} 个碰撞") if numEntries > 0: self.pickerQueue.sortEntries() for i in range(numEntries): entry = self.pickerQueue.getEntry(i) hitPos = entry.getSurfacePoint(self.render) hitNode = entry.getIntoNodePath() distance = (hitPos - origin).length() print(f" 碰撞 {i}: {hitNode.getName()}, 距离: {distance:.2f}, 位置: {hitPos}") else: print(f" 没有检测到碰撞") if __name__ == "__main__": app = CollisionDebugTest() print("\n调试完成!")