节点组的位置在SCNNode.runAction的开头重置

时间:2015-03-02 21:24:12

标签: ios swift scenekit scnnode

我有一些代码可以在点击屏幕时围绕x轴旋转几个SCNNode:

func handleTap(gestureRecognize: UIGestureRecognizer) {
    let sceneView = self.view as SCNView

    let slice = self.cubes[0...8]
    let container = SCNNode()
    for node: SCNNode in slice {
        container.addChildNode(node)
    }
    sceneView.scene!.rootNode.addChildNode(container)
    container.runAction(SCNAction.rotateByX(CGFloat(M_PI / 2), y: 0.0, z: 0.0, duration: 1), completionHandler: { () -> Void in
        println("complete")
    })
}

我遇到的问题是,每次调用此函数时,节点似乎都会在执行操作之前将自身重置为原始位置。操作完成后,它们似乎保持在正确的位置,直到再次点击屏幕。如何进行后续调用handleTap将其从当前位置旋转?

我尝试在将节点添加到容器之前从其原始父节点中删除它们,但它没有明显的效果。

我也尝试过使用动画

    let spin = CABasicAnimation(keyPath: "rotation")
    spin.fromValue = NSValue(SCNVector4: SCNVector4(x: -1, y: 0, z: 0, w: 0))
    spin.toValue = NSValue(SCNVector4: SCNVector4(x: -1, y: 0, z: 0, w: Float(M_PI_2)))
    spin.duration = 3
    spin.repeatCount = .infinity
    container.addAnimation(spin, forKey: "spin around")

与行动具有完全相同的效果。

如果我将节点作为根视图的子节点放回runAction的完整块中

    container.runAction(action, completionHandler: { () -> Void in
        println("completed rotation")
        for node: SCNNode in slice {
            node.removeFromParentNode()
            sceneView.scene!.rootNode.addChildNode(node)
        }
    })

然后节点在完成操作后返回到原始位置,而不是在新点击开始时返回。

2 个答案:

答案 0 :(得分:0)

当从场景的根节点移除节点,添加到容器并旋转时,相对于容器的本地坐标系将变换应用于节点。解决方案是将节点的转换从容器的坐标系转换为根节点的坐标系,然后再将其添加回根节点。

func handleTap(gestureRecognize: UIGestureRecognizer) {
    let sceneView = self.view as SCNView
    let action = SCNAction.rotateByAngle(CGFloat(M_PI_2), aroundAxis: SCNVector3Make(-1, 0, 0), duration: 1)
    let slice = self.cubes[0...8]
    let container = SCNNode()
    let root = sceneView.scene!.rootNode


    for node: SCNNode in slice {
        container.addChildNode(node)
    }

    root.addChildNode(container)

    container.runAction(action, completionHandler: { () -> Void in
        for node: SCNNode in slice {
            let transform = node.parentNode!.convertTransform(node.transform, toNode: root)
            node.removeFromParentNode()
            node.transform = transform
            root.addChildNode(node)
        }
    })
}

答案 1 :(得分:0)

这是我在没有容器或类似容器的情况下旋转SCNNode的方式:

let targetRotationRadians: CGFloat = targetRotationAngle * (CGFloat.pi / 180.0)
let rotationAction = SCNAction.rotateTo(x: 0.0, y: targetRotationRadians, z: 0.0, duration: animationDuration, usesShortestUnitArc: true)
yourSCNNode.runAction(rotationAction)

重要的是将usesShortestUnitArc方法的true设置为SCNAction.rotateTo。这样,节点不必旋转到所需角度即可返回其原始角度。