189 lines
6.9 KiB
Python
189 lines
6.9 KiB
Python
#!/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调试完成!") |