5
votes

I created two nodes: a sphere and a box:

    var sphere = SCNNode(geometry: SCNSphere(radius: 0.005))
    //I get the box node from scn file
    let boxScene = SCNScene(named: "art.scnassets/world.scn")!
    var boxNode: SCNNode?

I want two nodes or physicsBody's to interact, so I created a category for categoryBitMask and contactTestBitMask:

struct CollisionCategory: OptionSet {
    let rawValue: Int
    static let box = CollisionCategory(rawValue: 1)
    static let sphere = CollisionCategory(rawValue: 2)
} 

Here I set the box node as a physics body:

self.boxScene.rootNode.enumerateChildNodes { (node, _) in
    if node.name == "box" {
        boxNode = node
        let boxBodyShape = SCNPhysicsShape(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0.1), options: nil)
        let physicsBody = SCNPhysicsBody(type: .static, shape: boxBodyShape)
        boxNode!.physicsBody = physicsBody
        boxNode!.physicsBody?.categoryBitMask = CollisionCategory.box.rawValue
        boxNode!.physicsBody?.contactTestBitMask = CollisionCategory.sphere.rawValue
        boxNode!.physicsBody?.collisionBitMask = boxNode!.physicsBody!.contactTestBitMask
    }
}

Here I set the sphere node in the render function, which you can move around the view:

func setUpSphere() {
         let sphereBodySphere = SCNPhysicsShape(geometry: SCNSphere(radius: 0.005))
         let physicsBody = SCNPhysicsBody(type: .kinematic, shape: sphereBodySphere)
         sphere.physicsBody = physicsBody
         sphere.physicsBody?.categoryBitMask = CollisionCategory.sphere.rawValue
         sphere.physicsBody?.contactTestBitMask = CollisionCategory.box.rawValue
         sphere.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
         sphere.physicsBody?.collisionBitMask = sphere.physicsBody!.contactTestBitMask
         previousPoint = currentPosition 
}

///It Adds a sphere and changes his position
func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
    guard let pointOfView = sceneView.pointOfView else { return }
    let mat = pointOfView.transform
    let dir = SCNVector3(-1 * mat.m31, -1 * mat.m32, -1 * mat.m33)
    let currentPosition = pointOfView.position + (dir * 0.185)

    if buttonPressed {
        if let previousPoint = previousPoint {
            sphere.position = currentPosition
            sceneView.scene.rootNode.addChildNode(sphere)
        }
     }
}

I added the protocol SCNPhysicsContactDelegate to the ViewController, and I set in ViewDidLoad():

override func viewDidLoad() {
    super.viewDidLoad()
    sceneView.delegate = self
    sceneView.scene.physicsWorld.contactDelegate = self
    ///I correctly see the shapes of the sphere and the box physics            bodies using
    sceneView.debugOptions = .showPhysicsShapes
    createBox()
    setUpSphere()
    sceneView.scene = boxScene
    sceneView.scene.physicsWorld.contactDelegate = self
}

Then I added that function:

func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact) {
        print("Collision!")
}

enter image description here

This is what happens.

When the two nodes collide nothing happens, so I can't know if the two bodies are touching. Could the problem be about .kinematic, .static or about the function render()? I followed step by step different tutorials about collisions in ARKit: Tutorial 1, Tutorial 2. I have no idea why it doesn't work like expected. Is there something wrong in my code?

Download file code link: https://ufile.io/20sla

1
I'll start this out by saying I don't know anything about arkit, but a quick comparison between your code and the Tutorial 1 code shows that you are calling didEnd in the function that triggers the collision while the tutorial calls didBegin. which the author states 'is to handle when the collision has first begun'. Maybe that could have an effect?Steve-o169

1 Answers

1
votes

willRenderScene is called uptown 60 times a second for every time the scene is going to be rendered. Since you're recreating the physics body every time it's probably messing up the physics engine determine collisions.

Try changing your code to only create the physics body once during setup.