【问题标题】:Multiple serial animations in SceneKitSceneKit 中的多个串行动画
【发布时间】:2017-08-08 01:15:00
【问题描述】:

我希望能够在 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 的完成块会在不可预测的时间内触发?

【问题讨论】:

    标签: ios swift animation scenekit scntranscaction


    【解决方案1】:

    尝试使用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)
    

    【讨论】:

      【解决方案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)
      }
      

      【讨论】:

        猜你喜欢
        • 2016-08-04
        • 2015-08-30
        • 1970-01-01
        • 2020-07-28
        • 2012-08-21
        • 2015-02-27
        • 2015-07-24
        • 2016-04-27
        • 2016-01-03
        相关资源
        最近更新 更多