Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple serial animations in SceneKit

I want to be able to run multiple animations, one after another, in SceneKit. I've implemented a function which runs one animation like so:

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()
}

And then I've tried to run multiple serial animations like so:

    func animateMoves(_ moves: [Move]) {
        for (index, move) in moves.enumerated() {
            perform(#selector(animateMove(_:)), 
            with: move, 
            afterDelay: TimeInterval(Double(index) * move.duration)
        }
    }

Everything is animating but the animations don't run in a serial manner. Animations start and finish in unpredictable time. Sample logs from debugger:

Animate move started 1
Animate move started 2
Animate move finished 1
Animate move finished 2
Animate move started 3
Animate move finished 3

I realise that my approach isn't the best, but only in that way I was able to achieve almost working animations.

I know that there is a SCNAction class available. Maybe I should make many actions within one transaction? If so, could someone explain to me how exactly SCNTransactions work and why the completion SCNTransaction's completion block fires in unpredictable time?

like image 378
Bartosz Olszanowski Avatar asked Mar 16 '17 17:03

Bartosz Olszanowski


1 Answers

Try to use SCNAction.sequence():

class func sequence([SCNAction])

Creates an action that runs a collection of actions sequentially

let sequence = SCNAction.sequence([action1, action2, action3]) // will be executed one by one

let node = SCNNode()
node.runAction(sequence, completionHandler:nil)
like image 94
Oleh Zayats Avatar answered Nov 15 '22 03:11

Oleh Zayats