同时在多个 SceneKit 节点上执行 CAAnimation

CAAnimation on multiple SceneKit nodes simultaneously

我正在创建一个应用程序,其中我在 AR 应用程序中使用 SceneKit 内容。我有多个节点被放置在场景中的不同位置。它们不一定在一个父节点内,也可能不一定在一个父节点内。用户必须根据应用程序设置的挑战选择正确的节点。如果用户选择了正确的节点,则正确的节点将执行一种动画,而错误的节点(可能是多个)将执行另一组动画。我正在直接使用 CAAnimation 完成动画,这一切都很好。基本上为了完成这个,我正在创建一个包含所有节点的数组并将它们用于动画。

DispatchQueue.global(qos: .userInteractive).async { [weak self] in
    for node in (self?.nodesAddedInScene.keys)! {
        for index in 1...node.childNodes.count - 1 {
            if node.childNodes[index].childNodes.first?.name == "target" {
                self?.riseUpSpinAndFadeAnimation(on: node.childNodes[index])
            } else {
                self?.fadeAnimation(on: node.childNodes[index])
            }
        }
    }
}

当用户选择 "target" 节点时,该节点执行一组动画,其他节点执行另一组动画。

RiseUpSpinAndFadeAnimation:

    private func riseUpSpinAndFadeAnimation(on shape: SCNNode) {
        let riseUpAnimation = CABasicAnimation(keyPath: "position")
        riseUpAnimation.fromValue = SCNVector3(shape.position.x, shape.position.y, shape.position.z)
        riseUpAnimation.toValue = SCNVector3(shape.position.x, shape.position.y + 0.5, shape.position.z)

        let spinAnimation = CABasicAnimation(keyPath: "eulerAngles.y")
        spinAnimation.toValue = shape.eulerAngles.y + 180.0
        spinAnimation.autoreverses = true

        let fadeAnimation = CABasicAnimation(keyPath: "opacity")
        fadeAnimation.toValue = 0.0

        let riseUpSpinAndFadeAnimation = CAAnimationGroup()
        riseUpSpinAndFadeAnimation.animations = [riseUpAnimation, fadeAnimation, spinAnimation]
        riseUpSpinAndFadeAnimation.duration = 1.0
        riseUpSpinAndFadeAnimation.fillMode = kCAFillModeForwards
        riseUpSpinAndFadeAnimation.isRemovedOnCompletion = false

        shape.addAnimation(riseUpSpinAndFadeAnimation, forKey: "riseUpSpinAndFade")
    }

FadeAnimation:

private func fadeAnimation(on shape: SCNNode) {
    let fadeAnimation = CABasicAnimation(keyPath: "opacity")
    fadeAnimation.toValue = 0.0
    fadeAnimation.duration = 0.5
    fadeAnimation.fillMode = kCAFillModeForwards
    fadeAnimation.isRemovedOnCompletion = false
    shape.addAnimation(fadeAnimation, forKey: "fade")
}

我希望动画能够成功,它们确实如此。但是,问题是因为节点在数组中,所以并不是所有节点都同时执行动画。动画开始时存在微小差异,这实际上导致效果不佳 UI。

我正在寻找的是一种逻辑,其中我可以在所有节点上附加动画并稍后 一起调用这些动画 假设用户点击正确的节点。数组对我来说似乎不是一个明智的选择。但是,恐怕如果我将所有这些节点都设为一个空节点的子节点,并在该空节点上设置 运行 动画,可能一开始就很难管理这些子节点的放置,因为他们认为保持随机距离,不一定靠得很近。鉴于这最终会推动 AR 体验,所以它更像是一个无赖。

请求一些输入是否有方法将动画附加到多个(从这些对象中选择)对象(即使按顺序)但 运行 它们在一起。我用了shape.addAnimation(fadeAnimation, forKey: "fade") "forKey",在这种用例中可以使用吗?任何指针表示赞赏。

锰,

我只是在这里猜测一下,或者可以为您激发一个想法:-)

我主要关注你问题的这一部分: "What I am looking for is a logic wherein I can attach animations on all nodes and call these animations together later when let's say the user taps correct node."

我想知道 SCNTransaction 是否: [https://developer.apple.com/documentation/scenekit/scntransaction][1] 可能会成功

或者 dispatch.sync 或异步(完全是猜测......但可能有所帮助) [https://developer.apple.com/documentation/dispatch][1]

或者我离题太远了:-) 只是想帮忙....

我们都通过分享我们所知道的来学习

RAD

通过使用暂停的 CAKeyframe 动画 (.speed = 0) 并在 SCNSceneRendererDelegate "renderer(updateAtTime:)" 函数中设置动画的时间偏移 (.timeOffset),我有多达五十个 SCNNodes 完美和谐地制作动画。

如何为大量节点添加每 1/60 秒的时间偏移的暂停动画真是太神奇了。向 SceneKit 开发人员致敬,他们在添加和删除 CAAnimations 方面的开销如此之小。

我尝试了许多不同的 CAAnimation/SCNAction 技术,然后才决定使用它。在其他方法中,动画会随着时间的推移不同步。