如何使用Swift处理Scenekit中的碰撞检测?

时间:2016-03-22 19:05:11

标签: swift collision detection scenekit

我一直在尝试使用一些物理设置一个简单的Scenekit场景,这样我就可以了解SCNPhysicsContactDelegate,categoryBitMask,collisionBitMask和physicsWorld func是如何工作的。不确定我是否还需要设置contactTestBitMask。

了解接触检测让我了解了逐位运算符的长路径以及位屏蔽的概念。添加二进制文件很有趣!然而,这仍然非常模糊,我正在尝试拼凑我在SpriteKit和SceneKit中找到的几个教程。 This is the most comprehensive但它在Obj-C中,我不明白如何翻译成Swift。

这是我创造的。任何见解都将非常感激。你能看到我设置错误吗?当红色滚球击中蓝色目标时,我想要一个简单的Print语句。地板,坡道和目标是.static,而滚球是.dynamic。

Animated Gif of Scene

import UIKit
import SceneKit


class ViewController: UIViewController, SCNPhysicsContactDelegate {
    //category bit masks for ball node and target node
    // ball = 0001 -> 1 and target = 0010 ->2
    let collisionRollingBall: Int = 1 << 0
    let collsionTarget: Int = 1 << 1

//declare variables
var sceneView: SCNView!
var cameraNode: SCNNode!
var groundNode: SCNNode!
var lightNode: SCNNode!
var rampNode: SCNNode!
var rollingBallNode: SCNNode!
var targetNode: SCNNode!

override func viewDidLoad() {
    super.viewDidLoad()
    //set up sceneview and scene. Define the physicsworld contact delegate as self
    sceneView = SCNView(frame: self.view.frame)
    sceneView.scene = SCNScene()
    sceneView.scene!.physicsWorld.contactDelegate = self
    self.view.addSubview(sceneView)

    //add floor
    let groundGeometry = SCNFloor()
    groundGeometry.reflectivity = 0
    let groundMaterial = SCNMaterial()
    groundMaterial.diffuse.contents = UIColor.greenColor()
    groundGeometry.materials = [groundMaterial]
    groundNode = SCNNode(geometry: groundGeometry)

    //add ramp
    let rampGeometry = SCNBox(width: 4, height: 1, length: 18, chamferRadius: 0)
    rampNode = SCNNode(geometry: rampGeometry)
    rampNode.position = SCNVector3(x: 0, y: 2.0, z: 1.0)
    rampNode.rotation = SCNVector4(1, 0, 0, 0.26)

    //add rolling ball
    let rollingBallGeometry = SCNSphere(radius: 0.5)
    let sphereMaterial = SCNMaterial()
    sphereMaterial.diffuse.contents = UIColor.redColor()
    rollingBallGeometry.materials = [sphereMaterial]
    rollingBallNode = SCNNode(geometry: rollingBallGeometry)
    rollingBallNode.position = SCNVector3(0, 6, -6)

    //add target box
    let targetBoxGeometry = SCNBox(width: 4, height: 1, length: 4, chamferRadius: 0)
    let targetMaterial = SCNMaterial()
    targetMaterial.diffuse.contents = UIColor.blueColor()
    targetBoxGeometry.materials = [targetMaterial]
    targetNode = SCNNode(geometry: targetBoxGeometry)
    targetNode.position = SCNVector3(x: 0, y: 0.5, z: 11.5)
    targetNode.rotation = SCNVector4(-1,0,0,0.592)

    //add a camera
    let camera = SCNCamera()
    self.cameraNode = SCNNode()
    self.cameraNode.camera = camera
    self.cameraNode.position = SCNVector3(x: 13, y: 5, z: 12)
    let constraint = SCNLookAtConstraint(target: rampNode)
    self.cameraNode.constraints = [constraint]
    constraint.gimbalLockEnabled = true

    //add a light
    let spotLight = SCNLight()
    spotLight.type = SCNLightTypeSpot
    spotLight.castsShadow = true
    spotLight.spotInnerAngle = 70.0
    spotLight.spotOuterAngle = 90.0
    spotLight.zFar = 500
    lightNode = SCNNode()
    lightNode.light = spotLight
    lightNode.position = SCNVector3(x: 0, y: 25, z: 25)
    lightNode.constraints = [constraint]

    //define physcis bodies
    let groundShape = SCNPhysicsShape(geometry: groundGeometry, options: nil)
    let groundBody = SCNPhysicsBody(type: .Static, shape: groundShape)
    groundNode.physicsBody = groundBody

    let rampShape = SCNPhysicsShape(geometry: rampGeometry, options: nil)
    let rampBody = SCNPhysicsBody(type: .Static, shape: rampShape)
    rampNode.physicsBody = rampBody

    let sphereShape = SCNPhysicsShape(geometry: rollingBallGeometry, options: nil)
    let sphereBody = SCNPhysicsBody(type: .Dynamic, shape: sphereShape)
    rollingBallNode.physicsBody?.categoryBitMask = collisionRollingBall
    rollingBallNode.physicsBody?.collisionBitMask = collsionTarget
    rollingBallNode.physicsBody = sphereBody

    let targetShape = SCNPhysicsShape(geometry: targetBoxGeometry, options: nil)
    let targetBody = SCNPhysicsBody(type: .Static, shape: targetShape)
    targetNode.physicsBody?.categoryBitMask = collsionTarget
    targetNode.physicsBody?.collisionBitMask = collisionRollingBall
    targetNode.physicsBody = targetBody

    //add nodes to view
    sceneView.scene?.rootNode.addChildNode(groundNode)
    sceneView.scene?.rootNode.addChildNode(rampNode)
    sceneView.scene?.rootNode.addChildNode(rollingBallNode)
    sceneView.scene?.rootNode.addChildNode(targetNode)
    sceneView.scene?.rootNode.addChildNode(self.cameraNode)
    sceneView.scene?.rootNode.addChildNode(lightNode)

}

func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {
print("contact")

 //   let contactMask = contact.nodeA.categoryBitMask | 
//contact.nodeB.categoryBitMask

    //if contactMask == collsionTarget | collisionRollingBall {
      //  print("The ball hit the target")
  //  }

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

1 个答案:

答案 0 :(得分:1)

我认为您必须重置&#34; catagoryBitMask&#34;委托函数中的值,因为您正在尝试设置&#34; catagoryBitMask&#34;和&#34; collisionBitMask&#34;在physicsBody仍为零时的值。

rollingBallNode.physicsBody?.categoryBitMask = collisionRollingBall
rollingBallNode.physicsBody?.collisionBitMask = collsionTarget
rollingBallNode.physicsBody = sphereBody

尝试将第3行放在第1位。