iPhoneトンネル電車

レールの上から見る視点を、タッチで電車からの視点に変えるiPhoneアプリのサンプルコードを描いてみます。

import UIKit

import SceneKit

class ViewController: UIViewController {

    weak var sceneView : SCNView?

    

    override func viewDidLoad() {

        super.viewDidLoad()

        setupScene()

        createRailroad()

        createTunnel()

        createTrain()

        createCamera()

        createLight()

    }

    func setupScene() {

        let sv = SCNView(frame: view.bounds)

        sv.backgroundColor = UIColor(hue: 0.25, saturation: 0.2, brightness: 1, alpha: 1)

        sv.scene = SCNScene()

        view.addSubview(sv)

        sceneView = sv

    }

    

    func createRailroad() {

        let ground = SCNBox(width: 12, height: 12, length: 2, chamferRadius: 0)

        ground.firstMaterial?.diffuse.contents = UIColor.brownColor()

        let groundNode = SCNNode(geometry: ground)

        groundNode.position = SCNVector3(x: 0, y: 0, z: –1.1)

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

        

        let path = UIBezierPath(roundedRect: CGRectMake(-5, –5, 10, 10), cornerRadius: 2)

        [path .appendPath(UIBezierPath(roundedRect: CGRectMake(-4.6, –4.6, 9.2, 9.2), cornerRadius: 2))]

        path.flatness = 0.01

        let rail = SCNShape(path: path, extrusionDepth: 0.2)

        rail.firstMaterial?.diffuse.contents = UIColor.darkGrayColor()

        let railNode = SCNNode(geometry: rail)

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

    }

    func createTunnel() {

        let t = SCNTube(innerRadius: 0.6, outerRadius: 0.7, height: 3)

        t.firstMaterial?.diffuse.contents = UIColor.greenColor()

        let tNode = SCNNode(geometry: t)

        tNode.position = SCNVector3(x: 4.8, y: 0, z: 0)

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

    }

    

    func createTrain() {

        let train = SCNBox(width: 1, height: 0.5, length: 0.5, chamferRadius: 0.1)

        train.firstMaterial?.diffuse.contents = UIColor.redColor()

        let trainNode = SCNNode(geometry: train)

        trainNode.name = “train”

        trainNode.position = SCNVector3(x: –3, y: –4.8, z: 0.3)

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

        

        trainNode.runAction(SCNAction.repeatActionForever(SCNAction.sequence([

            SCNAction.moveTo(SCNVector3(x:3, y:-4.8, z:0.3), duration: 1.0),

            SCNAction.group([

                SCNAction.moveTo(SCNVector3(x:4.8, y:-3, z:0.3), duration: 0.5),

                SCNAction.rotateToX(0, y: 0, z: CGFloat(M_PI) * 0.5, duration: 0.5 ,shortestUnitArc:true)

            ]),

            SCNAction.moveTo(SCNVector3(x:4.8, y:3, z:0.3), duration: 1.0),

            SCNAction.group([

                SCNAction.moveTo(SCNVector3(x:3, y:4.8, z:0.3), duration: 0.5),

                SCNAction.rotateToX(0, y: 0, z: CGFloat(M_PI), duration: 0.5)

                ]),

            SCNAction.moveTo(SCNVector3(x:-3, y:4.8, z:0.3), duration: 1.0),

            SCNAction.group([

                SCNAction.moveTo(SCNVector3(x:-4.8, y:3, z:0.3), duration: 0.5),

                SCNAction.rotateToX(0, y: 0, z: CGFloat(M_PI) * 1.5, duration: 0.5)

                ]),

            SCNAction.moveTo(SCNVector3(x:-4.8, y:-3, z:0.3), duration: 1.0),

            SCNAction.group([

                SCNAction.moveTo(SCNVector3(x:-3, y:-4.8, z:0.3), duration: 0.5),

                SCNAction.rotateToX(0, y: 0, z: CGFloat(M_PI) * 2.0, duration: 0.5)

                ])

        ])))

    }

    

    func createCamera() {

        let camera = SCNNode()

        camera.name = “camera”

        camera.camera = SCNCamera()

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

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

    }

    

    func createLight() {

        let light = SCNLight()

        light.type = SCNLightTypeDirectional

        let lightNode = SCNNode()

        lightNode.light = light

        lightNode.position = SCNVector3(x: 0, y: 0, z: 20)

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

    }

    

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

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

            camera.pivot = SCNMatrix4MakeRotation(Float(M_PI) * 0.5, 0, 0, 1);

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

            camera.rotation = SCNVector4(x: 0, y: 1, z: 0, w: –Float(M_PI) * 0.55)

            camera.camera?.automaticallyAdjustsZRange = true

            

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

            train?.addChildNode(camera)

        }

    }

}