0
votes

I'm building an app with ARkit and I'd like the user to have the ability to start and stop animations in the scene with the use of a button in the viewcontroller. However, I am having trouble finding an example of this code. Any pointers would be appreciated. For reference, my code is as follows for animating the dae file. I had a version working where I could stop the animation, but could not get it to restart. Thanks in advance.

func loadModels(atom: String) {

    // Create a new scene
        let scene = SCNScene(named: "art.scnassets/" + atom + ".scn")!

    // Set the scene to the view
    sceneViewAr?.scene = scene

    let mainnode = scene.rootNode.childNode(withName: "mainnode", recursively: true)
    mainnode?.runAction(SCNAction.rotateBy(x: 10, y: 0, z: 0, duration: 0))

    let orbit = scene.rootNode.childNode(withName: "orbit", recursively: true)
    orbit?.runAction(SCNAction.rotateBy(x: 0, y: 2 * 50, z: 0, duration: 100))

    if let orbittwo = scene.rootNode.childNode(withName: "orbit2", recursively: true) {
        orbittwo.runAction(SCNAction.rotateBy(x: 0, y: -2 * 50, z: 0, duration: 100))
    }

    if let orbitthree = scene.rootNode.childNode(withName: "orbit3", recursively: true) {
        orbitthree.runAction(SCNAction.rotateBy(x: 0, y: 2 * 50, z: 0, duration: 100))
    }

}
1

1 Answers

0
votes

I dont think there is a way to pause and stop in the way that you want per se.

Having said this you can make use of the following SCNAction functions:

 func action(forKey key: String) -> SCNAction?
 func removeAction(forKey key: String)

Essentially you are going to have to stop and then recreate the actions again.

As such you could do something like so:

Create a variable under your class declaration for your SCNActions so you dont have to rewrite them every time e.g:

let rotateXAction = SCNAction.rotateBy(x: 10, y: 0, z: 0, duration: 10)

Then Create 2 functions one to add and the other to remove the actions e.g:

/// Adds An SCNAction To A Specified Node With A Key
///
/// - Parameters:
///   - action: SCNAction
///   - node: SCNNode
///   - key: String
func addAction(_ action: SCNAction, toNode node: SCNNode, forKey key: String){

    node.runAction(action, forKey: key)
}


/// Removes An SCNAction For A Specified Node With A Key
///
/// - Parameters:
///   - action: SCNAction
///   - node: SCNNode,
///   - key: String
func removeActionFromNode(_ node: SCNNode, forKey key: String){

    node.removeAction(forKey: key)
}

Which you could then test like so:

/// Tests Whether The `SCNActions` Can Be Stated & Stopped
func testActions(){

    //1. Create An Array Of Colours
    let colours: [UIColor] = [.red, .green, .blue, .orange, .purple, .black]

    //2. Create An Array Of Face Materials
    var faceArray = [SCNMaterial]()

    //3. Create An SCNNode With An SCNBox Geometry
    let firstNode = SCNNode(geometry: SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0))

    for faceIndex in 0..<colours.count{
        let material = SCNMaterial()
        material.diffuse.contents = colours[faceIndex]
        faceArray.append(material)
    }
    firstNode.geometry?.materials = faceArray

    //4. Add It To The Scene
    self.augmentedRealityView.scene.rootNode.addChildNode(firstNode)
    firstNode.position = SCNVector3(0 , 0, -1)

    //5. Run The Action
    addAction(rotateXAction, toNode: firstNode, forKey: "rotateX")


    //6. Stop It After 4 Seconds
    DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
        self.removeActionFromNode(firstNode, forKey: "rotateX")

    }

    //7. Start It Again After 8
    DispatchQueue.main.asyncAfter(deadline: .now() + 8) {
        self.addAction(self.rotateXAction, toNode: firstNode, forKey: "rotateX")

    }
}

In your context you can easily tweak these functions to apply for a specific IBAction etc.

This is just a starter and in no way a refactored or refined example, however it should point you in the right direction...