我希望能够在SceneKit中一个接一个地运行多个动画。我已经实现了一个运行一个动画的函数:
fileprivate func animateMove(_ move: Move) {
print("Animate move started " + move.identifier)
// I am creating rotateNode
let rotateNode = SCNNode()
rotateNode.eulerAngles.x = CGFloat.pi
scene.rootNode.addChildNode(rotateNode)
// Then I am selecting nodes which I want to rotate
nodesToRotate = ...
// Then I am adding the nodes to rotate node
_ = nodesToRotate.map { rotateNode.addChildNode($0) }
SCNTransaction.begin()
SCNTransaction.animationDuration = move.animationDuration
SCNTransaction.completionBlock = {
rotateNode.enumerateChildNodes { node, _ in
node.transform = node.worldTransform
node.removeFromParentNode()
scene.rootNode.addChildNode(node)
}
rotateNode.removeFromParentNode()
print("Animate move finished " + move.identifier)
}
SCNTransaction.commit()
}
然后我尝试运行多个串行动画,如下所示:
func animateMoves(_ moves: [Move]) {
for (index, move) in moves.enumerated() {
perform(#selector(animateMove(_:)),
with: move,
afterDelay: TimeInterval(Double(index) * move.duration)
}
}
一切都是动画,但动画不会以连续方式运行。动画在不可预测的时间内开始和结束。 来自调试器的示例日志:
Animate move started 1
Animate move started 2
Animate move finished 1
Animate move finished 2
Animate move started 3
Animate move finished 3
我意识到我的方法不是最好的,但只有通过这种方式,我才能够实现几乎可以工作的动画。
我知道有一个SCNAction类可用。也许我应该在一次交易中做出很多动作?如果是这样,有人可以向我解释SCNTransactions究竟是如何工作的以及SCNTransaction的完成块在不可预测的时间内完成的原因是什么?
答案 0 :(得分:4)
尝试使用 SCNAction.sequence():
class func sequence([SCNAction])
创建一个按顺序运行一系列操作的操作
let sequence = SCNAction.sequence([action1, action2, action3]) // will be executed one by one
let node = SCNNode()
node.runAction(sequence, completionHandler:nil)
答案 1 :(得分:2)
按照@Oleh Zayats的回答我尝试使用SCNAction.sequence(_ :)方法实现我的案例,但问题是我需要在每个完成的子操作后触发完成处理程序才能删除来自rotationNode的节点。
经过几个小时的挣扎,我得到了一个非常好的解决方案,它就像一个魅力。
即:
我创建了一个函数rotateAction,它看起来像这样:
func rotateAction(with move: Move, from rotateNode: SCNNode) -> SCNAction {
let preAction = SCNAction.run { (rotateNode) in
// all the pre action setup like choosing nodes to rotate
}
let action = SCNAction.rotate(by: -move.angle, around: vector, duration: move.animationDuration)
let postAction = SCNAction.run { (rotateNode) in
// completion handler for each action
}
return SCNAction.sequence([preAction, action, postAction])
}
然后我能够编写一个能够一个接一个地运行多个动画的函数:
func animateRotateMoves(_ moves: [Move]) {
let rotateNode = SCNNode()
scene.rootNode.addChildNode(rotateNode)
var actions: [SCNAction] = []
for move in moves {
let action = rotateAction(with: move, from: rotateNode)
actions.append(action)
}
actions.append(SCNAction.removeFromParentNode())
let sequence = SCNAction.sequence(actions)
rotateNode.runAction(sequence)
}