Is there a way to prevent node glitching shaking during collisions?

Viewed 96

The function (code below) simply moves a character node (contact.nodeA) back after it has penetrated a collision node (contact.nodeB) that it's not allowed to pass through.

In a scenario where a user is trying to move the character node (contact.nodeA) while it's stuck in a corner, etc. the scene/character repeatedly shakes/glitches while its position is repeatedly being moved back away from contact.nodeB at 60hz.

Is it possible with SCNPhysicsContact in SceneKit to prevent contact.nodeA from moving forward into contact.nodeB in the first place? (ie., why does "contact.penetrationDistance" occur at all? Why can't we just be alerted when a physics contact has begun w/o contact.nodeA actually moving forward into contact.nodeB? We are, after all, catching the contact on "didBegin" yet there's already penetration that we have to readjust.)

(When a user is trying to move the character node while it's "stuck" in a corner, or between two rocks, etc.)

Or, is there another solution to prevent the repeated shaking of contact.nodeA as its position is repeatedly being readjusted to compensate for its penetration into contact.nodeB? Transform instead of position change?

I've already tried setting momentum to 0.0 and removing all animations, etc. However, since contact is still occurring with contact.nodeB, contact.nodeA cannot be moved away since its momentum is still being stopped during contact with nodeB.

Any help would be greatly appreciated.

private func characterNode(_ characterNode: SCNNode, hitWall wall: SCNNode, withContact contact: SCNPhysicsContact) {

    if characterNode.name != "collider" { return }
        
    if maxPenetrationDistance > contact.penetrationDistance { return }

    var characterPosition = float3(characterNode.parent!.position)
    var positionOffset = float3(contact.contactNormal) * Float(contact.penetrationDistance)
        
    maxPenetrationDistance = contact.penetrationDistance
    characterPosition.y += positionOffset.y
    replacementPositions[characterNode.parent!] = SCNVector3(characterPosition)
}

extension GameViewController : SCNPhysicsContactDelegate {
    func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
        
    if gameState != .playing { return }
    
    contact.match(BitmaskWall) {
        (matching, other) in
        
        if other.name == "collider" {
            self.characterNode(other, hitWall: matching, withContact: contact)
        }
    }
}
0 Answers
Related