如何在swift

时间:2018-06-14 11:37:04

标签: ios swift

在Swift 4中,我从数组中的dae文件加载/保存一组动画:

var animations = [String: CAAnimation]()
loadAnimation(withKey: "stepL", sceneName: "art.scnassets/StepL", animationIdentifier: "StepL-1")
loadAnimation(withKey: "stepR", sceneName: "art.scnassets/StepR", animationIdentifier: "StepR-1")


func loadAnimation(withKey: String, sceneName:String, animationIdentifier:String) {
    let sceneURL = Bundle.main.url(forResource: sceneName, withExtension: "dae")
    let sceneSource = SCNSceneSource(url: sceneURL!, options: nil)

    if let animationObject = sceneSource?.entryWithIdentifier(animationIdentifier, withClass: CAAnimation.self) {
        // The animation will only play once
        animationObject.repeatCount = 1
        // To create smooth transitions between animations
        animationObject.fadeInDuration = CGFloat(0.8)
        animationObject.fadeOutDuration = CGFloat(0.6)

        // Store the animation for later use
        animations[withKey] = animationObject
    }
}

稍后我正在播放动画,将其添加到我的场景中:

func playAnimation(key: String) {
    print("fire animation: " + key)
    scnView.scene?.rootNode.addAnimation(animations[key]!, forKey: key)
}

这似乎可以在触摸时单独进行,但我希望能够以非常具体的时间触发这些序列。

我已经尝试构建一个循环并将其发送到具有特定时序的DispatchQueue:

        var delaytime = state.steptime!
        for _ in 0..<state.trCount!  {
            for wSide in state.walkSeq! {
                walkQ.asyncAfter(deadline: .now() + delaytime){
                    self.playAnimation(key: wSide)
                }
                delaytime += state.steptime! + 1.0
            }
        }

我尝试过使用wallDeadline的类似但略有不同的方法:

let wt = DispatchWallTime.now() + state.pausetime!

        //build sequence
        var train_seq =  [(name:"stepL", time:wt), (name:"stepR",time:wt + state.pausetime! + state.steptime!)]

        for _ in 0..<state.trCount! {
            let lasttime = train_seq[ train_seq.count - 1 ].time
            train_seq += [(name:"stepL", time:lasttime + state.steptime!)]
            train_seq += [(name:"stepR", time:lasttime + state.pausetime! + state.steptime!)]
        }

        //send it
        for i in 0..<train_seq.count {
            walkQ.asyncAfter(wallDeadline: train_seq[i].time){
                self.playAnimation(key: train_seq[i].name)
            }
        }

不可避免地发生的是前几个按预期运行,然后围绕第四组序列开始叠加在一起并同时点火,不再遵守我定义的时间< / p>

在预期时间轴上触发序列中动画的最佳方法是什么?有没有办法暂停/睡眠循环,直到前一个动画停止,然后触发系列中的下一个?

谢谢!

1 个答案:

答案 0 :(得分:0)

我最终按照我需要的顺序进行了一系列SCNAction,包括等待

        var seq = [SCNAction]()

        for _ in 0..<state.trCount!{
            let act1 = SCNAction.run {_ in
                self.playAnimation(key: "stepL")
            }
            seq.append(act1)

            let act2 = SCNAction.wait(duration: state.steptime!)
            seq.append(act2)

            let act3 = SCNAction.run { _ in
                self.playAnimation(key: "stepR")
            }
            seq.append(act3)
            seq.append(act2)

            let act4 = SCNAction.run { _ in
                self.playAnimation(key: "idle")
            }
            seq.append(act4)

            let act5 = SCNAction.wait(duration: state.pausetime!)
            seq.append(act5)
        }

        let sequence = SCNAction.sequence(seq)
        scnView.scene?.rootNode.runAction(sequence, completionHandler:nil )