1. 程式人生 > >ios 3D引擎 SceneKit 開發(7) --基礎的碰撞檢測

ios 3D引擎 SceneKit 開發(7) --基礎的碰撞檢測

好久沒有寫部落格了,變懶了,最近工作不多,那就繼續堅持寫部落格。
今天我們來說說SceneKit框架的 Basic Collision Detection,基礎碰撞檢測。

2D中的碰撞檢查大家都能能理解,涉及到的數學知識並不複雜。但在3D中碰撞檢測要涉及到更復雜的數學知識了,很多人數學功底不好的同學就犯難了,我也是。幸好SceneKit框架 提供了方便的方法去判斷碰撞檢測。

  1. 要想讓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所消耗的效能也小。

  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 版。