Animazione di oggetti SCN con CAKeyframeAnimation in Swift SceneKit

Aug 25 2020

Sto scrivendo un'applicazione che mostra le reazioni chimiche e le molecole in 3D. Ho letto tutti i valori e le posizioni di ogni atomo da un file di testo e sto creando ogni forma di atomo con SCNSpheres. Ho tutti gli altri valori di cui ho bisogno per leggere correttamente, ma non riesco a capire come aggiungere animazioni di fotogrammi chiave a ciascun oggetto nodo nella mia scena.

Ho impostato le molecole in questo modo in 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)
    }

So che le CAKeyframeAnimations dovrebbero essere impostate in questo modo

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")

Semplicemente non so dove dovrei dichiarare queste animazioni e come i livelli influiscono su tutto questo. A quale livello devo aggiungere le animazioni? E come posso attivarli per giocare? Ho cercato in tutto Internet per aiuto con questo, ma non riesco a trovare nulla che mostri solo una semplice implementazione.

Posso fornire più codice se necessario, sono abbastanza nuovo in StackOverflow e voglio assicurarmi di farlo bene.

Risposte

1 Voltan Aug 25 2020 at 01:35

Puoi farlo in modi diversi, ma mi piace questo metodo: 58001288 (la mia risposta qui) in quanto puoi pre-costruire alcune animazioni usando scenekit e quindi eseguirle come una sequenza.

Voltan Sep 02 2020 at 21:17

Per il commento .. serviva più spazio.

Una sequenza è una cosa fissa. Puoi avviarlo, ripeterlo e interromperlo. Tuttavia, è difficile interagire con esso durante le fasi.

Se hai davvero bisogno di farlo, allora un modo è suddividere la sequenza nelle sue parti e chiamare tu stesso la successiva dopo un gestore di completamento di quella corrente. Tengo un array e un contatore in modo da sapere dove mi trovo. Quindi in pratica è solo una coda di azioni che gestisco: se sono in un determinato passaggio e il pulsante viene premuto, posso annullare tutte le azioni correnti, impostare l'effetto desiderato e riavviarlo.

Modificare:

Il gestore di completamento chiama se stesso alla fine della funzione e fa avanzare il proprio conteggio di array in modo che possa essere chiamato il successivo nell'elenco. Questo è ovviamente un po 'pericoloso, quindi lo userei con parsimonia, ma è così che l'ho fatto. Ho avviato il mio con un timer, quindi non dimenticare di ripulirlo. Avevo un interruttore globale GAME_ACTIVE e all'interno del codice l'ho controllato prima di chiamarmi di nuovo.

Modifica2: Questa è in realtà una mossaTo, ma è ancora solo un set personalizzato di azioni SCNA che si richiama una volta completato in base alla durata in modo che passi immediatamente a quella successiva senza ritardi.

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