'Sometimes after a collision clearly ends, didBegin contact is called last, AFTER didEnd contact - iOS / SceneKit
I have 2 nodes properly colliding with each other. One node is a set of walls and is set as dynamic. The other node is a cylinder which follows the camera in an AR view and is set as kinematic. This is using ARKit, but the collisions are between SceneKit nodes.
The collision works exactly as I want it to and the walls' node moves correctly when the cylinder collides with it.
The problem is that I need to run some code when the collision ended to re-enable a button.
In didBegin contact I hide the button as such:
func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
if contact.nodeA.physicsBody?.categoryBitMask == BodyType.wallsCategory.rawValue || contact.nodeB.physicsBody?.categoryBitMask == BodyType.wallsCategory.rawValue {
freezeButton.isHidden = true
}
}
Then in didEnd contact I re-enable the button like that:
func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact) {
freezeButton.isHidden = false
}
And usually all of this works exactly as I wanted so the button correctly vanishes when a collision occurs and the button comes back when the collision ends.
BUT, often when the collision completes, the button does not return.
I added print statements in didBegin and didEnd and I also added similar labels on screen so I could clearly see when those functions are called. What I see is that often the last call was to didBegin even after the collision has clearly ended.
I know this because I have SCNDebugOptions.showPhysicsShapes as debugOptions so I can clearly see that the cylinder is not touching the walls at all.
I then need to cause a new collision then walk back to have the didEnd function be called and get my button back.
I'm not using the didUpdate contact call as I don't need it.
How come didBegin is called last when clearly the collision has ended?
What could cause this to happen like that?
And what could I do to fix this?
I am thinking of a workaround which would check if some time has passed since the last didBegin that would indicate this is an old collision.
Or is there something else I could check if a collision is currently still in progress? AFAIK, SceneKit doesn't have a function similar to allContactedBodies as in SpriteKit.
Is there something else I could use to check that 2 bodies are still in contact or not?
Thanks!
Solution 1:[1]
As a workaround you could probably give the End-Contact statement freezeButton.isHidden = false a small delay like with the DispatchQueue. This will re-enable the button on the next Run-Loop. This might not be the perfect solution, but it could give you better results than now. Give it a try.
DispatchQueue.main.async { self.freezeButton.isHidden = false }
In addition you could check within the Begin-Contact if the Button is not hidden already, and only hide it if needed.
if !freezeButton.isHidden { freezeButton.isHidden = true }
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | ZAY |
