ios 动画的替代方法(forKey:)(现已弃用)?

mdfafbf1  于 2023-01-18  发布在  iOS
关注(0)|答案(4)|浏览(106)
    • bounty将在6天后过期**。回答此问题可获得+100声望奖励。Fattie希望引起更多人关注此问题。

我正在使用iOS 11(针对ARKit),虽然许多人都指向苹果公司的一个带有Fox的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中了吗?
文档并没有真正显示太多的信息,为什么它被弃用或从这里去哪里。
谢谢

p8ekf7hl

p8ekf7hl1#

    • TL; DR**:有关如何使用新API的示例,请参见Apple的sample game(搜索SCNAnimationPlayer

尽管animation(forKey:)及其与CAAnimation一起使用的姊妹方法在iOS11中已被弃用,但您可以继续使用它们-一切都将正常。
但是,如果您想使用新的API,并且不关心向后兼容性(在ARKit的情况下,无论如何都不需要向后兼容性,因为它只在iOS11之后可用),请继续阅读。
新引入的SCNAnimationPlayer提供了一个比前代更方便的API。现在更容易实时处理动画。WWDC2017中的This video是了解它的一个很好的起点。
简单总结一下:SCNAnimationPlayer允许您动态更改动画的速度。与添加和删除CAAnimation相比,它为使用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")

1.用它!

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

fquxozlt2#

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

mspsb9vt3#

以下是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))
    }
}
e4yzc0pl

e4yzc0pl4#

2023年的例子。

我加载的典型动画如下所示:

func simpleLoadAnim(filename: String) -> SCNAnimationPlayer {
    let s = SCNScene(named: filename)!
    let n = s.rootNode.childNodes.filter({!$0.animationKeys.isEmpty}).first!
    return n.animationPlayer(forKey: n.animationKeys.first!)!
}

所以,

laugh = simpleLoadAnim(filename: "animeLaugh") // animeLaugh.dae
giggle = simpleLoadAnim(filename: "animeGiggle")

然后,第一步,必须将它们添加到角色中:

sally.addAnimationPlayer(laugh, forKey: "laugh")
sally.addAnimationPlayer(giggle, forKey: "giggle")

通常你一次只会有一个。所以设置权重,第二步

laugh.blendFactor = 1
giggle.blendFactor = 0

要播放或停止SCNAnimationPlayer,只需第三步

laugh.play()
giggle.stop()

几乎可以肯定的是,您将有自己的代码(数百行)来混合动画(这可能只需要很短的时间,0.1秒,也可能需要1秒左右)。
如果你愿意,你可以使用键访问动画,on,角色(sally)。但真正的"要点"是你可以启动,停止等SCNAnimationPlayer
您还将有大量的代码来设置SCNAnimationPlayer如何您喜欢(速度,循环,镜像等等等等)
您将需要这个非常关键的答案来获得colada文件(必须是单独的字符/动画文件)正常工作https://stackoverflow.com/a/75093081/294884
一旦你有各种SCNAnimationPlayer动画正常工作,这是相当容易使用,运行,混合等动画。
基本顺序是
1.每个动画必须是在它自己的. dae文件
1.加载每个动画文件到一个SCNAnimationPlayer
1.将所有动画"添加"到有问题的角色
1.编程混合
1.然后简单地play()stop()实际的SCNAnimationPlayer项目(不要麻烦使用字符上的键,这有点无意义)

相关问题