2017-10-20 102 views
0

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

我试图解决这个问题的方法是设置一个布尔变量,一旦联系开始,以防止进一步移动,但我遇到案件(特别是如果我拖动节点太快),更改为真,该节点在另一个对象内稍微有一点点。

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

编辑:

一些样本图像以进一步澄清该问题:

为了简单起见我已经添加仅2个节点来证明的问题。第一张图像是初始位置,第二张和第三张(侧面图)在非常快速的平移之后。只有在节点已经相交后才触发联系检测。

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

EDIT 2

进一步研究朝下扫描试验线,technicaly如果我能发现可能的碰撞之前我移动节点,我应该能够限制运动停止intersetion发生

UPDATE:另一个死胡同,因为Xcode中指出

Error: convexSweep only works with convex shapes 

回答

1

很多撞头和人的天之后大多数放弃了,我重新阅读了physicsWorld文档,并最终找到了我一直忽略的东西 - contactTest方法,可以在任何时候手动触发,独立于渲染循环。我在渲染器(_:willRenderScene:atTime :)中使用它,以便在场景呈现之前“修复”重叠。

我的场景比示例稍微复杂一点,但是几乎没有多余的tweeks,现在我几乎可以使用它了。我不确定这是否是合适的解决方案,以及如何高性价比才能成为明智的选择,但现在我会安顿下来,这样我可以继续开发。

的情况下,有人相关的代码在类似的情况运行:

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; 
      } 

     } 

    } 
}