2017-03-16 2 views
3

Ich möchte in SceneKit mehrere Animationen nacheinander ausführen können. Ich habe eine Funktion implementiert, die so eine Animation wie läuft:Mehrere serielle Animationen in 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() 
} 

Und dann habe ich versucht, mehrere serielle Animationen wie so laufen:

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

Alles belebt aber die Animationen nicht seriell ablaufen. Animationen beginnen und enden in unvorhersehbarer Zeit. Probenprotokolle von 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 

Ich weiß, dass mein Ansatz ist nicht die beste, aber nur so konnte ich fast Arbeits Animationen erzielen.

Ich weiß, dass es eine SCNAction-Klasse gibt. Vielleicht sollte ich viele Aktionen innerhalb einer Transaktion machen? Wenn ja, könnte mir jemand erklären, wie genau SCNTransactions funktionieren und warum der Completion-Block der Completion SCNTransaction in unvorhersehbarer Zeit ausgelöst wird?

Antwort

3

Try SCNAction.sequence() verwenden:

class func sequence([SCNAction]) 

Erzeugt eine Aktion, die eine Sammlung von Aktionen nacheinander ausgeführt

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

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

Antwort @Oleh Zayats' Im Anschluss Ich habe Ich versuchte, meinen Fall mit der Methode SCNAction.sequence (_ :) zu implementieren, aber das Problem war, dass ich nach jeder abgeschlossenen Unteraktion den Beendigungshandler brauchte, um ihn zu löschen, damit ich die Knoten entfernen konnte Rotationsknoten.

Nach ein paar Stunden des Kampfes habe ich eine recht schöne Lösung gefunden und es funktionierte wie ein Zauber.

Nämlich:

Ich habe eine Funktion rotateAction gemacht, die etwa wie folgt aussieht:

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

Dann eine Funktion schreiben konnte ich in der Lage mehrere Animationen nacheinander auszuführen:

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