Q:

Trying to print something when two objects are in contact/collides. Will later add score when ball touches the bottom of the bucket

My two objects are: a ball, and a bucket. The bucket consists of two childNode What I am trying to achieve is to do something whenever the ball goes inside the bucket and touches the "cylinder" of the bucket which is the base. But when I add the baseNode as childNode with name cylinder, my bucket disappears in the scene and does not load anything. How can I get this working along with the contact that is happening.
import UIKit
import SceneKit
import ARKit

enum BodyType: Int{

case ballNode = 1
case baseNode = 2

}

class ViewController: UIViewController, ARSCNViewDelegate {

@IBOutlet var sceneView: ARSCNView!

@IBOutlet weak var AddBasketBtn: UIButton!
override func viewDidLoad() {
    super.viewDidLoad()

sceneView.scene.physicsWorld.contactDelegate = self as? SCNPhysicsContactDelegate

    // Set the view's delegate
    sceneView.delegate = self

    // Show statistics such as fps and timing information
    sceneView.showsStatistics = true

    // Create a new scene
    let scene = SCNScene()

    // Set the scene to the view
    sceneView.scene = scene

   registerGestureRecognizer()
}

func registerGestureRecognizer(){

  let directions : [UISwipeGestureRecognizer.Direction] = [.up]
    for direction in directions{
   let swipe = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe))
    swipe.direction = direction
        sceneView.addGestureRecognizer(swipe)

    }

}

@objc func handleSwipe(gestureRecognizer: UISwipeGestureRecognizer){

    //print ("will it work?")
    //sceneview to be accessed
    //access the point of view of the sceneView, the center point

    guard let sceneView = gestureRecognizer.view as? ARSCNView else{

        return
    }
    guard let centerPoint = sceneView.pointOfView else {

        return

    }

    //transform matrix
    //the orientation
    //position of camera
    // orientation and position are needed to determine the camera where the ball needs to be placed
    let cameraTransform = centerPoint.transform

    let cameraLocation = SCNVector3(x: cameraTransform.m41, y: cameraTransform.m42, z: cameraTransform.m43)

    let cameraOrientation = SCNVector3(x: -cameraTransform.m31, y: -cameraTransform.m32, z: -cameraTransform.m33)

    //x1 + x2, y1+y2, z1+z2
    let cameraPosition = SCNVector3Make(cameraLocation.x + cameraOrientation.x, cameraLocation.y + cameraOrientation.y, cameraLocation.z + cameraOrientation.z)

    let ball = SCNSphere(radius:0.04)
   // Bucketnode.scale = SCNVector3Make(0.2,0.2,0.2);
    let material = SCNMaterial()
    material.diffuse.contents = UIImage(named: "basketballSkin.png")
    ball.materials = [material]

    let ballNode = SCNNode(geometry: ball)

    ballNode.position = cameraPosition

    let physicsShape = SCNPhysicsShape(node: ballNode, options:nil)

    let physicsBody = SCNPhysicsBody(type: .dynamic, shape: physicsShape)

    ballNode.physicsBody = physicsBody

    ballNode.physicsBody?.categoryBitMask = BodyType.ballNode.rawValue
    ballNode.physicsBody?.collisionBitMask = BodyType.ballNode.rawValue
    ballNode.physicsBody?.contactTestBitMask = BodyType.ballNode.rawValue

    let forceVector:Float = 2.7

    ballNode.physicsBody?.applyForce(SCNVector3Make(cameraPosition.x * forceVector, cameraPosition.y * forceVector, cameraPosition.z*forceVector), asImpulse: true)

    sceneView.scene.rootNode.addChildNode(ballNode)

    DispatchQueue.main.asyncAfter(deadline: .now() + 2) { // change 2 to desired number of seconds
        ballNode.removeFromParentNode()
    }
}

func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
    let contactMask = contact.nodeA.categoryBitMask | contact.nodeB.categoryBitMask
    switch (contactMask) {
    case BodyType.baseNode.rawValue | BodyType.ballNode.rawValue :
        print("hit")
    default:
        return
    }
}

func addBackboard(){

guard let bucketScene = SCNScene(named:"art.scnassets/BucketBlue.scn") else {

    return
}

guard let bucketNode = bucketScene.rootNode.childNode(withName: "tube", recursively: false) else {

    return
}

guard let baseNode = bucketScene.rootNode.childNode(withName: "cylinder", recursively: true) else {

    return
} //this part makes my bucket disappear, without it, it works fine but no contact action can be recognised

baseNode.physicsBody?.categoryBitMask = BodyType.baseNode.rawValue
baseNode.physicsBody?.collisionBitMask = BodyType.baseNode.rawValue
baseNode.physicsBody?.contactTestBitMask = BodyType.baseNode.rawValue

bucketNode.scale = SCNVector3Make(0.15,0.15,0.15);
bucketNode.worldPosition = SCNVector3(x: 0, y: -1.35, z: -1.4)

let physicsShape = SCNPhysicsShape(node: bucketNode, options: [SCNPhysicsShape.Option.type: SCNPhysicsShape.ShapeType.concavePolyhedron])

let physicsBody = SCNPhysicsBody(type: .static, shape: physicsShape)

bucketNode.physicsBody = physicsBody

sceneView.scene.rootNode.addChildNode(bucketNode)

}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Create a session configuration
    let configuration = ARWorldTrackingConfiguration()

    // Run the view's session
    sceneView.session.run(configuration)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    // Pause the view's session
    sceneView.session.pause()
}

// MARK: - ARSCNViewDelegate

/*
// Override to create and configure nodes for anchors added to the view's session.
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    let node = SCNNode()

    return node
}
*/

func session(_ session: ARSession, didFailWithError error: Error) {
    // Present an error message to the user

}

func sessionWasInterrupted(_ session: ARSession) {
    // Inform the user that the session has been interrupted, for example, by presenting an overlay

}

func sessionInterruptionEnded(_ session: ARSession) {
    // Reset tracking and/or remove existing anchors if consistent tracking is required

}
@IBAction func AddBasket(_ sender: Any) {
    addBackboard()
    AddBasketBtn.isHidden = true
}
}

A:

I solved my problem in my code by deleting the base of the bucket in SceneKit editor and then adding another base to it through code using SCNCylinder as a new node to the scene. Then I used the new node for contact with my ball using contact bit masks.

