iPhoneチューブパズル

チューブを回転させてボールを通すiPhoneアプリのサンプルコードを描いてみます。

import UIKit

import SceneKit

class ViewController: UIViewController {

    weak var scene : SCNScene?

    weak var sceneView : SCNView?

    

    override func viewDidLoad() {

        super.viewDidLoad()

        self.view.backgroundColor = UIColor(hue: 0.8, saturation: 0.6, brightness: 1, alpha: 1)

        

        self.setupScene()

        

        let tubeA = self.createTube()

        let tubeB = self.createTube()

        tubeB.name = “tubeB”

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

        tubeB.transform = SCNMatrix4Translate(tubeB.transform, –12, –16, 0)

        self.createCamera()

    }

    func setupScene() {

        let w = CGRectGetMaxX(self.view.bounds)

        let sv = SCNView(frame: CGRect(x: 0, y: 0, width: w, height: w))

        sv.backgroundColor = UIColor(hue: 0.1, saturation: 0.5, brightness: 1, alpha: 1)

        sv.scene = SCNScene()

        self.view.addSubview(sv)

        

        self.scene = sv.scene

        self.sceneView = sv

    }

    

    func createTube() -> SCNNode {

        let tube = SCNNode()

        self.scene?.rootNode.addChildNode(tube)

        

        let t = SCNTube(innerRadius: 5, outerRadius: 5.1, height: 20)

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

        let tNode = SCNNode(geometry: t)

        tube.addChildNode(tNode)

        tNode.transform = SCNMatrix4MakeTranslation(5, 10, 0)

        

        var shapes : [AnyObject] = [AnyObject]()

        var transforms : [AnyObject] = [AnyObject]()

        shapes.append(SCNPhysicsShape(geometry: t, options: [SCNPhysicsShapeTypeKey : SCNPhysicsShapeTypeConcavePolyhedron]))

        transforms.append(NSValue(SCNMatrix4: tNode.transform))

        

        for i in 010 {

            let ring = SCNTube(innerRadius: 5, outerRadius: 5.1, height: 2)

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

            let ringNode = SCNNode(geometry: ring)

            

            let dAngle = Float(M_PI/20.0) * Float(i) + Float(-M_PI/2.0)

            var transform = SCNMatrix4Translate(SCNMatrix4Identity, 5, 0, 0)

            transform = SCNMatrix4Rotate(transform, dAngle, 0.0, 0.0, 1.0)

            ringNode.transform = transform

            

            tube.addChildNode(ringNode)

            

            shapes.append(SCNPhysicsShape(geometry: ring, options: [SCNPhysicsShapeTypeKey : SCNPhysicsShapeTypeConcavePolyhedron]))

            transforms.append(NSValue(SCNMatrix4: transform))

        }

        

        tube.physicsBody = SCNPhysicsBody.staticBody()

        tube.physicsBody?.physicsShape = SCNPhysicsShape(shapes: shapes, transforms: transforms)

        

        return tube

    }

    

    func createCamera() {

        let camera = SCNNode()

        camera.camera = SCNCamera()

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

        self.scene?.rootNode.addChildNode(camera)

    }

    

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {

        

        let p = touches.anyObject()!.locationInView(self.sceneView)

        let hits = self.sceneView!.hitTest(p, options: [SCNHitTestIgnoreChildNodesKey : false]) as [SCNHitTestResult]

        if let target : SCNNode = hits.first?.node.parentNode {

            if target.name == “tubeB” {

                target.runAction(SCNAction.rotateByAngle(CGFloat(M_PI/2.0), aroundAxis: SCNVector3(x: 0, y: 0, z: 1), duration: 1.0))

            }

        } else {

            let ball = SCNSphere(radius: 3)

            ball.firstMaterial?.diffuse.contents = UIColor(hue: 0.6, saturation: 0.6, brightness: 1, alpha: 1)

            let ballNode = SCNNode(geometry: ball)

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

            self.scene?.rootNode.addChildNode(ballNode)

            ballNode.physicsBody = SCNPhysicsBody.dynamicBody()

        }

    }

}