0

Im having trouble with detecting collisions in AR/SCNKit. Ive found this: How to set up SceneKit collision detection, although helpful, I still dont have my code working.

The main goal is to detect when two scene nodes touch, one is a ball, the other is a scnbox acting as a scnplane.

ViewController.swift

class ViewController: UIViewController, ARSCNViewDelegate, SCNPhysicsContactDelegate{

    override func viewDidLoad() {
        super.viewDidLoad()
        let scene = SCNScene()
        sceneView.scene = scene
        sceneView.scene.physicsWorld.contactDelegate = self
    }

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

        let width = CGFloat(planeAnchor.extent.x)
        let length = CGFloat(planeAnchor.extent.z)
        let planeHeight = CGFloat(0.01)

        let plane = SCNBox(width: width, height:planeHeight, length:length, chamferRadius: 0)

        plane.materials.first?.diffuse.contents = UIColor.orange
        let planeNode = SCNNode(geometry: plane)

        let x = CGFloat(planeAnchor.center.x)
        let y = CGFloat(planeAnchor.center.y)
        let z = CGFloat(planeAnchor.center.z)
        planeNode.position = SCNVector3(x,y,z)

        planeNode.physicsBody = SCNPhysicsBody(type:.kinematic, shape: SCNPhysicsShape(geometry:plane, options:nil))
        planeNode.physicsBody?.categoryBitMask = Int(CategoryMask.plane.rawValue)
        planeNode.physicsBody?.collisionBitMask = Int(CategoryMask.ball.rawValue) | Int(CategoryMask.plane.rawValue)
    }

    func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
        print("-> didBeginContact")
    }

    func physicsWorld(_ world: SCNPhysicsWorld, didUpdate contact: SCNPhysicsContact) {
        print("-> didUpdateContact")
    }

    func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact) {
        print("-> didEndContact")
    }

Ball.swift

class Ball {
    init(x: Float, y: Float, z:Float){

    let sphereNode = SCNNode()
    let sphere = SCNSphere(radius: 0.05)
    sphereNode.addChildNode(SCNNode(geometry: sphere))

    sphereNode.position = SCNVector3(x, y, z)
    self.node = sphereNode

    self.node.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry:sphere, options:nil))
    self.node.physicsBody?.categoryBitMask = Int(CategoryMask.ball.rawValue)
    self.node.physicsBody?.collisionBitMask = Int(CategoryMask.ball.rawValue) | Int(CategoryMask.plane.rawValue)
    self.node.physicsBody?.friction = 1
    self.node.physicsBody?.mass = 2.0
}

Constants.swift

enum CategoryMask: UInt32 {
    case ball = 0b01 // 1
    case plane = 0b11 // 2
}

I am expecting physicsWorld to get called when the plane and ball collide but it's not happening. Any insight is much appreciated.

user287474
  • 325
  • 1
  • 5
  • 19
  • Is there a reason you’re positioning the plane node at (0,0,0) rather than at the location of the plane anchor? – Noah Witherspoon May 31 '18 at 18:37
  • Im actually doing that in my code, but I only wanted to add the stuff relevant to the question – user287474 May 31 '18 at 19:00
  • It’s definitely relevant; if the node’s in the wrong place or has the wrong orientation, you’re not going to see the collision behavior you expect. My guess would be that the collider’s too thin and your ball objects are passing through it, but it’d help to have a more accurate representation of the code you’re actually running. – Noah Witherspoon Jun 01 '18 at 17:16
  • @NoahWitherspoon I updated the code in my question – user287474 Jun 01 '18 at 18:40

0 Answers0