0

I can't find any examples of Scene Kit contact handling, more specifically, anything implementing the below function:

func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
  ...
}

I can't get mine working so I came here.

This is what I have so far:

import UIKit
import QuartzCore
import SceneKit

enum BodyType: UInt32 {
    case sphere = 1
    case wall = 2
}

class GameViewController: UIViewController, SCNSceneRendererDelegate, SCNPhysicsContactDelegate {

    var gameView : SCNView!
    var gameScene : SCNScene!
    var cameraNode : SCNNode!
    var lightNode1 : SCNNode!
    var lightNode2 : SCNNode!

    override func viewDidLoad() {
        super.viewDidLoad()
        initView()
        initScene()
        initCamera()
        initLights()
        createBoundary()
        createBall()
    }

    func initView(){
        gameView = self.view as! SCNView
        gameView.allowsCameraControl = true
        gameView.autoenablesDefaultLighting = true
        gameView.delegate = self
        gameView.scene?.physicsWorld.contactDelegate = self
    }

    func initScene (){
        gameScene = SCNScene()
        gameView.scene = gameScene
        gameView.isPlaying = true
    }

    func initCamera() {
        cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 14.4, z: 0)
        cameraNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: Float.pi * 1.5)
        gameScene.rootNode.addChildNode(cameraNode)
    }

    func initLights() {
        lightNode1 = SCNNode()
        lightNode1.light = SCNLight()
        lightNode1.light?.type = SCNLight.LightType.omni
        lightNode1.light?.intensity = 300
        lightNode1.position = SCNVector3(x: 0, y: 20, z: 0)
        gameScene.rootNode.addChildNode(lightNode1)

        lightNode2 = SCNNode()
        lightNode2.light = SCNLight()
        lightNode2.light?.type = SCNLight.LightType.ambient
        lightNode2.light?.intensity = 900
        lightNode2.position = SCNVector3(x: 0, y: 0, z: 0)
        gameScene.rootNode.addChildNode(lightNode2)
    }

    func createBoundary() {
        let geometry:SCNGeometry = SCNPlane(width: 10, height: 10)
        geometry.materials.first?.diffuse.contents = UIColor.cyan
        let geometryNode = SCNNode(geometry: geometry)
        geometryNode.physicsBody = SCNPhysicsBody(type: .static, shape: nil)
        geometryNode.position = SCNVector3(x: 0, y: 0, z: 0)
        geometryNode.physicsBody?.categoryBitMask = BodyType.wall.hashValue
        geometryNode.physicsBody?.collisionBitMask = BodyType.wall.hashValue
        geometryNode.physicsBody?.contactTestBitMask = BodyType.wall.hashValue
        geometryNode.physicsBody?.isAffectedByGravity = false
        gameScene.rootNode.addChildNode(geometryNode)
        self.gameView.scene?.physicsWorld.gravity = SCNVector3(x: 0, y: 0, z: -10)

    }

    func createBall() {
        let geometry : SCNSphere = SCNSphere(radius: 1)
        geometry.materials.first?.diffuse.contents = UIColor.white
        let geometryNode = SCNNode(geometry: geometry)
        geometryNode.physicsBody?.categoryBitMask = BodyType.sphere.hashValue
        geometryNode.physicsBody?.collisionBitMask = BodyType.sphere.hashValue
        geometryNode.physicsBody?.contactTestBitMask = BodyType.sphere.hashValue
        geometryNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
        geometryNode.position = SCNVector3(x: 0, y: 0, z: 0)
        geometryNode.physicsBody?.isAffectedByGravity = true
        gameScene.rootNode.addChildNode(geometryNode)
    }

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

    override var shouldAutorotate: Bool {
        return false
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

}

The print("hit") line doesn't get called. Why is that?

user113630
  • 13
  • 4
  • Try changing `hashValue` to `rawValue` in your switch statement. – 0x141E Apr 23 '17 at 19:49
  • I get an error: Expression pattern of type 'UInt32' cannot match values of type 'Int' – user113630 Apr 25 '17 at 02:08
  • Change the `BodyType` enum from `UInt32` to `Int`. You'll also need to change `hashValue` to `rawValue` when assigning the physicsBody's bit masks. You shouldn't use `hashValue` anywhere in the code you posted. – 0x141E Apr 25 '17 at 09:02
  • ^^^ You are right. I needed to change the `BodyType` to `Int` and use `rawValue` instead of `hashValue`. But one thing nobody caught was that `gameView.scene?.physicsWorld.contactDelegate = self` needed to be in the `viewDidLoad()` lol just figured that out – user113630 Apr 27 '17 at 22:03

0 Answers0