对这个例程的介绍有点深意,说是通过碰撞检测机制来操作鼠标控制棋盘,但是又说Plane类可以更快的实现。不知道这个Plane类是啥,但是先研究下这个例程本身好了。
self.disableMouse()先说一下这个方法在之前每个例程里都有提到,之前觉得没什么,今天把这个注释掉后发现问题很大。
它的作用不是禁用鼠标,而是禁用默认的鼠标控制camera的功能。
1. 碰撞检测机制
from panda3d.core import CollisionHandlerQueue, CollisionRay
首先导入这两个包
Examples:
nodePath.setCollideMask(BitMask32(0x10))
This sets the into collide mask of nodePath, and all children of nodePath, to the value 0x10, regardless of the value each node had before.
nodePath.node().setFromCollideMask(BitMask32(0x10))
You can only set the from collide mask on a collision node, and you must set it directly on the node itself, not on the NodePath.
这两句的区别就在于一个是作为into对象,一个作为from对象。但看了例程之后 发现如果是into对象,是这样的语句:
self.squares[i].find("**/polygon").node().setIntoCollideMask(BitMask32.bit(1))
我觉得还是按例程来做即可了。
This control is provided with the collide masks. Every CollisionNode has two collide masks: a "from" mask, which is used when the CollisionNode is acting as a "from" object (i.e. it has been added to a CollisionTraverser), and an "into" mask, which is used when the node is acting as an "into" object (i.e. it is in the scene graph, and a from object is considering it for collisions).
这一段解释了两者的区别,大致是from主动,into被动。
碰撞掩码: 在碰撞节点的“from”中的实体与另一个CollisionNode或GeomNode进行碰撞测试之前,比较碰撞掩码。具体来说,from对象的“from”掩码和into对象的“into”掩码被“与”在一起。如果结果不为零 - 意味着两个掩码至少有一个相同的位 - 则尝试进行碰撞测试; 否则,这两个对象将被忽略。
nodePath.node().setFromCollideMask(BitMask32(0x10))
BitMask32指的就是32位的碰撞掩码(32个二进制位)
nodePath.setCollideMask(BitMask32(0x04), BitMask32(0xff))
This replaces the lower 8 bits of nodePath and all of its children with the value 0x04, leaving the upper 24 bits of each node unchanged.
这一段我是这么理解的,0x代表16进制,16进制的1位代表2进制4位,所以0x04共8个bit,也就是说最低位的8个bit被设置了,剩余的32-8=24个bit没有用到。
2. 棋盘布局
self.squares[i].find("**/polygon").node().setTag('square', str(i))
这一步用于保存棋盘标签
nearPoint = render.getRelativePoint(
camera, self.pickerRay.getOrigin())
# Same thing with the direction of the ray
nearVec = render.getRelativeVector(
camera, self.pickerRay.getDirection())
self.pieces[self.dragging].obj.setPos(
PointAtZ(.5, nearPoint, nearVec))
这里实在不知道这代码的运行原理,不过应该是用来模拟了棋子的运动。应该是通过点和方向确定了移动的线。
3. 整个碰撞检测过程:
self.picker = CollisionTraverser() 定义一个碰撞移动器,
self.pq = CollisionHandlerQueue() 建立一个handler
self.pickerNode = CollisionNode('mouseRay12')
# Attach that node to the camera since the ray will need to be positioned
# relative to it
self.pickerNP = camera.attachNewNode(self.pickerNode)
# Everything to be picked will use bit 1. This way if we were doing other
# collision we could separate it
self.pickerNode.setFromCollideMask(BitMask32.bit(1))
self.pickerRay = CollisionRay() # Make our ray
# Add it to the collision node
self.pickerNode.addSolid(self.pickerRay)
# Register the ray as something that can cause collisions
self.picker.addCollider(self.pickerNP, self.pq)
建立了一个collision node
self.picker.traverse(self.squareRoot)
使用traverse方法,只在squareRoot上检测碰撞(定义好的棋盘,可以就不用检测别的了)