在 Swift SceneKit 中使用 CAKeyframeAnimation 为 SCN 对象设置动画

Animating SCN Objects with CAKeyframeAnimation in Swift SceneKit

我正在编写一个以 3D 形式显示化学反应和分子的应用程序。我从文本文件中读取每个原子的所有值和位置,并使用 SCNSpheres 创建每个原子形状。我有我需要正确读入的所有其他值,但我不知道如何向场景中的每个节点对象添加关键帧动画。

我在 ViewController.swift

中设置了这样的分子
func makeAtom(atomName: String, coords: [Double], scene: SCNScene) {
        guard let radius = atomRadii[atomName]?.atomicRadius else { return }
        
        atoms.append(Atom(name: atomName, x: coords[0], y: coords[1], z: coords[2], radius: radius, positions: []))
        
        let atomGeometry = SCNSphere(radius: CGFloat(radius))
        let atomNode = SCNNode(geometry: atomGeometry)
        atomNode.position = SCNVector3(coords[0], coords[1], coords[2])
        scene.rootNode.addChildNode(atomNode)
        
        atomNodes.append(atomNode)
    }

我知道 CAKeyframeAnimations 应该这样设置

let animation = CAKeyframeAnimation()
animation.keyPath = "position.y"
animation.values = [0, 300, 0]
animation.keyTimes = [0, 0.5, 1]
animation.duration = 2
animation.isAdditive = true

vw.layer.add(animation, forKey: "move")

我只是不知道我应该在哪里声明这些动画以及层如何影响这一切。我应该将动画添加到哪一层?我怎样才能触发他们玩?我一直在整个互联网上搜索这方面的帮助,但我找不到任何仅显示简单实现的内容。

如果需要,我可以提供更多代码,我是 Whosebug 的新手,想确保我做的是正确的。

你可以用不同的方式来做,但我喜欢这种方法:你可以pre-build一些使用 scenekit 的动画,然后 运行 它们作为一个序列。

根据评论..需要更多空间。

序列是固定的东西。您可以开始、重复和停止它。但是,在阶段中很难与之交互。

如果您确实需要这样做,那么一种方法是将您的序列分解成多个部分,并在当前序列的完成处理程序之后自行调用下一个序列。我保留了一个数组和一个计数器,这样我就知道我在哪里。所以基本上它只是我管理的一个动作队列 - 如果我在某个步骤并且按下了按钮,那么我可以取消所有当前动作,设置所需的效果,然后重新启动它。

编辑:

完成处理程序在函数末尾调用自身并增加自己的数组计数,以便可以调用列表中的下一个。这显然有点危险,所以我会谨慎使用,但我就是这样做的。我用定时器启动了我的,然后别忘了清理它。我有一个全局 GAME_ACTIVE 开关,我在代码中检查了它,然后再次调用自己。

Edit2:这实际上是一个 moveTo,但它仍然只是一组自定义的 SCNAction,它会在完成时根据持续时间调用自身,以便立即转到下一个而不会延迟。

func moveTo()
    {
        let vPanelName = moves[moveCount]
        let vLaneNode = grid.gridPanels[vPanelName]!.laneNodes[lane]
        let vAction = SCNAction.move(to: vLaneNode.presentation.position, duration: TimeInterval(data.getAttackSpeed(vGameType: gameType)))
        
        node.runAction(vAction, completionHandler:
            {
                self.moveCount += 1
                if(self.moveCount >= self.moves.count - 1)
                {
                    self.killMe(vRealKill: false)
                    return
                }
                else
                {
                    self.moveTo()
                }
        })
    }