2017-03-16 1 views
3

Je souhaite être capable d'exécuter plusieurs animations, l'une après l'autre, dans SceneKit. J'ai mis en place une fonction qui exécute une animation comme ceci:Plusieurs animations série dans 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() 
} 

Et puis j'ai essayé d'exécuter plusieurs animations série comme ceci:

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

Tout est anime, mais les animations ne pas courir de manière sérielle. Les animations commencent et finissent dans un temps imprévisible. journaux Exemples de débogueur:

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

je me rends compte que mon approche est pas le meilleur, mais seulement de cette façon que j'a pu réaliser des animations presque de travail.

Je sais qu'il existe une classe SCNAction disponible. Peut-être que je devrais faire beaucoup d'actions dans une transaction? Si oui, quelqu'un pourrait-il m'expliquer comment fonctionne exactement SCNTransactions et pourquoi le bloc d'achèvement de SCNTransaction se termine-t-il dans un temps imprévisible?

Répondre

3

Essayez d'utiliser SCNAction.sequence():

class func sequence([SCNAction]) 

Crée une action qui exécute un ensemble d'actions de manière séquentielle

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

let node = SCNNode() 
node.runAction(sequence, completionHandler:nil) 
1

Après la réponse de @Oleh Zayats J'ai J'ai essayé d'implémenter mon cas en utilisant la méthode SCNAction.sequence (_ :), mais le problème était que j'avais besoin que le gestionnaire de complétion soit déclenché après chaque sous-action complétée afin de pouvoir retirer les nœuds de rotationNode.

Après quelques heures de lutte, j'ai trouvé une solution plutôt sympa et ça a marché comme un charme.

A savoir:

J'ai fait une rotateAction fonction qui ressemble à ceci:

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

Alors j'ai pu écrire une fonction pour pouvoir exécuter plusieurs animations l'un après l'autre:

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