【问题标题】:Alternative to animation(forKey:) (now deprecated)?替代动画(forKey:)(现已弃用)?
【发布时间】:2018-02-11 00:54:31
【问题描述】:

我正在使用 iOS 11(适用于 ARKit),虽然许多人使用 Fox 指向 Apple 的 SceneKit 示例应用程序,但我在该示例项目中使用的扩展程序存在问题 (file ) 添加动画:

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中了吗?

文档并没有真正显示关于它被弃用的原因或从这里去哪里的太多信息。

谢谢

【问题讨论】:

    标签: ios swift scenekit ios11


    【解决方案1】:

    TL;DR:如何使用新 API 的示例可以在 Apple 的 sample game 中找到(搜索 SCNAnimationPlayer


    即使animation(forKey:) 及其与CAAnimation 一起使用的姊妹方法在iOS11 中已被弃用,您仍可以继续使用它们——一切都会正常工作。

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

    新推出的SCNAnimationPlayer 相比其前身提供了更方便的API。现在更容易实时处理动画。 来自WWDC2017This video 将是了解它的一个很好的起点。

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

    您可以在Fox 2 game by Apple 中找到如何使用所有这些的示例。


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

    extension SCNAnimationPlayer {
        class func loadAnimation(fromSceneNamed sceneName: String) -> SCNAnimationPlayer {
            let scene = SCNScene( named: sceneName )!
            // find top level animation
            var animationPlayer: SCNAnimationPlayer! = nil
            scene.rootNode.enumerateChildNodes { (child, stop) in
                if !child.animationKeys.isEmpty {
                    animationPlayer = child.animationPlayer(forKey: child.animationKeys[0])
                    stop.pointee = true
                }
            }
            return animationPlayer
        }
    }
    

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

    1. 加载动画并添加到对应节点

      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")
      
    2. 使用它!

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

    【讨论】:

    • 非常感谢。我已经按照您的链接完成了该操作,用 SCNAnimationPlayer 替换了我的 CAAnimation 代码,但我无法让它终生发挥作用。网格跳到动画的第一帧,所以我知道它正在加载它。我可以记录动画并查看正确的帧数,但 play() 什么也不做。使用 CAAnimation 的相同动画效果很好。有什么我可以测试的吗?
    【解决方案2】:

    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
        }
    }
    

    【讨论】:

      【解决方案3】:

      这是 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))
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-17
        • 2020-03-03
        • 2013-04-28
        • 2012-12-01
        • 2012-12-03
        • 2020-03-22
        • 1970-01-01
        相关资源
        最近更新 更多