Extracting CAAnimation from a .dae file so I can use setAnimationSpeed to change the speed

306 views Asked by At

I have a .dae file animation of a train, and I am trying to extract the train's animation as a CAAnimation so I can use the function setAnimationSpeed to ... change it's speed.

So far I have this declaration of the scene assets:

struct Assets {
        static let basePath = "art.scnassets/"

        static func animation(named name: String) -> CAAnimation {
            return CAAnimation.animation(withSceneName: basePath + name)
        }

        static func scene(named name: String) -> SCNScene {
            guard let scene = SCNScene(named: name) else {
                fatalError("Failed to load scene \(name).")
            }
            return scene
        }
    }

Which uses this extension to store the animation:

extension CAAnimation {
    class func animation(withSceneName name: String) -> CAAnimation {
        guard let scene = SCNScene(named: name) else {
            fatalError("Failed to find scene with name \(name).")
        }

        var animation: CAAnimation?
        scene.rootNode.enumerateChildNodes { (child, stop) in
            guard let firstKey = child.animationKeys.first else { return }
            animation = child.animation(forKey: firstKey)
            stop.initialize(to: true)
        }

        guard let foundAnimation = animation else {
            fatalError("Failed to find animation named \(name).")
        }
        return foundAnimation
    }
}

Then I Set up the SCNScene and initialize the animation:

let scene = Assets.scene(named: "Astro_Train_Loop_V1.dae")

let trainAnimationName: String?

required init?(coder: NSCoder) {
      trainAnimationName = scene.rootNode.animationKeys.first
      super.init(coder: coder)
      }

Finally in viewDidLoad() I call a function which does a bunch of math from user input, updates the speed, and applies it to the animation:

 func updateSpeed () {

    SCNTransaction.begin()
    scene.rootNode.setAnimationSpeed(CGFloat(effectiveSpeed), forKey: trainAnimationName!)
    SCNTransaction.commit()

}

Right now this last bit is where I am getting fatal error: unexpectedly found nil while unwrapping an Optional value which I take to mean that trainAnimationName! is empty or doesn't have what the function needs....

setAnimationSpeed requires the name of the animation (a String) but that is not what is getting returned from the animation() extension, is it?

I know that the .dae file has animation because it plays in a loop when I build the project. Please help clue in a total Noob on the missing link(s)!

Cheers.

Update: Based on that reference (which is relevant), I've managed to distill my issue down to this paraphrased version of it:

let train: SCNNode = scene.rootNode.childNode(withName: "Astro_Train_Loop_V1.dae", recursively: true)!
let trainAnimation: CAAnimation = train.animation(forKey: "Astro_Train_Loop_V1.dae")!
let trainAnimationGroup: CAAnimationGroup = (trainAnimation as? CAAnimationGroup)!

for key in trainAnimationGroup.animations [] {
    let animation: CAAnimation = train.animation(forKey: key)!
    animation.speed = 0

}

This, right now, is giving me an error because the array trainAnimationGroup.animations is empty. So once we have an array of the animations (all the nodes within the animated scene file) we can cycle through it and change the speed of each one. Great! But how does the animations array get filled with animations? We've established that we have a CAAnimation that contains animation, and we've established the animationGroup, which is... a group of animations. How do I fill this array with these animations? Thank you again!

0

There are 0 answers