2017-03-16 33 views
3

我希望能夠在SceneKit中一個接一個地運行多個動畫。我實現它運行一個動畫像這樣的功能: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的完成塊在不可預知的時間內觸發?

回答

3

嘗試使用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

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