让学习成为一种习惯
首先确定一个问题: 是要用A去碰撞B 呢? 还是B 去碰撞A?
我用A去碰撞B 来讲解这个问题
能够实现物理碰撞的前提条件是什么?
两个物体都要有物理身体,我们知道游戏中物理身体有三种dynimic,static,kinematic
节点A 和节点B 都设置了物理身体(SCNPhysicsBody),那么如图所示,SCNPhysicsBody 有三个属性如下
解释一下前两个属性的作用
categoryBitMask (分类掩码)表示的物理身体的类别,如果是游戏的话,加入这个节点属于飞机 我们可以给飞机设置一个类别掩码 0b001 (最大值为15位)
collisionBitMask(碰撞掩码) 表示节点的物体身体允许被那些分类的物理身体碰撞 0b101
A 要去碰撞B, 如果要产生碰撞效果应该怎么设置呢?
ANode.physicsBody.categoryBitMask = 0b001;
BNode.physicsBody.collisionBitMask = 0b011; // b允许那些分类与自己碰撞
如果两个掩码进行按位与运算 结果为一个非零的数字 就会产生碰撞
如果是下面的设置将不会产生碰撞
ANode.physicsBody.categoryBitMask = 0b001;
BNode.physicsBody.collisionBitMask = 0b110;
提示:
注意千万不要将两者的顺序搞混了,有点绕
注意一个词语'接触检测'不是碰撞检测哦!就是说两个物体是否碰撞与能否检测到接触没有关系
先来看一个代理,这个代理是物理世界的一个属性
scnView.scene?.physicsWorld.contactDelegate = self
代理SCNPhysicsContactDelegate 有三个方法
// 开始接触
optional public func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact)
// 接触中
optional public func physicsWorld(_ world: SCNPhysicsWorld, didUpdate contact: SCNPhysicsContact)
// 接触结束
optional public func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact)
如果两个物体满足接触条件就会触发这个代理事件
怎么才能让其满足这个接触条件呢?
1.首先要设置物理身体(同上面一样)
如果要想A去接触B,并且要触发代理事件
ANode.physicsBody.categoryBitMask = 0b001;
BNode.physicsBody.contactTestBitMask = 0b101;// 允许分类掩码的对象和自己发生接触时触发回调函数
这样A 在受到力的时候,去接触B 就会去触发代理事件
第一步 创建工程(略)
运行结果如下
Scenekit_15.gif
为什么没碰撞呢?
sphereNode.physicsBody?.categoryBitMask = 1;
boxNode.physicsBody!.collisionBitMask = 0b010;
分析
1|0b10 = 0 所以不产生效果
如果改为下面的设置就会产生碰撞效果
sphereNode.physicsBody?.categoryBitMask = 0b10;
Scenekit_15.gif
设置正方体的允许那些物理身体接触自己发生代理事件
boxNode.physicsBody!.collisionBitMask = 0x01;
设置球体的属性掩码
sphereNode.physicsBody?.categoryBitMask=0x01;
命令行输出如下
'<SCNNode: 0x6080003c1a40 pos(0.000000 5.000000 -20.000000) | geometry=<SCNBox: 0x60800018ea00 | width=10.000 height=10.000 length=10.000 chamferRadius=0.000> | no child>' '<SCNNode: 0x6080003c1b30 pos(0.000000 20.000000 -20.000000) | geometry=<SCNSphere: 0x6000001448e0 | radius=1.000> | no child>' point(0.000000 9.949695 -20.000000) normal(0.000000 -1.000000 0.000000) impulse(0.000000) distance:0.050305>
属性如下
// 被碰撞的节点
open var nodeA: SCNNode { get }
// 主动碰撞的物体 这里指的是上面例子的球体
open var nodeB: SCNNode { get }
// 碰撞点的世界坐标
open var contactPoint: SCNVector3 { get }
// 碰撞点的法线
open var contactNormal: SCNVector3 { get }
// 碰撞的力度
open var collisionImpulse: CGFloat { get } // the collision impulse on nodeA
// 离世界坐标点的距离
open var penetrationDistance: CGFloat { get }
物理世界的碰撞检测就这些内容了