ios 3D引擎 SceneKit 開發(7) --基礎的碰撞檢測
好久沒有寫部落格了,變懶了,最近工作不多,那就繼續堅持寫部落格。
今天我們來說說SceneKit框架的 Basic Collision Detection,基礎碰撞檢測。
2D中的碰撞檢查大家都能能理解,涉及到的數學知識並不複雜。但在3D中碰撞檢測要涉及到更復雜的數學知識了,很多人數學功底不好的同學就犯難了,我也是。幸好SceneKit框架 提供了方便的方法去判斷碰撞檢測。
- 要想讓SCNNode 模擬碰撞檢測,首先要設定它的Physics Body,Physics Body有三種類型:
(1)Dynamic:動態的物體,受力的影響(applyForce)。
(2)Static: 靜態的物體,不受力的影響。
(3)Kinemat:這種型別比較特殊,你可以直接移動,旋轉它,在空間變換中,會對Dynamic的物體產生力的影響。
//示例1
rootWallNode.physicsBody = [SCNPhysicsBody dynamicBody];
//示例2
SCNPhysicsShape *shape = [SCNPhysicsShape shapeWithGeometry:[SCNBox boxWithWidth:5 height:5 length:5 chamferRadius:0] options:nil];
self.cameraNode.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeKinematic shape:shape];
我們來解釋一下上面的程式碼 示例1 建立一個dynamicBody,形狀與node 的一致。示例2 建立一個 正方體的形狀,意思就是大體包住node,對精度要求不高的可以使用示例2,示例2相對於示例1所消耗的效能也小。
當然SceneKit物理引擎為了提高效能,並不是所有設定Physics Body 的node都去檢測碰撞,你也只需要某兩個node碰撞的事件。所以你需要指定那幾個node碰撞時讓物理引擎告訴你。
比如說一個房間有一張椅子和一張桌子,你可以移動椅子,你想檢測椅子跟桌子,牆的碰撞。
我們首先需要給node 標記各自的身份:
//我們建立列舉,讓可讀性高一點
typedef enum : NSUInteger {
CollisionDetectionMaskChair = 1 ,
CollisionDetectionMaskDesk = 2,
CollisionDetectionMaskWall = 4
} CollisionDetectionMask;
self.chairNode.physicsBody.categoryBitMask = CollisionDetectionMaskChair;
self.deskNode.physicsBody.categoryBitMask = CollisionDetectionMaskDesk;
self.wallNode.physicsBody.categoryBitMask = CollisionDetectionMaskWall;
接下來我們告訴物理引擎當椅子與桌子,牆發生碰撞告訴我,設定如下:
self.chairNode.physicsBody.collisionBitMask = CollisionDetectionMaskDesk|CollisionDetectionMaskWall;
self.chairNode.physicsBody.contactTestBitMask = CollisionDetectionMaskDesk|CollisionDetectionMaskWall;
而桌子,牆 的碰撞物件都是椅子
self.deskNode.physicsBody.collisionBitMask = CollisionDetectionMaskChair;
self.deskNode.physicsBody.contactTestBitMask = CollisionDetectionMaskChair;
self.wallNode.physicsBody.collisionBitMask = CollisionDetectionMaskChair;
self.wallNode.physicsBody.contactTestBitMask = CollisionDetectionMaskChair;
3.接下來我們就要實現 SCNPhysicsContactDelegate 的代理方法
scene.physicsWorld.contactDelegate = self;
最主要的三個代理方法如下,從字面意思很好理解,就不一一介紹了
#pragma mark SCNPhysicsContactDelegate
- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact{
//開始碰撞
}
- (void)physicsWorld:(SCNPhysicsWorld *)world didUpdateContact:(SCNPhysicsContact *)contact{
//得到兩個碰撞的node
SCNNode *nodeA = contact.nodeA;
SCNNode *nodeB = contact.nodeB;
// SCNVector3 contactPoint = contact.contactPoint;
//碰撞點
if(nodeA.physicsBody.categoryBitMask == CollisionDetectionMaskChair) {
// 做一些事情
}
}
- (void)physicsWorld:(SCNPhysicsWorld *)world didEndContact:(SCNPhysicsContact *)contact{
//結束碰撞
}
OK,基礎的碰撞檢測就講這麼多了,這也是最簡單的,後面有機會我們再講中級碰撞檢測。後續有機會我會多發Demo出來,供大家參考。
一個有碰撞檢測的Demo: http://git.oschina.net/Roc.Tian/Blog_DEMO中的 BeerCanBully_Objective-C。
Beer Can Bully Final 為swift 版。