【问题标题】:CAAnimation on multiple SceneKit nodes simultaneously同时在多个 SceneKit 节点上的 CAAnimation
【发布时间】:2018-05-19 03:46:53
【问题描述】:

我正在创建一个应用程序,其中我在 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])
            }
        }
    }
}

当用户选择“目标”节点时,该节点会播放一组动画,而其他节点会播放另一组动画。

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”,可以在这种用例中使用吗?任何指针表示赞赏。

【问题讨论】:

    标签: ios swift scenekit arkit caanimation


    【解决方案1】:

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

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

    在解决这个问题之前,我尝试了许多不同的 CAAnimation/SCNAction 技术。在其他方法中,动画会随着时间的推移而失去同步。

    【讨论】:

    • 听起来很有趣,我目前正在旅行 - 将使用您的建议,然后让您知道此优化是否有效。谢谢肖恩!
    • 是的,CAKeyframe 动画和 CABasicAnimation 一样流畅。我现在倾向于 CABasicAnimation。但是,我会接受这个作为答案。
    【解决方案2】:

    锰,

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

    我专注于您问题的这一部分: “我正在寻找的是一种逻辑,其中我可以在所有节点上附加动画,然后当假设用户点击正确的节点时将这些动画一起调用。”

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

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

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

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

    辐射

    【讨论】:

    • 感谢伙伴,无论我使用 SCNTransaction/CAAnimation 还是 SCNAction,根本问题仍然存在。我将不得不更改节点的属性,我将使用与使用 CAAnimation 时相同的数组。最终这会导致相同的问题,即所有节点的非同步动画。实际上我之前尝试过 SCNTransaction ,因此我知道我最终会处理同样的问题。不过,我会尝试 Dispatches - 听起来那里可能有一些东西,以防万一没有其他优雅的解决方案。谢谢
    猜你喜欢
    • 2017-07-22
    • 1970-01-01
    • 2021-05-19
    • 2017-02-07
    • 2015-07-10
    • 2015-06-20
    • 1970-01-01
    • 2017-08-22
    • 2018-09-10
    相关资源
    最近更新 更多