Scenekit - physicsWorld设置,以防止运动节点相交

时间:2017-10-20 06:10:41

标签: ios swift scenekit

我的场景中有几个节点可以旋转和拖动。我已经设置了一个physicsWorld委托,将类型为kinematic的physicsBody添加到我的节点并检查physicsWorld didBeginContact - 到目前为止一切正常,当我移动节点时,联系人开始/结束触发。

我试图处理这个的方法是设置一个bool var,一旦接触开始阻止进一步移动,就会变为true,但是我遇到了一些情况(特别是如果我拖得节点太快),那个节点在另一个对象内部得到一点点。

我应该使用不同的方法吗?我真的不想要碰撞,只是另一个节点表现“坚固”,即使在高速接触时也不允许交叉。

编辑:

一些示例图片以进一步澄清问题:

为简单起见,我只添加了2个节点来演示此问题。第一张图像是初始位置,第二张图像和第三张图像(侧视图)位于右侧非常快速的平移之后。仅在节点已经交叉之后才触发接触检测。

我尝试过的一种方法是在触发接触之前抓住最后一个位置,并在检测到接触后重新设置节点位置,但结果非常不连贯且不稳定,有时你可以看到物体相交跳到最后的“好”位置。我觉得必须有一些更简单的方法来实现这一目标,但在花费数小时通过可用资源后,我无法弄明白。

编辑2

进一步的研究指出了扫描测试线,技术上如果我能在移动节点之前检测到可能的碰撞,我应该能够在交叉点发生之前限制移动停止

UPDATE:另一个死胡同,正如Xcode所指出的那样

Error: convexSweep only works with convex shapes

1 个答案:

答案 0 :(得分:2)

经过很多天的轰炸和几乎放弃之后,我重新重读了physicsWorld文档,终于找到了我一直在忽视的东西 - 可以随时手动触发的contactTest方法,独立于渲染环。我在渲染器中使用它(_:willRenderScene:atTime :)以便"修复"渲染场景之前的重叠。

我的场景比示例复杂一点,但几乎没有额外的调整,我几乎让它现在正常工作。我不确定这是否是正确的解决方案,以及它将如何变得性能明智,但是现在我会安定下来,这样我就可以继续开发。

相关代码以防有人在类似情况下运行:

func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {

    // make sure we have active node and pan direction
    if(selectedBrickNode != nil && self.panDirection != nil){

        // contactTest
        let pw = scnScene.physicsWorld
        let node = selectedBrickNode.node!
        let contacts = pw.contactTest(with: node.physicsBody!, options: nil)

        var axisVector:SCNVector3
        // specify which axis we want to correct
        switch self.panDirection!{
            case "right","left": axisVector = SCNVector3Make(1,0,0)
            default: axisVector = SCNVector3Make(0,1,0);
        }

        for contact in contacts {
            // round contact normal to get a unit vector
            let cn = SCNVector3( round(contact.contactNormal.x),
                                 round(contact.contactNormal.y),
                                 round(contact.contactNormal.z))

            // fix only for pan direction axis
            if abs(cn.x) == axisVector.x && abs(cn.y)==axisVector.y  {
                let normal = contact.contactNormal
                let transform = SCNMatrix4MakeTranslation( round(normal.x) * -Float(contact.penetrationDistance),
                                            round(normal.y) * -Float(contact.penetrationDistance),
                                            round(normal.z) * -Float(contact.penetrationDistance))
                node.transform = SCNMatrix4Mult(node.transform, transform)
                // break to prevent repeated contacts 
                break;
            }

        }

    }
}