Animazione di oggetti SCN con CAKeyframeAnimation in Swift SceneKit
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
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.
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()
}
})
}