#!/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调试完成！") 