iPhone開閉ギア

ギアをくるくる回してチューブの中のドアを開けるiPhoneアプリのサンプルコード

import UIKit

import SceneKit

class ViewController: UIViewController {

    weak var sceneView : SCNView?

    var count = 0

    

    override func viewDidLoad() {

        super.viewDidLoad()

        setupScene()

        createTube()

        createGear()

    }

    func setupScene() {

        let sv =  SCNView(frame: view.bounds)

        sv.backgroundColor = UIColor.lightGrayColor()

        sv.scene = SCNScene()

        sv.autoenablesDefaultLighting = true

        sv.allowsCameraControl = true

        view.addSubview(sv)

        

        sceneView = sv

    }

    func createTube() {

        let tube = SCNTube(innerRadius: 2, outerRadius: 2.1, height: 20)

        tube.firstMaterial?.diffuse.contents = UIColor(hue: 0.5, saturation: 0.3, brightness: 1, alpha: 1).colorWithAlphaComponent(0.3)

        let tubeNode = SCNNode(geometry: tube)

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

        tubeNode.physicsBody = SCNPhysicsBody.staticBody()

        tubeNode.physicsBody?.categoryBitMask = 0x1 << 1

        tubeNode.physicsBody?.physicsShape = SCNPhysicsShape(node: tubeNode, options: [SCNPhysicsShapeTypeKey : SCNPhysicsShapeTypeConcavePolyhedron])

        

        let door = SCNCylinder(radius: 2, height: 0.2)

        door.firstMaterial?.diffuse.contents = UIColor(hue: 0.5, saturation: 0.3, brightness: 1, alpha: 1)

        let doorNode = SCNNode(geometry: door)

        doorNode.name = “door”

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

        doorNode.physicsBody = SCNPhysicsBody.staticBody()

        doorNode.physicsBody?.collisionBitMask = 0x1

    }

    

    func createGear() {

        let gear = SCNNode()

        gear.name = “gear”

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

        gear.transform = SCNMatrix4Rotate(gear.transform, Float(M_PI)/2.0, 1, 0, 0)

        gear.transform = SCNMatrix4Translate(gear.transform, 0, 0, 2.5)

        

        let base = SCNTube(innerRadius: 0.8, outerRadius: 1.4, height: 0.2)

        base.firstMaterial?.diffuse.contents = UIColor.blueColor()

        let baseNode = SCNNode(geometry: base)

        gear.addChildNode(baseNode)

        

        [Int](012).each {

            let t = SCNBox(width: 0.4, height: 0.2, length: 0.4, chamferRadius: 0.05)

            t.firstMaterial?.diffuse.contents = base.firstMaterial?.diffuse.contents

            let tn = SCNNode(geometry: t)

            

            let w = M_PI / 6.0 * Double($0)

            let x = 1.5 * sin(w)

            let z = 1.5 * cos(w)

            tn.position = SCNVector3(x: Float(x), y: 0, z: Float(z))

            tn.rotation = SCNVector4(x: 0, y: 1, z: 0, w: Float(w))

            gear.addChildNode(tn)

        }

    }

    

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

        let c = count % 3

        switch c {

        case 1:

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

            door?.runAction(SCNAction.moveTo(SCNVector3(x: 4, y: 0, z: 0), duration: 2.0))

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

            gear?.runAction(SCNAction.rotateByAngle(CGFloat(M_PI) * 2.0, aroundAxis: SCNVector3(x: 0, y: 0, z: 1), duration: 2.0))

        case 2:

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

            door?.runAction(SCNAction.moveTo(SCNVector3Zero, duration: 2.0))

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

            gear?.runAction(SCNAction.rotateByAngle(-CGFloat(M_PI) * 2.0, aroundAxis: SCNVector3(x: 0, y: 0, z: 1), duration: 2.0))

        default:

            let ball = SCNSphere(radius: 1)

            ball.firstMaterial?.diffuse.contents = UIColor.orangeColor()

            let ballNode = SCNNode(geometry: ball)

            ballNode.position = SCNVector3(x: 0, y: 10, z: 0)

            ballNode.physicsBody = SCNPhysicsBody.dynamicBody()

            self.sceneView?.scene?.rootNode.addChildNode(ballNode)

            delay(10.0) { ballNode.removeFromParentNode() }

        }

        ++count

    }

    

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

}