有没有办法链接SceneKit动画?

时间:2019-09-18 22:03:02

标签: swift scenekit

我正在寻找一种链接SceneKit动画的方式。

我要向场景中添加x个节点,我想添加第一个节点,使其淡入,一旦可见,我们便转到下一个节点,直到所有节点都可见。因此,在我们从第二个节点开始之前,我需要在第一个节点上结束动画。

很明显,我尝试使用SCNActions进行for循环,但是动画是批处理在一起的,因此所有节点都同时出现。

我不知道要添加多少个节点,因此无法进行序列化。

处理此问题的最佳方法是什么?

编辑:

好的,我发现如果在将序列添加到节点之前将其添加到暂停的场景中(包括增加的等待间隔)

let sequence = SCNAction.sequence([.wait(duration: delay), .fadeIn(duration: 0.5)])
node.runAction(sequence)

然后,一旦添加了所有节点,我便会取消暂停场景,从而达到我想要的效果。但这似乎很骇人。

有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

暂停/取消暂停-嗯,是的,但是如果您开始做更多的事情,那可能会引起问题。

我喜欢每个(James P)的completionHandler路由。您可以使用此方法设置多个(和不同的)动画或移动。就像移动到(5,0,0)一样,旋转,设置动画,当它到达那里时,再次调用它并移动到(10,0,0),依此类推。

如果它们都以相同的方式工作,则可以使用计时器,如果这正是您想要的,那将给您带来一定的一致性。如果您走这条路线,请确保在主线程中放置计时器。

您还可以根据需要创建一些预定义的序列:

let heartBeat = SCNAction.sequence([
        SCNAction.move(to: SCNVector3(-0.5,  0.0, 0.80), duration: 0.4),
        SCNAction.unhide(),
        SCNAction.fadeIn(duration: 1.0),
        SCNAction.move(to: SCNVector3(-0.3,  0.0, 0.80), duration: 0.4),
        SCNAction.move(to: SCNVector3(-0.2,  0.2, 0.80), duration: 0.4),
        SCNAction.move(to: SCNVector3(-0.1, -0.2, 0.80), duration: 0.4),
        SCNAction.move(to: SCNVector3( 0.0,  0.0, 0.80), duration: 0.4),
        SCNAction.move(to: SCNVector3( 0.1,  0.5, 0.80), duration: 0.4),
        SCNAction.move(to: SCNVector3( 0.3, -0.5, 0.80), duration: 0.4),
        SCNAction.move(to: SCNVector3( 0.5,  0.0, 0.80), duration: 0.4),
        SCNAction.fadeOut(duration: 0.1),
        SCNAction.hide()
        ])

node.runAction(SCNAction.repeatForever(heartBeat))

答案 1 :(得分:0)

我最终使用了Timer,我确实考虑了一下,但是无法使它正常工作,可能是因为我没有在主线程上这样做。

这是到目前为止我正在使用的代码,以防其他人在同一条船上。

func animateNodesInTo(scene: SCNScene, withDuration: TimeInterval) {

        DispatchQueue.main.async {
            let nodes = scene.rootNode.childNodes
            let acion = SCNAction.fadeIn(duration: withDuration)

            Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
                let opaqueNode = nodes.first(where: {$0.opacity == 0})
                opaqueNode?.runAction(acion)

                if opaqueNode == nil {
                    timer.invalidate()
                }
            }
        }

    }