iPhone 逃げる三角

タッチするとニュッと三角が逃げるiPhoneアプリのサンプルコード
(※アイデアはAndrewさんからいただきました!ありがとうございます。)

import UIKit

import SceneKit

class ViewController: UIViewController {

    

    weak var sceneView : SCNView?

    

    override func viewDidLoad() {

        super.viewDidLoad()

        setupScene()

        createTriangleShapes()

        createCamera()

    }

    

    func setupScene() {

        let sv = SCNView(frame: view.bounds)

        sv.scene = SCNScene()

        sv.backgroundColor = UIColor(white: 0.05, alpha: 1)

        view.addSubview(sv)

        

        sceneView = sv

    }

    

    func createTriangleShapes() {

        

        let r = 5

        

        // patten of animation ?

        let points = [

            [SCNVector3(x: 5, y: 0, z: 0), SCNVector3(x: –5, y: 5, z: 0), SCNVector3(x: –5, y: –5, z: 0)],

            [SCNVector3(x: 5, y: 0, z: 0), SCNVector3(x: –5, y: 5, z: 0), SCNVector3(x: –15, y: –2, z: 0)],

            [SCNVector3(x: 5, y: 0, z: 0), SCNVector3(x: –15, y: 8, z: 0), SCNVector3(x: –15, y: –2, z: 0)],

            [SCNVector3(x: –5, y: 0, z: 0), SCNVector3(x: –15, y: 8, z: 0), SCNVector3(x: –15, y: –2, z: 0)]

        ]

        

        let geometories = points.map { (var ps) -> SCNGeometry in

            var verts : [SCNVector3] = ps

            let indices : [Int32] = [0, 1, 2];

            let vertexSource = SCNGeometrySource(vertices:UnsafePointer<SCNVector3>(verts), count:verts.count);

            let indexData = NSData(bytes:indices, length:sizeof(Int32) * indices.count);

            let element = SCNGeometryElement(data:indexData, primitiveType:.Triangles, primitiveCount:indices.count, bytesPerIndex:sizeof(Int32));

            

            let triangle = SCNGeometry(sources:[vertexSource], elements:[element]);

            triangle.firstMaterial?.diffuse.contents = UIColor(hue: 0.1, saturation: 0.4, brightness: 1, alpha: 1)

            

            return triangle

        }

        

        let triangle = SCNNode(geometry: geometories[0])

        triangle.name = “triangle”

        triangle.morpher = SCNMorpher()

        triangle.morpher?.targets = geometories

        sceneView?.scene?.rootNode.addChildNode(triangle)

    }

    

    func createCamera() {

        let camera = SCNNode()

        camera.camera = SCNCamera()

        camera.position = SCNVector3(x: 0, y: 0, z: 15)

        sceneView?.scene?.rootNode.addChildNode(camera)

    }

    

    var lock = false

    var frameNumber = 0

    

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

        if frameNumber == 0 {

            [Int](02).each { i in

                self.delay(Double(i) * 0.2, doit: { () -> Void in

                    self.dodge()

                })

            }

        } else {

            dodge()

        }

    }

    

    func dodge() {

        

        let triangle = sceneView?.scene?.rootNode.childNodeWithName(“triangle”, recursively: false)

        if let targets = triangle?.morpher?.targets as? [SCNGeometry] {

            triangle?.geometry = targets[frameNumber]

            frameNumber = (frameNumber + 1) % targets.count

        

            let numMorpher = triangle!.morpher!.targets!.count

            let a = CABasicAnimation(keyPath: “morpher.weights[\(frameNumber)]”)

            a.fromValue = 0

            a.toValue = 1

            a.duration = 0.2

            a.removedOnCompletion = false;

            a.fillMode = kCAFillModeForwards;

            a.delegate = self

            [triangle?.addAnimation(a, forKey: “”)]

        }

    }

    

    final func delay(delay:Double, doit:()->Void) {

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), doit)

    }

}

extension Array {

    func each(doit:T -> Void) { for i in self {doit(i)} }

}