Ios 动画的替代品(forKey:)(现在已弃用)?

Ios 动画的替代品(forKey:)(现在已弃用)?,ios,swift,scenekit,ios11,Ios,Swift,Scenekit,Ios11,我正在使用iOS 11(用于ARKit),虽然许多人都指向苹果公司的一个带有福克斯的SceneKit示例应用程序,但我对该示例项目()中用于添加动画的扩展有问题: extension CAAnimation { class func animationWithSceneNamed(_ name: String) -> CAAnimation? { var animation: CAAnimation? if let scene = SCNScene(

我正在使用iOS 11(用于
ARKit
),虽然许多人都指向苹果公司的一个带有福克斯的
SceneKit
示例应用程序,但我对该示例项目()中用于添加动画的扩展有问题:

extension CAAnimation {
    class func animationWithSceneNamed(_ name: String) -> CAAnimation? {
        var animation: CAAnimation?
        if let scene = SCNScene(named: name) {
            scene.rootNode.enumerateChildNodes({ (child, stop) in
                if child.animationKeys.count > 0 {
                    animation = child.animation(forKey: child.animationKeys.first!)
                    stop.initialize(to: true)
                }
            })
        }
        return animation
    }
}
看起来这个扩展非常方便,但我不知道如何迁移它,因为它已经被弃用了?它现在是否默认内置在
SceneKit

文档中并没有显示太多关于它被弃用的原因或者从这里到哪里的信息


谢谢

TL;DR:关于如何使用新API的示例可以在苹果的(搜索
SCNAnimationPlayer


尽管
animation(forKey:)
及其与
CAAnimation
一起工作的姐妹方法在
iOS11
中已被弃用,但您可以继续使用它们–一切都会正常工作

但是如果您想使用新的API,并且不关心向后兼容性(在
ARKit
的情况下,您不需要向后兼容性,因为它只在
iOS11
之后才可用),请继续阅读

新推出的
SCNAnimationPlayer
与以前的版本相比提供了更方便的API。现在更容易实时处理动画。 从
WWDC2017
开始学习将是一个很好的起点

作为一个简短的总结:
SCNAnimationPlayer
允许您动态更改动画的速度。与添加和删除
CAAnimation
s相比,它使用
play()
stop()
等方法为动画播放提供了更直观的界面。 您还可以将两个动画混合在一起,例如,可以使用这两个动画在它们之间进行平滑过渡

您可以在中找到如何使用所有这些的示例


以下是您发布的扩展,它适用于使用
SCNAnimationPlayer
(您可以在Fox 2示例项目的
Character
类中找到):

您可以按如下方式使用它:

  • 加载动画并将其添加到相应的节点

    let jumpAnimation = SCNAnimationPlayer.loadAnimation(fromSceneNamed: "jump.scn")
    jumpAnimation.stop() // stop it for now so that we can use it later when it's appropriate 
    model.addAnimationPlayer(jumpAnimation, forKey: "jump")
    
  • 用它

    model.animationPlayer(forKey: "jump")?.play()
    

  • Lësha Turkowski毫不费力地回答了问题

    extension SCNAnimationPlayer {
    
        class func loadAnimationPlayer(from sceneName: String) -> SCNAnimationPlayer? {
            var animationPlayer: SCNAnimationPlayer?
    
            if let scene = SCNScene(named: sceneName) {
                scene.rootNode.enumerateChildNodes { (child, stop) in
                    if !child.animationKeys.isEmpty {
                        animationPlayer = child.animationPlayer(forKey: child.animationKeys[0])
                        stop.pointee = true
                    }
                }
            }
    
            return animationPlayer
        }
    }
    

    下面是一个SwiftUI和SceneKit的示例

    import SwiftUI
    import SceneKit
    
    struct ScenekitView : UIViewRepresentable {
    @Binding var isPlayingAnimation: Bool
    
    let scene = SCNScene(named: "art.scnassets/TestScene.scn")!
    
    func makeUIView(context: Context) -> SCNView {
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)
    
        let scnView = SCNView()
        return scnView
    }
    
    func updateUIView(_ scnView: SCNView, context: Context) {
        scnView.scene = scene
    
        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true
    
        controlAnimation(isAnimating: isPlayingAnimation, nodeName: "TestNode", animationName: "TestAnimationName")
    }
    
    func controlAnimation(isAnimating: Bool, nodeName: String, animationName: String) {
        guard let node = scene.rootNode.childNode(withName: nodeName, recursively: true) else {  return }
        guard let animationPlayer: SCNAnimationPlayer = node.animationPlayer(forKey: animationName) else {  return }
        if isAnimating {
            print("Play Animation")
            animationPlayer.play()
        } else {
            print("Stop Animation")
            animationPlayer.stop()
        }
    }
    }
    
    struct DogAnimation_Previews: PreviewProvider {
        static var previews: some View {
            ScenekitView(isPlayingAnimation: .constant(true))
        }
    }
    

    非常感谢。我按照你的链接做了这件事,用SCNAnimationPlayer替换了我的动画代码,但我无法让它在我的生命中播放。网格跳到动画的第一帧,因此我知道它正在加载它。我可以记录动画并查看正确的帧数,但play()什么也不做。使用CAAnimation的相同动画效果很好。有什么我可以测试的吗?
    import SwiftUI
    import SceneKit
    
    struct ScenekitView : UIViewRepresentable {
    @Binding var isPlayingAnimation: Bool
    
    let scene = SCNScene(named: "art.scnassets/TestScene.scn")!
    
    func makeUIView(context: Context) -> SCNView {
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)
    
        let scnView = SCNView()
        return scnView
    }
    
    func updateUIView(_ scnView: SCNView, context: Context) {
        scnView.scene = scene
    
        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true
    
        controlAnimation(isAnimating: isPlayingAnimation, nodeName: "TestNode", animationName: "TestAnimationName")
    }
    
    func controlAnimation(isAnimating: Bool, nodeName: String, animationName: String) {
        guard let node = scene.rootNode.childNode(withName: nodeName, recursively: true) else {  return }
        guard let animationPlayer: SCNAnimationPlayer = node.animationPlayer(forKey: animationName) else {  return }
        if isAnimating {
            print("Play Animation")
            animationPlayer.play()
        } else {
            print("Stop Animation")
            animationPlayer.stop()
        }
    }
    }
    
    struct DogAnimation_Previews: PreviewProvider {
        static var previews: some View {
            ScenekitView(isPlayingAnimation: .constant(true))
        }
    }