基本理论
2D中的碰撞检查大家都能能理解,涉及到的数学知识并不复杂。但在3D中碰撞检测要涉及到更复杂的数学知识了,很多人数学功底不好的同学就犯难了,我也是。幸好SceneKit框架 提供了方便的方法去判断碰撞检测。
要想让SCNNode 模拟碰撞检测,首先要设置它的Physics Body,Physics Body有三种类型:
(1)Dynamic:动态的物体,受力的影响(applyForce)。
(2)Static: 静态的物体,不受力的影响。
(3)Kinemat:这种类型比较特殊,你可以直接移动,旋转它,在空间变换中,会对Dynamic的物体产生力的影响。
其次需要设置categoryBitMask,来表示物体的特质,比如下面我们定义了一个bottom和cube,这样碰撞的时候,我们可以通过这个mask来判断碰撞node的类型。
typedef NS_OPTIONS(NSUInteger, CollisionCategory) {
CollisionCategoryBottom = 1 << 0,
CollisionCategoryCube = 1 << 1,
};
Kinemat物体
SCNNode *bottomNode = [SCNNode nodeWithGeometry:bottomPlane];
bottomNode.physicsBody = [SCNPhysicsBody
bodyWithType:SCNPhysicsBodyTypeKinematic
shape: nil];
bottomNode.physicsBody.categoryBitMask = CollisionCategoryBottom;
这里设置了一个Kinemat物体,可以吸引其他物体,该物体的标示为CollisionCategoryBottom.
Dynamic物体
node.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeDynamic shape:nil];
node.physicsBody.mass = 2.0;
node.physicsBody.categoryBitMask = CollisionCategoryCube;
这里设置了一个Dynamic物体,mass为其重量,会影响其动能,该物体的标示为CollisionCategoryCube.
设置碰撞delegate
@protocol SCNPhysicsContactDelegate <NSObject>
@optional
- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact;
- (void)physicsWorld:(SCNPhysicsWorld *)world didUpdateContact:(SCNPhysicsContact *)contact;
- (void)physicsWorld:(SCNPhysicsWorld *)world didEndContact:(SCNPhysicsContact *)contact;
@end
self.sceneView.scene.physicsWorld.contactDelegate = self;
一共3个碰撞函数,碰撞开始前,碰撞开始中,碰撞开始后。
- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact {
if (contact.nodeA.physicsBody.categoryBitMask == CollisionCategoryBottom) {
//对bottom的SCNNode做处理
} else {
//对cube的SCNNode做处理
}
}
碰撞中,返回碰撞的nodeA|nodeB,可以通过categoryBitMask来判断是SCNNode的类型。
具体参看demo