1

I just found a really odd behavior with Scene Kit. I created a clean project to see if this would happen, and it did. Consider the following GameViewController class:

import UIKit
import QuartzCore
import SceneKit

class GameViewController: UIViewController, SCNPhysicsContactDelegate {

    func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {
        let label = UILabel(frame: CGRectMake(0, 0, 100, 100))
        label.textColor = .whiteColor()
        label.text = "Test"
        self.view.addSubview(label)
    }

    override func viewDidLoad() {

        // Controller
        super.viewDidLoad()

        // Scene
        let scene = SCNScene()
        scene.physicsWorld.contactDelegate = self

        // Scene View
        let scnView = self.view as! SCNView
        scnView.scene = scene

        // Camera
        let camera = SCNCamera()
        camera.usesOrthographicProjection = true
        camera.orthographicScale = 8

        // Camera Node
        let cameraNode = SCNNode()
        cameraNode.camera = camera
        cameraNode.position = SCNVector3(x: -3, y: 7.5, z: 10)
        cameraNode.eulerAngles = SCNVector3(x: -0.5, y: -0.5, z: 0)
        scene.rootNode.addChildNode(cameraNode)

        // Light
        let light = SCNLight()
        light.type = SCNLightTypeDirectional

        // Light Node
        let lightNode = SCNNode()
        lightNode.light = light
        lightNode.eulerAngles = SCNVector3Make(-1, -0.5, 0)
        scene.rootNode.addChildNode(lightNode)

        // Box Shape
        let geometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
        geometry.materials.first?.diffuse.contents = UIColor(red: 255, green: 255, blue: 0, alpha: 1)

        // Upper Box
        let box = SCNNode(geometry: geometry)
        box.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: nil)
        box.physicsBody?.categoryBitMask = 1
        box.physicsBody?.contactTestBitMask = 2
        scene.rootNode.addChildNode(box)

        // Bottom Box
        let box2 = SCNNode(geometry: geometry)
        box2.position.y -= 5
        box2.physicsBody = SCNPhysicsBody(type: .Static, shape: nil)
        box2.physicsBody?.categoryBitMask = 2
        box2.physicsBody?.contactTestBitMask = 1
        box2.physicsBody?.affectedByGravity = false
        scene.rootNode.addChildNode(box2)

    }
}

What happens here is, we create a SCNScene, then we add the camera/lightning and create two boxes that will collide. We also set the controller as a delegate for the physics contact delegate.

But the important code is at the top, when the contact between the two objects occurs. We create an UILabel and position it at the top left of the screen. But here is the problem: It takes around seven seconds for the label to display. And it seems to always be this time. This seems rather odd, but you can try it yourself: just create a SceneKit project (using Swift), and replace the controller code with the one I provided.

Additional note: if you add print("a") in the physicsWorld() function, it will run immediately, so the code is being run at the right time, but for some reason the UILabel isn't displaying right away.

zantuja
  • 211
  • 1
  • 4
  • 14

1 Answers1

1

At first I thought your scene wasn't being rendered after the contact; hence not displaying the label, so put a scnView.playing = true line in. However, this resulted in the label never being displayed.

Next thought was that you're trying to do something on a thread you shouldn't be. Modifying UIKit views should really only be done on the main thread, and it's not clear what thread calls the SCNPhysicsContactDelegate functions. Given it's relatively easy to ensure it does run on the main thread...

func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {
    dispatch_async(dispatch_get_main_queue()) {
        let label = UILabel(frame: CGRectMake(0, 0, 100, 100))
        label.textColor = .whiteColor()
        label.text = "Test"
        self.view.addSubview(label)
    }
}

This fixes the delay for me, and also works with scnView.playing = true.

lock
  • 2,861
  • 1
  • 13
  • 20
  • Thanks. I wasn't expecting that issue as the code worked perfectly on a SpriteKit project. This seemed to solve the problem. – zantuja Jul 19 '16 at 06:38